I need any python library to change pitch of my wav file without any raw audio data processing. I spent couple hours to find it, but only found some strange raw data processing code snippets and video, that shows real-time pitch shift, but without source code.
-
1Site rules state that we're not here to find a library for you or create one for that matter. If you've searched and couldn't find one - odds are there are none and you'll have to write it yourself. At least this is the norm and I'm simply informing you about this in case you don't get any answers or your question gets closed. – Torxed May 14 '17 at 12:44
-
Enter `ffmpeg python` in your search engine, and take it from there. – boardrider May 14 '17 at 12:50
-
1This rule should be revised. It gets in the way of progress. – P i Feb 21 '23 at 08:28
3 Answers
Since a wav
file basically is raw audio data, you won't be able to change the pitch without "raw audio processing".
Here is what you could do.
You will need the wave
(standard library) and numpy
modules.
import wave
import numpy as np
Open the files.
wr = wave.open('input.wav', 'r')
# Set the parameters for the output file.
par = list(wr.getparams())
par[3] = 0 # The number of samples will be set by writeframes.
par = tuple(par)
ww = wave.open('pitch1.wav', 'w')
ww.setparams(par)
The sound should be processed in small fractions of a second. This cuts down on reverb. Try setting fr
to 1; you'll hear annoying echos.
fr = 20
sz = wr.getframerate()//fr # Read and process 1/fr second at a time.
# A larger number for fr means less reverb.
c = int(wr.getnframes()/sz) # count of the whole file
shift = 100//fr # shifting 100 Hz
for num in range(c):
Read the data, split it in left and right channel (assuming a stereo WAV file).
da = np.fromstring(wr.readframes(sz), dtype=np.int16)
left, right = da[0::2], da[1::2] # left and right channel
Extract the frequencies using the Fast Fourier Transform built into numpy.
lf, rf = np.fft.rfft(left), np.fft.rfft(right)
Roll the array to increase the pitch.
lf, rf = np.roll(lf, shift), np.roll(rf, shift)
The highest frequencies roll over to the lowest ones. That's not what we want, so zero them.
lf[0:shift], rf[0:shift] = 0, 0
Now use the inverse Fourier transform to convert the signal back into amplitude.
nl, nr = np.fft.irfft(lf), np.fft.irfft(rf)
Combine the two channels.
ns = np.column_stack((nl, nr)).ravel().astype(np.int16)
Write the output data.
ww.writeframes(ns.tostring())
Close the files when all frames are processed.
wr.close()
ww.close()

- 42,427
- 3
- 64
- 94
-
ok. i can read first second and change pitch by 500 (of what?), i want for example change pitch by 1 semitone. How can i read whole file and change its pitch once for whle file. I cant believe that it possible by only changing pitch of each second. When i try `readframes(wr.getnframes())` and `np.roll(lf, 500)` pitch doesn't change, and i need use another bigger value instead of 500. – Daniel May 15 '17 at 08:58
-
@DanielReshetnikov I've re-written my answer. It turns out you need to process fractions of a second at a time to prevent nasty echos. – Roland Smith May 15 '17 at 20:02
-
Now I can transpose whole file. It's a little bit better. Now i can change pitch in hertzes, but unfortunately it is not possible to convert hertzes to semitones (my fault - I didn't I outlined it in this issue). – Daniel May 17 '17 at 10:50
-
What if one wants to shift by a small amount, like 3.4 hz Low piano frequencies are shifted by small amounts like that https://en.wikipedia.org/wiki/Piano_key_frequencies – spacether Nov 22 '20 at 03:13
-
When I run the code from this answer, I get this issue: `` ValueError Traceback (most recent call last)
in – user163859 Sep 13 '21 at 08:245 6 # Extract the frequencies using the Fast Fourier Transform built into numpy. ----> 7 lf, rf = np.fft.rfft(left), np.fft.rfft(right) 8 9 # Roll the array to increase the pitch. <__array_function__ internals> in rfft(*args, **kwargs) [...] ValueError: Invalid number of FFT data points (0) specified. ``
I recommend trying Librosa's pitch shift function: https://librosa.github.io/librosa/generated/librosa.effects.pitch_shift.html
import librosa
y, sr = librosa.load('your_file.wav', sr=16000) # y is a numpy array of the wav file, sr = sample rate
y_shifted = librosa.effects.pitch_shift(y, sr, n_steps=4) # shifted by 4 half steps

- 6,651
- 3
- 42
- 46
-
1
-
Unfortunately libroasa still isn't working for Python 3.11 (bytecode-changes--related) ref: https://github.com/librosa/librosa/issues/1644 – P i Feb 21 '23 at 08:41
-
The quality of the ouput audio I get with librosa is pretty bad compared to the original (I'm only shifting by 2 semitones), am I the only one having this problem? Any recomendations on how to improve the quality? – Hiperfly Jun 27 '23 at 12:35
You can try pydub for quick and easy pitch change across entire audio file and for different formats (wav, mp3 etc).
Here is a working code. Inspiration from here and refer here for more details on pitch change.
from pydub import AudioSegment
from pydub.playback import play
sound = AudioSegment.from_file('in.wav', format="wav")
# shift the pitch up by half an octave (speed will increase proportionally)
octaves = 0.5
new_sample_rate = int(sound.frame_rate * (2.0 ** octaves))
# keep the same samples but tell the computer they ought to be played at the
# new, higher sample rate. This file sounds like a chipmunk but has a weird sample rate.
hipitch_sound = sound._spawn(sound.raw_data, overrides={'frame_rate': new_sample_rate})
# now we just convert it to a common sample rate (44.1k - standard audio CD) to
# make sure it works in regular audio players. Other than potentially losing audio quality (if
# you set it too low - 44.1k is plenty) this should now noticeable change how the audio sounds.
hipitch_sound = hipitch_sound.set_frame_rate(44100)
#Play pitch changed sound
play(hipitch_sound)
#export / save pitch changed sound
hipitch_sound.export("out.wav", format="wav")

- 10,893
- 6
- 47
- 74
-
5I tried your code. pitch is changing fine, but play speed also changing. I need only to change pitch. – Daniel May 17 '17 at 10:29
-
Bit of a long shot, but is there anyway of keeping the speed with this method? – b-fg Nov 20 '18 at 16:29
-
-
https://stackoverflow.com/questions/76696132/maintain-same-length-of-note-file-wav-while-pushing-up-the-octave-from-1a-to-7g – Ronalds Mazītis Jul 16 '23 at 10:39