diff --git a/CHANGES b/CHANGES index b1c9f55..e5b95c4 100644 --- a/CHANGES +++ b/CHANGES @@ -3,6 +3,7 @@ Version 0.5: This included a mixertest with more features - fixed/applied patch 2594366: alsapcm_setup does not do any error checking + Version 0.4: - API changes: mixers() and Mixer() now take a card index instead of a card name as optional parameter. diff --git a/isine.py b/isine.py new file mode 100644 index 0000000..f71611e --- /dev/null +++ b/isine.py @@ -0,0 +1,79 @@ +''' Use this example from an interactive python session, for example: + +>>> from isine import change +>>> change(880) +''' + +from threading import Thread +from Queue import Queue, Empty +from math import pi, sin +import struct +import alsaaudio + +sampling_rate = 44100 +format = alsaaudio.PCM_FORMAT_S16_LE +framesize = 2 # bytes per frame for the values above + +def digitize(s): + if s > 1.0 or s < -1.0: + raise ValueError + + return struct.pack('h', int(s * 32767)) + +def generate(frequency): + # generate a buffer with a sine wave of frequency + size = int(sampling_rate / frequency) + buffer = '' + for i in range(size): + buffer = buffer + digitize(sin(i/(2 * pi))) + + return buffer + +class SinePlayer(Thread): + + def __init__(self, frequency = 440.0): + Thread.__init__(self) + self.setDaemon(True) + self.device = alsaaudio.PCM() + self.device.setchannels(1) + self.device.setformat(format) + self.device.setrate(sampling_rate) + self.queue = Queue() + self.change(frequency) + + def change(self, frequency): + '''This is called outside of the player thread''' + # we generate the buffer in the calling thread for less + # latency when switching frequencies + + + # More than 100 writes/s are pushing it - play multiple buffers + # for higher frequencies + + factor = int(frequency/100.0) + if factor == 0: + factor = 1 + + buf = generate(frequency) * factor + print 'factor: %d, frames: %d' % (factor, len(buf) / framesize) + + self.queue.put( buf) + + def run(self): + buffer = None + while True: + try: + buffer = self.queue.get(False) + self.device.setperiodsize(len(buffer) / framesize) + self.device.write(buffer) + except Empty: + if buffer: + self.device.write(buffer) + + +isine = SinePlayer() +isine.start() + +def change(f): + isine.change(f) + diff --git a/playwav.py b/playwav.py index 97c8f99..218c7c2 100755 --- a/playwav.py +++ b/playwav.py @@ -14,13 +14,18 @@ import alsaaudio def play(device, f): + + sys.stdout.write('%d channels, %d sampling rate\n' % (f.getnchannels(), + f.getframerate())) # Set attributes device.setchannels(f.getnchannels()) device.setrate(f.getframerate()) - # We assume signed data, little endian + + # We 8bit is unsigned in wav files if f.getsampwidth() == 1: - device.setformat(alsaaudio.PCM_FORMAT_S8) + device.setformat(alsaaudio.PCM_FORMAT_U8) + # Otherwise we assume signed data, little endian elif f.getsampwidth() == 2: device.setformat(alsaaudio.PCM_FORMAT_S16_LE) elif f.getsampwidth() == 3: