Correct the sine example (finally!) Closes #10

This commit is contained in:
Lars Immisch
2017-02-25 01:04:18 +01:00
parent 698e6044d3
commit 94ced0517e
+40 -24
View File
@@ -6,30 +6,50 @@
from __future__ import print_function from __future__ import print_function
import sys
from threading import Thread from threading import Thread
from queue import Queue, Empty from multiprocessing import Queue
if sys.version_info[0] < 3:
from Queue import Empty
else:
from queue import Empty
from math import pi, sin from math import pi, sin
import struct import struct
import alsaaudio import alsaaudio
sampling_rate = 44100 sampling_rate = 48000
format = alsaaudio.PCM_FORMAT_S16_LE format = alsaaudio.PCM_FORMAT_S16_LE
framesize = 2 # bytes per frame for the values above framesize = 2 # bytes per frame for the values above
channels = 2
def digitize(s): def nearest_frequency(frequency):
if s > 1.0 or s < -1.0: # calculate the nearest frequency where the wave form fits into the buffer
raise ValueError # in other words, select f so that sampling_rate/f is an integer
return float(sampling_rate)/int(sampling_rate/frequency)
return struct.pack('h', int(s * 32767)) def generate(frequency, duration = 0.125):
# generate a buffer with a sine wave of `frequency`
# that is approximately `duration` seconds long
def generate(frequency): # the buffersize we approximately want
# generate a buffer with a sine wave of frequency target_size = int(sampling_rate * channels * duration)
size = int(sampling_rate / frequency)
buffer = bytes() # the length of a full sine wave at the frequency
for i in range(size): cycle_size = int(sampling_rate / frequency)
buffer = buffer + digitize(sin(i/(2 * pi)))
# number of full cycles we can fit into target_size
factor = int(target_size / cycle_size)
size = max(int(cycle_size * factor), 1)
sine = [ int(32767 * sin(2 * pi * frequency * i / sampling_rate)) \
for i in range(size)]
return struct.pack('%dh' % size, *sine)
return buffer
class SinePlayer(Thread): class SinePlayer(Thread):
@@ -37,7 +57,7 @@ class SinePlayer(Thread):
Thread.__init__(self) Thread.__init__(self)
self.setDaemon(True) self.setDaemon(True)
self.device = alsaaudio.PCM() self.device = alsaaudio.PCM()
self.device.setchannels(1) self.device.setchannels(channels)
self.device.setformat(format) self.device.setformat(format)
self.device.setrate(sampling_rate) self.device.setrate(sampling_rate)
self.queue = Queue() self.queue = Queue()
@@ -48,18 +68,14 @@ class SinePlayer(Thread):
# we generate the buffer in the calling thread for less # we generate the buffer in the calling thread for less
# latency when switching frequencies # latency when switching frequencies
if frequency > sampling_rate / 2:
raise ValueError('maximum frequency is %d' % (sampling_rate / 2))
# More than 100 writes/s are pushing it - play multiple buffers f = nearest_frequency(frequency)
# for higher frequencies print('nearest frequency: %f' % f)
factor = int(frequency/100.0) buf = generate(f)
if factor == 0: self.queue.put(buf)
factor = 1
buf = generate(frequency) * factor
print('factor: %d, frames: %d' % (factor, len(buf) / framesize))
self.queue.put( buf)
def run(self): def run(self):
buffer = None buffer = None