Pythonic sound generator
[naja.git] / naja / gen_sound.py
diff --git a/naja/gen_sound.py b/naja/gen_sound.py
new file mode 100644 (file)
index 0000000..8ad0479
--- /dev/null
@@ -0,0 +1,49 @@
+import math
+import struct
+
+
+def gen_sine(freq, secs, volume):
+    """
+    Generate imperfect sine waves
+
+    Design notes. Produces ~= (user requested) s of raw audio
+    We're aiming for an 8-bit'ish effect, so we're going with
+    8125 Hz, 8 bit sampling, but faking it out to
+    CDDA output (44100 Hz, 16 bit signed) for easier conversion to ogg
+    by multiply the value by 256 (after roundin) and repeating it 4 times.
+    """
+    OUTPUT_RATE = 8125
+    # We generate freq cycles and sample that OUTPUT_RATE times
+    per_cycle = OUTPUT_RATE // freq
+    data = []
+    for x in range(per_cycle):
+        rad = float(x) / per_cycle * 2 * math.pi
+        y = 256 * int(volume * math.sin(rad))
+        data.extend([struct.pack('<i', y)] * 4)
+    # This is correct because OUTPUT_RATE = CDDA rate / 4 and we repeat
+    # the samples 4 times, so this works out to CDDA rate
+    for x in range(int(freq * secs)):
+        yield b''.join(data)
+
+
+class Chunk(object):
+    def __init__(self, type, **kwargs):
+        self.type = type
+        self.volume = 95
+        self.length = 0.25
+        for k, v in kwargs.iteritems():
+            setattr(self, k, v)
+
+    def raw(self):
+        if self.type == 'silence':
+            for i in xrange(int(176400 * self.length)):
+                yield '\x00'
+
+        if self.type == 'sine':
+            for data in gen_sine(self.freq, self.length, self.volume):
+                yield data
+
+
+def scale(start, stop, step, type='sine', **kwargs):
+    for freq in range(start, stop, step):
+        yield Chunk(type, freq=freq, **kwargs)