5

I'm writing a code that supposed to give some audio output to the user based on his action, and I want to generate the sound rather than having a fixed number of wav files to play. Now, what I'm doing is to generate the signal in numpy format, store the data in a wav file and then read the same file into pyaudio. I think this is redundant, however, I couldn't find a way to do that. My question is, can I stream a numpy array (or a regular list) directly into my the pyaudio to play?

2
  • Yes. You can just read the data directly from the numpy array into the CHUNKs you pass into pyaudio. You should be able to find examples by searching a bit. afaik, there's no structure built into IPython to do this for the entire array in one go though. Commented Jun 5, 2015 at 21:22
  • 3
    You can use the play() function of python-sounddevice.rtfd.org to directly play back NumPy arrays in one go. Commented Jul 29, 2015 at 14:12

3 Answers 3

7

If its just playback and does not need to be synchronised to anything then you can just do the following:

# Open stream with correct settings
stream = self.p.open(format=pyaudio.paFloat32,
                         channels=CHANNELS,
                         rate=48000,
                         output=True,
                         output_device_index=1
                         )
# Assuming you have a numpy array called samples
data = samples.astype(np.float32).tostring()
stream.write(data)

I use this method and it works fine for me. If you need to record at the same time then this won't work.

Sign up to request clarification or add additional context in comments.

1 Comment

DeprecationWarning: tostring() is deprecated. Use tobytes() instead.
2

If you are just looking to generate audio tones then below code may be useful,

It does need pyaudio that can be installed as

pip install pyaudio

Sample Code

#Play a fixed frequency sound.
from __future__ import division
import math
import pyaudio

#See http://en.wikipedia.org/wiki/Bit_rate#Audio
BITRATE = 44100 #number of frames per second/frameset.      

#See http://www.phy.mtu.edu/~suits/notefreqs.html
FREQUENCY = 2109.89 #Hz, waves per second, 261.63=C4-note.
LENGTH = 1.2 #seconds to play sound

NUMBEROFFRAMES = int(BITRATE * LENGTH)
RESTFRAMES = NUMBEROFFRAMES % BITRATE
WAVEDATA = ''    

for x in xrange(NUMBEROFFRAMES):
WAVEDATA = WAVEDATA+chr(int(math.sin(x/((BITRATE/FREQUENCY)/math.pi))*127+128))    

#fill remainder of frameset with silence
for x in xrange(RESTFRAMES): 
WAVEDATA = WAVEDATA+chr(128)

p = pyaudio.PyAudio()
stream = p.open(format = p.get_format_from_width(1), 
            channels = 1, 
            rate = BITRATE, 
            output = True)
stream.write(WAVEDATA)
stream.stop_stream()
stream.close()
p.terminate()

Code is slightly modified from this askubuntu site

3 Comments

Why does this pop when starting and ending?
You are hearing clicking sound as peaks of two frames are not matching. See my this SO posting for possible solution stackoverflow.com/questions/36438850/…
I'm using your code above though. Nothing else. In fact even if I write 0s, I seem to get popping. But if I changed to a wider sample-depth (eg. 32bit), there is no popping.
2

You can directly stream the data through pyaudio, there is no need to write and read a .wav file.

import pyaudio
p = pyaudio.PyAudio()
stream = p.open(format=pyaudio.paFloat32,
                channels=1,
                rate=44100,
                frames_per_buffer=1024,
                output=True,
                output_device_index=1
                )
samples = np.sin(np.arange(50000)/20)
stream.write(samples.astype(np.float32).tostring())
stream.close()

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.