Modifier le volume d'un fichier wav en python
J'ai un 2 secondes 16 bits de canal unique de 8 khz wav fichier et j'ai besoin de changer son volume.
Il devrait être assez simple, parce que changer le volume est le même que la modification de l'amplitude du signal, et j'ai juste besoin de l'atténuer, c'est-à multiplier par un nombre entre 0 et 1. Mais ça ne fonctionne pas: le nouveau son est plus faible, mais TRÈS bruyant. Ce que je fais mal?
Voici mon code:
import wave, numpy, struct
# Open
w = wave.open("input.wav","rb")
p = w.getparams()
f = p[3] # number of frames
s = w.readframes(f)
w.close()
# Edit
s = numpy.fromstring(s, numpy.int16) * 5 / 10 # half amplitude
s = struct.pack('h'*len(s), *s)
# Save
w = wave.open("output.wav","wb")
w.setparams(p)
w.writeframes(s)
w.close()
Merci les gars!
- Pourquoi êtes-vous à l'aide de
* 5 / 10
au lieu de/ 2
? - Si je devais deviner, je dirais que le
* 5
partie est de clipping et de débordement. - Êtes-vous de lire le fichier dans le bon boutisme? les fichiers WAV sont little-endian. à l'Aide de l'autre endian permettra de réduire de moitié l'échantillon et ajouter BEAUCOUP de bruit.
- Oh mon...!! Désolé pour l'affichage que... La réponse a été trop facile. En procédant ainsi: s = numpy.fromstring(s, numpy.int16) * 5 / 10 # la moitié de l'amplitude Du signal est saturé, parce que j'ai multiplié les entiers avant de les diviser. Une solution: s = numpy.fromstring(s, numpy.int16) / 10 * 5 # la moitié de l'amplitude attention, cela ne fonctionne PAS comme les résultats de la division zéro: s = numpy.fromstring(s, numpy.int16) * (5 / 10) # la moitié de l'amplitude, je le garde ici au cas où il permet à quelqu'un d'autre.
- Jan, parce qu'ils sont censés être vars: 5 volume souhaité, puis 10 est le volume original.
- Nick, OUI!! Vous êtes de droite. Merci!!!!
- Vous devriez poster votre commentaire comme une réponse et de l'accepter quand c'est possible (+24h IIRC)
- Merci Jan, mais stackoverflow me permet d'attendre encore 7 heures avant que je puisse poster une réponse... 🙂
- Depuis que vous avez trouvé le problème, il serait juste si vous avez posté une réponse et l'OP accepté. Une solution complète serait probablement inclure multipliant avec
float(desired_volume) / float(orig_volume)
. - Dommage que je ne suis pas à l'aise en python. Je ne savais même pas si python n'utilisez pas les types float pour tout.
- Une autre chose: le
*
opérateur dansstruct.pack('h', *s)
ligne convertit l'ensemble du tableau numpy dans un tuple de type int objets. C'est potentiellement très efficace, vous devez utiliser less.tostring
au lieu de cela, ce qui permettra de créer efficacement une chaîne directement à partir du contenu du tableau. - Si il est mis à l'échelle par un flotteur, en utilisant seulement
tostring
va donner un mauvais résultat. Mais au lieu de cela, vous pourriez faires = (s * (desired/original)).astype(numpy.int16).tostring()
.
Vous devez vous connecter pour publier un commentaire.
J'ai écrit un bibliothèque pour simplifier ce type de chose
Vous pouvez le faire comme ceci:
song = song - 36
Comme vous pouvez le voir dans les commentaires de la question, il existe plusieurs solutions, certaines sont plus efficaces.
Le problème a été détecté immédiatement par Jan Dvorak ("le * 5 pièce est de clipping et de déborder") et à la simplicité de la solution a été:
Dans ce cas, cette solution est parfaite pour moi, juste assez bon.
Merci à tous les gens!