0

Is it possible to stop a stream.write function before the buffer is consumed completely? When I try to do so, the sound is stopped, but the stream.write function never returns.

This is a working example of how I want to use a small class to play pure tone sounds without blocking the main thread.

import time
import sounddevice as sd
import numpy as np
from threading import Thread

toneduration = 10
samplerate = 44100
frequency = 440
amplitude = 0.5

sd.default.device = 1
sd.default.samplerate = samplerate
sd.default.channels = 2

class Sound(Thread):
    def __init__(self):
        Thread.__init__(self)
        self.stream = sd.OutputStream()
        self.stream.start()

        vector1 = np.linspace(0, toneduration, toneduration * samplerate)
        vector2 = amplitude * np.sin(2 * np.pi * frequency * vector1)
        vector3 = np.array([vector2, vector2])
        self.soundVector = np.ascontiguousarray(vector3.T, dtype=np.float32)

    def run(self):
        self.stream.write(self.soundVector)
        print('end')

sound = Sound()
sound.start()
time.sleep(3)
sound.stream.close()

I can play sounds of a given duration, but if I manually stop the stream using stream.close() the function doesn't return (the print('end') message is never displayed and the thread doesn't finish)

Do I have to use callback instead? In that case, how am I supposed to fill the buffer with a numpy array? I read the code examples in the documentation but I couldn’t figure it out how to do that.

bienqueda
  • 89
  • 5

1 Answers1

0

I guess the simplest way would be to use the play() function, which per default starts playback in the background (using a callback function called from a separate thread created by the underlying PortAudio library). You can then use the stop() function to stop playback.

If you need something more complicated than a simple playback of a NumPy array, you can implement your own callback function. As an example, you can look at the implementation of the play() function or at the examples, e.g. play_long_file.py.

As you mentioned, you can also use the so-called "blocking" API (using the write() method).

Either way, you would typically split your audio data into a series of blocks. This way, you can arrange for the playback to be stopped after any one of the blocks. This is also what the play() function does internally.

Matthias
  • 4,524
  • 2
  • 31
  • 50