Josemi
Josemi

Reputation: 346

How to reproduce an audio signal by frames python?

I'd like to reproduce an audio signal by frames in a loop in python. In order to do that, I've tried with:

import sounddevice as sd

#Suppose:
nframes = 750
lframe = 882
fs = 44100

#Loop
for i in range(0,nframes):
    sd.play(signal[i*lframe:(i+1)*lframe].astype('int16'),fs,blocking=True)

But I don't hear anything. I have checked that sd.play(signal.astype('int16'),fs,blocking=True) works correctly.

Thank you for your help in advance

Upvotes: 2

Views: 1139

Answers (2)

mathfux
mathfux

Reputation: 5939

Note that length of signal = 10000 * np.sin(2 * np.pi * fs * samples) is the same of length samples. In this case the most of junks signal[i:i+lframe] are empty.

My working example is:

import numpy as np
import sounddevice as sd

lframe = 882 * 10
fs = 44100
frequency = 880

samples = np.arange(0, 1, step=1/fs)
signal = 10000 * np.sin(2 * np.pi * frequency * samples)

for i in range(0, fs, lframe):
    sd.play(signal[i:i+lframe].astype('int16'), blocking=True, latency = 'low')

In this case nframes is not needed because we can calculate it dividing fs/lframe.

The main problem is that there is some delay after each sd.play. If we take lframe = 882, number of frames is 50 per second. The length of every frame is 0.02s which is shorter than delay. Hence I replace lframe = 882 with lframe = 882 * 10.

On my laptop, the minimal multiplier so that I can hear any signal is lframe = 882 * 8. Using latency = 'low' helped me to reduce it to lframes = 882 * 4 to hear some signal.

Upvotes: 1

Anil_M
Anil_M

Reputation: 11443

I am assuming nframes as "number of frames" and lframe as "length of frame chunk".
In that case nframes < lframe - Do you have typo there?

Lets assume nframes = 7500 which gives 8 chunks of length 882.

What we need is to create chunks of signal array of length lframe and then play those individually. We change range to xrange as xrange is easier at handling chunks and create signal chunks in steps of lframes and then simply play those.

for i in xrange(0, len(signal),lframe):
        sd.play(signal[i:i+lframe].astype('int16'),blocking=True)

Full Working Code:

import numpy as np
import sounddevice as sd

nframes = 7500
lframe = 882
fs = 44100

samples = np.arange(nframes)/float(nframes)
signal = 10000 * np.sin(2 * np.pi * fs * samples)


for i in xrange(0, len(signal),lframe):
    sd.play(signal[i:i+lframe].astype('int16'),blocking=True)

Upvotes: 1

Related Questions