Few days ago, I have installed a sounddevice library in Python 2.7.5. I'm trying to make a sound array and add some effects to it immediately after I push a key on my MIDI controller. But I get a huge delay of 0.1 to 0.2 second which makes my code useless:
import numpy as np
import sounddevice as sd
import time
import math
#we're making a sound array with a 5 seconds length noisy sound and playing it:
duration=5
framerate = 44100
array=0.02*np.random.uniform(-1, 1, framerate*duration)
sd.play(array, framerate)
t=time.time()
while(True):
signal=raw_input("push ENTER to hear a beep")
start_iter=int(framerate*(time.time()-t))
end_iter=min(start_iter+framerate/4, len(array))
#we're trying to change our data array and play a beep signal of 0.25 second after each ENTER press instantly
for i in range(start_iter, end_iter):
array[i]=0.05*math.sin(440*2*math.pi*i/44100.)
if end_iter==len(array): break #safe exit of a process after 5 seconds has passed
To keep it simple, my sound array is just a noisy sound and my effect consists of a 440Hz beep. I used raw_input() here (type "input()" in Python 3.x) instead of MIDI inputs which could be possible using Pygame library. My code works but each time we press ENTER we will hear a short delay before beep signal. Is it possible to eliminate it? If not, any other libraries allowing to play a sound stream with no delays live?
You can specify the desired latency with sounddevice.default.latency. Note however, that this is a suggested latency, the actual latency may be different, depending on the hardware and probably also on the host API. You can get an estimate of the actual latency with sounddevice.Stream.latency.
By default, the sounddevice
module uses PortAudio's high latency setting in the hope to provide more robust behavior. You can switch it to PortAudio's low setting, or you can try whatever numeric value (in seconds) you want.
import sounddevice as sd
sd.default.latency = 'low'
Alternatively, you can of course also use the latency
argument of play()
etc.
If you want to have more control over the time, you might want to write your own custom callback function. There you can use the time
argument, and outside of the callback function you can use sounddevice.Stream.time.
You can also try to start a stream without using the callback
argument and then use sounddevice.Stream.write() on it. I don't know what that will do to the latency, but it might be worth a try.
Regarding other libraries, since you seem to be using PyGame already, you might also use it for the audio output. It might or might not have a different latency.
BTW, I don't know if your code is thread-safe since you are manipulating the array while the callback gives the memory addresses to PortAudio. It's probably not a good idea to implement it like this.