synthesizing an audio pitch in python [closed] - python

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
i was wondering if there is a way to set the audio pitch. A certain tone would be the base. i want to know how to make the pitch go up or down. thanks.
also how do you play an audio tone. also if you know about any modules that do this, i would like to know them thanks.
my goal is to create a pong game that a blind person could play. the higher the ball is, the higher the pitch. the lower the ball, the lower the pitch. preferably in python. thanks in advance

If you want to try pyaudio library, then you can use this function piece of code I created some days ago!
import pyaudio
import struct
import math
SHRT_MAX=32767 # short uses 16 bits in complement 2
def my_sin(t,frequency):
radians = t * frequency * 2.0 * math.pi
pulse = math.sin(radians)
return pulse
#pulse_function creates numbers in [-1,1] interval
def generate(duration = 5,pulse_function = (lambda t: my_sin(t,1000))):
sample_width=2
sample_rate = 44100
sample_duration = 1.0/sample_rate
total_samples = int(sample_rate * duration)
p = pyaudio.PyAudio()
pformat = p.get_format_from_width(sample_width)
stream = p.open(format=pformat,channels=1,rate=sample_rate,output=True)
for n in range(total_samples):
t = n*sample_duration
pulse = int(SHRT_MAX*pulse_function(t))
data=struct.pack("h",pulse)
stream.write(data)
#example of a function I took from wikipedia.
major_chord = f = lambda t: (my_sin(t,440)+my_sin(t,550)+my_sin(t,660))/3
#choose any frequency you want
#choose amplitude from 0 to 1
def create_pulse_function(frequency=1000,amplitude=1):
return lambda t: amplitude * my_sin(t,frequency)
if __name__=="__main__":
# play fundamental sound at 1000Hz for 5 seconds at maximum intensity
f = create_pulse_function(1000,1)
generate(pulse_function=f)
# play fundamental sound at 500Hz for 5 seconds at maximum intensity
f = create_pulse_function(500,1)
generate(pulse_function=f)
# play fundamental sound at 500Hz for 5 seconds at 50% intensity
f = create_pulse_function(500,0.5)
generate(pulse_function=f)

Related

Unsure of calculation step in polygon formula [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 months ago.
Improve this question
The final step seen on Symbolab: is a conversion to decimal to get Radius = 2005.65151, which I'm not sure how to recreate or if there's a step in between.
The result I have so far (RadiusD) prints a fraction.
Image: Polygon formula where S = side length. N = num sides, r = radius
Error in this code:
import math
from fractions import Fraction, Decimal
def TestRadius():
HalfSideLen = 120/2
#60
edgeNum2Radians = math.radians(105) #Edge count
Radians = math.pi/edgeNum2Radians # correct so far
# 1.7142857142857142
Radius = HalfSideLen / math.sin(Radians)
RadiusD = Decimal(HalfSideLen / math.sin(Radians))
#1066491443117295/17592186044416
# wanting r = 2005.65151
print(RadiusD)
print(TestRadius())
My math is very poor, thanks for your help
Corrected by #ytung-dev. Somehow step 3 was returning a correct result so I didn't look too close at Step 2, where actually it was the error.
import math
def TestRadius():
HalfSideLen = 120/2
edgeNum = 105
Radians = math.pi/edgeNum
Radius = HalfSideLen / math.sin(Radians)
print(Radius)
print(TestRadius())
Try this:
import math
def fx(s,n):
return s / ( 2 * math.sin(math.pi/n) )
print(fx(120, 105))
# 2005.65
Few things to note:
math.sin() use radian
sin() in symbolab use degree
equation in your image use degree
180 deg = math.pi rad
What is wrong in your script is that edgeNum is a counting number not an angle, so you should not convert it to radian. The only degree-radian conversion you should handle is the 180 deg in the equation.
So, to make your equation work in python, you simply change the 180 deg in the equation to math.pi.

Add random noise to tone using python

I am trying to detect sudden loud noises in audio recordings. One way I have found to do this is by creating a spectrogram of the audio and adding the values of each column. By graphing the sum of the values in each column, one can see a spike every time there is a sudden loud noise. The problem is that, in my use case, I need to play a beep tone (with a frequency of 2350 Hz), while the audio is being recorded. The spectrogram of the beep looks like this:
As you can see, at the beginning and the end of this beep (which is a simple tone with a frequency of 2350 Hz), there are other frequencies present, which I have been unsuccessful in removing. These unwanted frequencies cause a spike when summing up the columns of the spectrogram, at the beginning and at the end of the beep. I want to avoid this because I don't want my beep to be detected as a sudden loud noise. See the spectrogram below for reference:
Here is what the graph of the sum of each column in the spectrogram:
Obviously, I want to avoid having false positives in my algorithm. So I need some way of getting rid of the spikes caused by the beginning and end of the beep. One idea that I have had so far is to add random noise with a low decibel value above and/or below the 2350 Hz line in the beep spectrogram above. This would ideally, create a tone that sounds very similar to the original, but instead of creating a spike when I add up all the values in the column, it would create more of a plateau. Is this idea a feasible solution to my problem? If so, how would I go about creating a beep sound that has random noise like I described above using python? Is there another, easier solution to my problem that I am overlooking?
Currently, I am using the following code to generate my beep sound:
import math
import wave
import struct
audio = []
sample_rate = 44100.0
def append_sinewave(
freq=440.0,
duration_milliseconds=500,
volume=1.0):
"""
The sine wave generated here is the standard beep. If you want something
more aggresive you could try a square or saw tooth waveform. Though there
are some rather complicated issues with making high quality square and
sawtooth waves... which we won't address here :)
"""
global audio # using global variables isn't cool.
num_samples = duration_milliseconds * (sample_rate / 1000.0)
for x in range(int(num_samples)):
audio.append(volume * math.sin(2 * math.pi * freq * ( x / sample_rate )))
return
def save_wav(file_name):
# Open up a wav file
wav_file=wave.open(file_name,"w")
# wav params
nchannels = 1
sampwidth = 2
# 44100 is the industry standard sample rate - CD quality. If you need to
# save on file size you can adjust it downwards. The stanard for low quality
# is 8000 or 8kHz.
nframes = len(audio)
comptype = "NONE"
compname = "not compressed"
wav_file.setparams((nchannels, sampwidth, sample_rate, nframes, comptype, compname))
# WAV files here are using short, 16 bit, signed integers for the
# sample size. So we multiply the floating point data we have by 32767, the
# maximum value for a short integer. NOTE: It is theortically possible to
# use the floating point -1.0 to 1.0 data directly in a WAV file but not
# obvious how to do that using the wave module in python.
for sample in audio:
wav_file.writeframes(struct.pack('h', int( sample * 32767.0 )))
wav_file.close()
return
append_sinewave(volume=1, freq=2350)
save_wav("output.wav")
Not really an answer - more of a question.
You're asking the speaker to go from stationary to a sine wave instantaneously - that is quite hard to do (though the frequencies aren't that high). If it does manage it, then the received signal should be the convolution of the top hat and the sine wave (sort of like what you are seeing, but without having some data and knowing what you're doing for the spectrogram it's hard to tell).
In either case you could check this by smoothing the start and end of your tone. Something like this for your tone generation:
tr = 0.05 # rise time, in seconds
tf = duration_milliseconds / 1000 # finish time of tone, in seconds
for x in range(int(num_samples)):
t = x / sample_rate # Time of sample in seconds
# Calculate a bump function
bump_function = 1
if 0 < t < tr: # go smoothly from 0 to 1 at the start of the tone
tp = 1 - t / tr
bump_function = math.e * math.exp(1/(tp**2 - 1))
elif tf - tr < t < tf: # go smoothly from 1 to 0 at the end of the tone
tp = 1 + (t - tf) / tr
bump_function = math.e * math.exp(1/(tp**2 - 1))
audio.append(volume * bump_function * math.sin(2 * math.pi * freq * t))
You might need to tune the rise time a bit. With this form of bump function you know that you have a full volume tone from tr after the start to tr before the end. Lots of other functions exist, but if this smooths the start/stop effects in your spectrogram then you at least know why they are there. And prevention is generally better than trying to remove the effect in post-processing.

Making a wavetable synth for the first time...Can somebody point me in the right direction?

I'm trying to make a wavetable synthesizer in Python for the first time (based off an example I found here https://blamsoft.com/tutorials/expanse-creating-wavetables/) but the resultant sound I'm getting doesn't sound tonal at all. My output is just a low grainy buzz. I'm pretty new to making wavetables in Python and I was wondering if anybody might be able to tell me what I'm missing in order to write an A440 sine wavetable to the file "wavetable.wav" and have it actually produce a pure sine tone? Here's what I have at the moment:
import wave
import struct
import numpy as np
frame_count = 256
frame_size = 2048
sps = 44100
freq_hz = 440
file = "wavetable.wav" #write waveform to file
wav_file = wave.open(file, 'w')
wav_file.setparams((1, 2, sps, frame_count, 'NONE', 'not compressed'))
values = bytes(0)
for i in range(frame_count):
for ii in range(frame_size):
sample = np.sin((float(ii)/frame_size) * (i+128)/256 * 2 * np.pi * freq_hz/sps) * 65535
if sample < 0:
sample = 0
sample -= 32768
sample = int(sample)
values += struct.pack('h', sample)
wav_file.writeframes(values)
wav_file.close()
print("Generated " + file)
The sine function I have inside the for loop is probably the part I understand the least because I just went by the example verbatim. I'm used to making sine functions like (y = Asin(2πfx)) but I'm not sure what the purpose is of multiplying by ((i+128)/256) and 65535 (16-bit amplitude resolution?). I'm also not sure what the purpose is of subtracting 32768 from each sample. Is anyone able to clarify what I'm missing and maybe point me in the right direction? Am I going about this the wrong way? Any help is appreciated!
If you just wanted to generate sound data ahead of time and then dump it all into a file, and you’re also comfortable using NumPy, I’d suggest using it with a library like SoundFile. Then there’s no need to delimit the data into frames.
Starting with a naïve approach (using numpy.sin, not trying to optimize things yet), one ends with something like this:
from math import tau
import numpy as np
import soundfile as sf
file_path = 'sine.flac'
sample_rate = 48_000 # hertz
duration = 1.0 # seconds
frequency = 432.0 # hertz
amplitude = 0.8 # (not in decibels!)
start_phase = 0.0 # at what phase to start
sample_count = floor(sample_rate * duration)
# cyclical frequency in sample^-1
omega = frequency * tau / sample_rate
# all phases for which we want to sample our sine
phases = np.linspace(start_phase, start_phase + omega * sample_count,
sample_count, endpoint=False)
# our sine wave samples, generated all at once
audio = amplitude * np.sin(phases)
# now write to file
fmt, sub = 'FLAC', 'PCM_24'
assert sf.check_format(fmt, sub) # to make sure we ask the correct thing beforehand
sf.write(file_path, audio, sample_rate, format=fmt, subtype=sub)
This will be a mono sound, you can write stereo using 2d arrays (see NumPy and SoundFile’s docs).
But note that to make a wavetable specifically, you need to be sure it contains just a single period (or an integer number of periods) of the wave exactly, so the playback of the wavetable will be without clicks and have a correct frequency.
You can play chunked sound in real time in Python too, using something like PyAudio. (I’ve not yet used that, so at least for a time this answer would lack code related to that.)
Finally, frankly, all above is unrelated to the generation of sound data from a wavetable: you just pick a wavetable from somewhere, that doesn’t do much for actual synthesis. Here is a simple starting algorithm for that. Assume you want to play back a chunk of sample_count samples and have a wavetable stored in wavetable, a single period which loops perfectly and is normalized. And assume your current wave phase is start_phase, frequency is frequency, sample rate is sample_rate, amplitude is amplitude. Then:
# indices for the wavetable values; this is just for `np.interp` to work
wavetable_period = float(len(wavetable))
wavetable_indices = np.linspace(0, wavetable_period,
len(wavetable), endpoint=False)
# frequency of the wavetable played at native resolution
wavetable_freq = sample_rate / wavetable_period
# start index into the wavetable
start_index = start_phase * wavetable_period / tau
# code above you run just once at initialization of this wavetable ↑
# code below is run for each audio chunk ↓
# samples of wavetable per output sample
shift = frequency / wavetable_freq
# fractional indices into the wavetable
indices = np.linspace(start_index, start_index + shift * sample_count,
sample_count, endpoint=False)
# linearly interpolated wavetavle sampled at our frequency
audio = np.interp(indices, wavetable_indices, wavetable,
period=wavetable_period)
audio *= amplitude
# at last, update `start_index` for the next chunk
start_index += shift * sample_count
Then you output the audio. Though there are better ways to play back a wavetable, linear interpolation is at least a fine start. Frequency slides are also possible with this approach: just compute indices in another way, no longer spaced uniformly.

Python change pitch of wav file [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 5 years ago.
Improve this question
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.
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()
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
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")

Design of a Notch filter in Python [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 7 years ago.
Improve this question
I'm trying to design an IIR Notch filter in python using numpy array and the scipy librairy to remove a sine tone from a imported wave file (I'm using the wave module to do so). My file was generated by Adobe audition : it is a pure sine # 1.2 kHZ, sampled # 48, 96 or 192 kHz, in order to have a "pseudo-periodic" data for my circular fft (just ask if I'm not clear enough)
Here is the code I used to implement the coefficient of my filter (I get the coefficient from the article "Second-order IIR Notch Filter Design and implementation of digital signal
processing system" by C. M. Wang & W. C. Xiao)
f_cut = 1200.0
wn = f_cut/rate
r = 0.99
B, A = np.zeros(3), np.zeros(3)
A[0],A[1],A[2] = 1.0, -2.0*r*np.cos(2*np.pi*wn), r*r
B[0],B[1],B[2] = 1.0, -2.0*np.cos(2*np.pi*wn), 1.0
filtered = signal.lfilter(B, A, data_flt_R, axis=0)
Where data_flt_R is a numpy array containing my right channel in a float64 type, and rate is my sampling frequency. I plot the frequency response and the fft of my data using the matplotlib module to see if everything is ok.
N = len(data_flt_R)
w, h = signal.freqz(B,A, N)
pyplot.subplot(2,1,1)
pyplot.semilogx(w*rate/(2*np.pi), 20*np.log10(np.absolute(h)))
fft1 = fftpack.fft(data_flt_R, N)
fft_abs1 = np.absolute(fft1)
ref = np.nanmax(fft_abs1)
dB_unfiltered = 20*np.log10(fft_abs1/ref)
fft2 = fftpack.fft(filtered, N)
fft_abs2 = np.absolute(fft2)
dB_filtered = 20*np.log10(fft_abs2/ref)
abs = fftpack.fftfreq(N,1.0/rate)
pyplot.subplot(2,1,2)
pyplot.semilogx(abs,dB_unfiltered,'r', label='unfiltered')
pyplot.semilogx(abs,dB_filtered,'b', label='filtered')
pyplot.grid(True)
pyplot.legend()
pyplot.ylabel('power spectrum (in dB)')
pyplot.xlim(10,rate/2)
pyplot.xlabel('frequencies (in Hz)')
And here is what I get :
I don't understand the results and values I get before and after my fc. Shouldn't I get a plot which looks like the red one but whithout the main peak ? Why do I have a slope in HF? Is this linked with windowing?
Moreover, the result changes if I change my sampling frequency and/or the data length (16/24 or 32 bits). Can anyone enlighten me?

Categories