Reputation: 35
In Python, with sounddevice, I am trying to simultaneously play on an output and record on an input, then to plot the signals on top of each other in a way to represent what is happening in the real world. I'm using the Stream class and currently my callback function looks like this:
def callback(indata, outdata, frames, time, status):
if status:
print(status)
if not hasattr(callback, "lastframe"):
callback.lastframe = 0 # Initialiser la première fois
lastframe = callback.lastframe
end = lastframe+frames
size = len(out[lastframe:end])
outdata[:size,0] = out[lastframe:end]
outsig['signal'] = np.append(outsig['signal'],outdata[:,0])
outsig['time'] = np.append(outsig['time'],np.linspace(time.outputBufferDacTime,time.outputBufferDacTime+(frames-1)/48e3,frames))
callback.lastframe = end
insig['signal'] = np.append(insig['signal'],indata)
insig['time'] = np.append(insig['time'],np.linspace(time.inputBufferAdcTime,time.inputBufferAdcTime+(frames-1)/48e3,frames))
if size < frames:
raise sd.CallbackStop
I know this callback isn't perfect, but in my point of view it should be a good proof of concept of what i'm trying to do. I'm getting the time.outputBufferDacTime and time.inputBufferAdcTime variable to know when the first sample of the block will be played (or has been recorded) and then knowing the sampling frequency and the blocksize, I can build a time vector for the output and input signals.
I'm close to the results I'm expecting but sometimes, the next block don't start where the previous block ended. (see plot below)
This artefact seems to come from my code because I can't hear it on the output, and they aren't synchronized between the input and output, so I'm assuming they are not present in the "real world".
Any idea where this can come from ?
Upvotes: 0
Views: 68
Reputation: 4884
The values in the time
variable are estimates, they are not exact. Depending on host API, device driver, and actual hardware, they might be more or less exact.
If you want to plot the signal, you should just concatenate the audio blocks from the callback function. Conceptually, your sound card does the same: it just plays a sequence of samples at its sampling rate, the time values at the beginning of each block are implicit.
If you want to compensate for the latency between input and output, you can use the value in mystream.latency
or the time
values in the callback, but again, both are somewhat unreliable estimates. If you want to have a more reliable estimate for the latency between the inputs and outputs of your sound card, you can measure it with a loop-back cable.
There might be some drift between the sampling rate of the device and the wall-clock time, but you only have to worry about this if you make veeeeery long recordings.
Upvotes: 0