Skip to content

Instantly share code, notes, and snippets.

@bharadwaj-raju
Created December 23, 2017 16:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bharadwaj-raju/f8bf7d65811b6a2f444202594f5e0146 to your computer and use it in GitHub Desktop.
Save bharadwaj-raju/f8bf7d65811b6a2f444202594f5e0146 to your computer and use it in GitHub Desktop.
Python-SoundGen

Python-SoundGen

Python scripts to generate sound from descriptions of sound waves.

Waveform formula from http://code.activestate.com/recipes/578168-sound-generator-using-wav-file/

License: MIT

There are three versions: soundgen.py, soundgen2.py and soundgen3.py. If in doubt, use soundgen3.py

soundgen3.py

Latest iteration.

Allows you to specify a series of tones, each tone being an ordered triplet (duration, frequency, amplitude%).

$ python3 soundgen3.py {duration},{freq},{amplitude%} [...] [--play]

For example,

$ python3 soundgen3.py 4,44,100 6,440,100 2,440,50 --play

generates a wav audio with 4 seconds of 44 Hz waves at 100% amplitude, then 6s of 440 Hz at 100%, then 2s of 440 Hz at 50%, and plays the resulting wav (--play). Omit --play to only generate audio and not play it.

soundgen2.py

Similar to soundgen3.py, generates series of tones, except amplitude cannot be specified (i.e. is assumed to be 100%).

soundgen.py

Original version.

Generates a single tone of given duration and frequency.

$ python3 soundgen.py duration freq [--play]

For example,

$ python3 soundgen.py 10 440 --play

generates a wav audio with 10 seconds of 440 Hz waves at 100% amplitude (which is assumed; cannot be specified), and plays the resulting wav (--play). Omit --play to only generate audio and not play it.

import math
import sys
import wave
import array
import subprocess as sp
import base64
import hashlib
# Usage: soundgen.py seconds freq [--play]
duration, freq = [int(x) for x in sys.argv[1:3]]
data = array.array('h') # signed short integer (-32768 to 32767) data
sample_rate = 44100 # samples/second, 44100 = CD Quality Audio
n_channels = 1 # of channels (1 = mono, 2 = stereo)
data_size = 2 # 2 bytes because of using signed short integers => bit depth = 16
n_samples_per_cycle = int(sample_rate / freq)
n_samples = sample_rate * duration
for i in range(n_samples):
sample = 32767 * math.sin(math.pi * 2 * (i % n_samples_per_cycle) / n_samples_per_cycle)
data.append(int(sample))
with wave.open('Sound_%dHz_%ds.wav' % (freq, duration), 'w') as f:
f.setparams((n_channels, data_size, sample_rate, n_samples, "NONE", "Uncompressed"))
f.writeframes(data.tostring())
print(hashlib.md5(base64.b64encode(data.tobytes())).hexdigest())
if '--play' in sys.argv:
sp.Popen(['aplay', 'Sound_%dHz_%ds.wav' % (freq, duration)]).wait()
import math
import sys
import wave
import array
import subprocess as sp
from collections import namedtuple
import base64
import hashlib
# Usage: soundgen.py seconds,freq [...] [--play]
Tone = namedtuple('Tone', 'duration freq')
tones_raw = [x for x in sys.argv[1:] if x != '--play']
tones = []
for tone_raw in tones_raw:
tones.append(Tone(*[int(x) for x in tone_raw.split(',')]))
data = array.array('h') # signed short integer (-32768 to 32767) data
sample_rate = 44100 # samples/second, 44100 = CD Quality Audio
n_channels = 1 # of channels (1 = mono, 2 = stereo)
data_size = 2 # 2 bytes because of using signed short integers => bit depth = 16
for tone in tones:
n_samples_per_cycle = int(sample_rate / tone.freq)
n_samples = sample_rate * tone.duration
for i in range(n_samples):
sample = 32767 * math.sin(math.pi * 2 * (i % n_samples_per_cycle) / n_samples_per_cycle)
data.append(int(sample))
uid = hashlib.md5(base64.b64encode(data.tostring())).hexdigest()
with wave.open('Sound_%s.wav' % uid, 'w') as f:
f.setparams((n_channels, data_size, sample_rate, n_samples, "NONE", "Uncompressed"))
f.writeframes(data.tostring())
if '--play' in sys.argv:
sp.Popen(['aplay', 'Sound_%s.wav' % uid]).wait()
import math
import sys
import wave
import array
import subprocess as sp
from collections import namedtuple
import base64
import hashlib
# Usage: soundgen.py seconds,freq,amplitude [...] [--play]
Tone = namedtuple('Tone', 'duration freq amplitude')
tones_raw = [x for x in sys.argv[1:] if x != '--play']
tones = []
for tone_raw in tones_raw:
tones.append(Tone(*[int(x) for x in tone_raw.split(',')]))
data = array.array('h') # signed short integer (-32768 to 32767) data
# -32768 to 32767 is the max amplitude of a sound card
sample_rate = 44100 # samples/second, 44100 = CD Quality Audio
n_channels = 1 # of channels (1 = mono, 2 = stereo)
data_size = 2 # 2 bytes because of using signed short integers => bit depth = 16
for tone in tones:
n_samples_per_cycle = int(sample_rate / tone.freq)
n_samples = sample_rate * tone.duration
for i in range(n_samples):
sample = 32767 * float(tone.amplitude) / 100
sample *= math.sin(math.pi * 2 * (i % n_samples_per_cycle) / n_samples_per_cycle)
data.append(int(sample))
uid = hashlib.md5(base64.b64encode(data.tostring())).hexdigest()
with wave.open('Sound_%s.wav' % uid, 'w') as f:
f.setparams((n_channels, data_size, sample_rate, n_samples, "NONE", "Uncompressed"))
f.writeframes(data.tostring())
if '--play' in sys.argv:
sp.Popen(['aplay', 'Sound_%s.wav' % uid]).wait()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment