Pythonic sound generator
[naja.git] / tools / gen_sound.py
index 7b13a819204f76d7635fcd38b6b31fc78a9734c4..1e9dd69a259f4c5188a4a8cc1296d29bdd8f42bb 100755 (executable)
@@ -1,72 +1,44 @@
 #!/usr/bin/env python
 
-# 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.
-
+from subprocess import Popen, PIPE
+import os
 import sys
-import math
-import struct
 
-OUTPUT_RATE = 8125
-DEFAULT_VOL = 95
+
+def gen_raw(description):
+    for chunk in description:
+        for blob in chunk.raw():
+            yield blob
 
 
-def gen_sine(freq, secs, volume):
-    filename = 'beep%s.pcm' % freq
-    # 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)
-    output = open(filename, 'wb')
-    # 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)):
-        output.write(b''.join(data))
-    output.close()
-    print ('Wrote output to %s' % filename)
+def encode(filename, data):
+    print "Writing %s" % filename
+    p = Popen(('oggenc', '-o', filename, '--raw', '--quiet', '-'),
+              stdin=PIPE, cwd='data/sounds')
+    for blob in data:
+        p.stdin.write(blob)
+    p.stdin.close()
+    assert p.wait() == 0
 
 
-def usage():
-    print ('Unexpected input')
-    print ('Usage gen_sound <freq> [<length>] [<volume>]')
-    print (' where <freq> is the frequency in Hz (int)')
-    print (' [<length>] is the time in seconds (float) - default 0.25')
-    print (' and [<volume>] is the volume (integer between 0 and 127)'
-           ' - default %s' % DEFAULT_VOL)
+def write(basename, description):
+    return encode('%s.ogg' % basename, gen_raw(description))
 
 
-if __name__ == "__main__":
-    try:
-        freq = int(sys.argv[1])
-        if len(sys.argv) > 2:
-            secs = float(sys.argv[2])
-        else:
-            secs = 0.25
-        if len(sys.argv) > 3:
-            volume = int(sys.argv[3])
-        else:
-            volume = DEFAULT_VOL
-    except Exception as exc:
-        usage()
-        print ('Error was: %s' % exc)
-        sys.exit(1)
+def main():
+    sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
+    from data.sounds import SOUNDS
+    from naja.gen_sound import Chunk
 
-    if volume > 128 or volume < 0:
-        usage()
-        print ('Invalid volume: %s' % volume)
-        sys.exit(1)
+    sounds = SOUNDS.keys()
+    if len(sys.argv) > 1:
+        sounds = (sys.argv[1:])
+    for sound in sounds:
+        description = SOUNDS[sound]
+        if isinstance(description, Chunk):
+            description = (description,)
+        write(sound, description)
 
-    if freq > 2000 or freq < 100:
-        usage()
-        print ('Invalid freq: %s' % volume)
-        sys.exit(1)
 
-    gen_sine(freq, secs, volume)
+if __name__ == '__main__':
+    main()