How do I write raw bytes to a sound-device?
In the olden days, you used to be able to open /dev/dsp
for reading and writing, now, with PulseAudio this doesn't work anymore.
I thought you could do it with padsp
, but this code doesn't run:
import ossaudiodev
f = ossaudiodev.open("w")
fmt, channels, rate = dsp.setparameters(fmt, channels, rate)
(running it via padsp python script.py
)
The error I get is No such file or directory: '/dev/dsp'
.
What am I missing? How do I read and write raw bytes from and to a sound device, and how do I select which one I want to use?
This script is a thin wrapper around PulseAudio's Simple API. It allows you to write samples to the default output:
#!/usr/bin/env python3
import random
import ctypes
import struct
class NoiseMaker (object):
PA_SAMPLE_U8 = 0
PA_STREAM_PLAYBACK = 1
def __init__(self, rate, channels):
pat_sample_spec = ctypes.c_buffer(struct.pack("LLB",
self.PA_SAMPLE_U8, rate, channels))
self.pa = ctypes.cdll.LoadLibrary("libpulse-simple.so.0")
self.s = self.pa.pa_simple_new(0, "App", self.PA_STREAM_PLAYBACK,
0, "App Noise", ctypes.byref(pat_sample_spec), 0, 0,0)
def write(self, data):
self.pa.pa_simple_write(self.s, data, len(data), 0)
def __del__(self):
self.pa.pa_simple_free(self.s)
one_second_noise = bytes(random.randint(0, 255) for i in range(44100*2))
NoiseMaker(44100, 2).write(one_second_noise)
The rate (44100) defines how many samples there are in a second of real time. It expects bytes in the range of 0-255 inclusive, which is defined by PA_SAMPLE_U8 (equivalent to 'Unsigned 8-Bit' as shown by Audacity, for example). If you have more than one channel, it expects alternating samples for each of them. So, one second of noise has 44100 samples per channel = 88200 samples, where the (modulo 2 = 0) ones are for the left channel.
Please note that this script runs only on Python 3