import math, numpy, wave, commands, sys, os
max_amplitude = 2**15-1 # iinfo('int16').max if numpy >= 1.0.3
[docs]def write(data, filename, channels=1, sample_width=2, sample_rate=44100):
"""
Writes the array data to the specified file.
The array data type can be arbitrary as it will be
converted to numpy.int16 in this function.
"""
ofile = wave.open(filename, 'w')
ofile.setnchannels(channels)
ofile.setsampwidth(sample_width)
ofile.setframerate(sample_rate)
ofile.writeframesraw(data.astype(numpy.int16).tostring())
ofile.close()
[docs]def read(filename):
"""
Read sound data in a file and return the data as an array
with data type numpy.int16.
"""
ifile = wave.open(filename)
channels = ifile.getnchannels()
sample_width = ifile.getsampwidth()
sample_rate = ifile.getframerate()
frames = ifile.getnframes()
data = ifile.readframes(frames)
data = numpy.fromstring(data, dtype=numpy.uint16)
return data.astype(numpy.int16)
[docs]def play(soundfile, player=None):
"""
Play a file with name soundfile or an array soundfile.
(The array is first written to file using the write function
so the data type can be arbitrary.)
The player is chosen by the programs 'open' on Mac and 'start'
on Windows. On Linux, try different open programs for various
distributions. If keyword argument 'player' is given, only this spesific
commands is run.
"""
tmpfile = 'tmp.wav'
if isinstance(soundfile, numpy.ndarray):
write(soundfile, tmpfile)
elif isinstance(soundfile, str):
tmpfile = soundfile
if player:
msg = 'Unable to open sound file with %s' %player
if sys.platform[:3] == 'win':
status = os.system('%s %s' %(player, tmpfile))
else:
status, output = commands.getstatusoutput('%s %s' %(player, tmpfile))
msg += '\nError message:\n%s' %output
if status != 0:
raise OSError(msg)
return
if sys.platform[:5] == 'linux':
open_commands = ['gnome-open', 'kmfclient exec', 'exo-open', 'xdg-open', 'open']
for cmd in open_commands:
status, output = commands.getstatusoutput('%s %s' %(cmd, tmpfile))
if status == 0:
break
if status != 0:
raise OSError('Unable to open sound file, try to set player'\
' keyword argument.')
elif sys.platform == 'darwin':
commands.getstatusoutput('open %s' %tmpfile)
else:
# assume windows
os.system('start %s' %tmpfile)
[docs]def note(frequency, length, amplitude=1, sample_rate=44100):
"""
Generate the sound of a note as an array if float elements.
"""
time_points = numpy.linspace(0, length, length*sample_rate)
data = numpy.sin(2*numpy.pi*frequency*time_points)
data = amplitude*data
return data
[docs]def add_echo(data, beta=0.8, delay=0.1, sample_rate=44100):
newdata = data.copy()
shift = int(delay*sample_rate) # b (math symbol)
newdata[shift:] = beta*data[shift:] + \
(1-beta)*data[:len(data)-shift]
#for i in xrange(shift, len(data)):
# newdata[i] = beta*data[i] + (1-beta)*data[i-shift]
return newdata
def _test1():
filename = 'tmp.wav'
tone1 = max_amplitude*note(440, 1, 0.2)
tone2 = max_amplitude*note(293.66, 1, 1)
tone3 = max_amplitude*note(440, 1, 0.8)
data = numpy.concatenate((tone1, tone2, tone3))
write(data, filename)
data = read(filename)
play(filename)
[docs]def Nothing_Else_Matters(echo=False):
E1 = note(164.81, .5)
G = note(392, .5)
B = note(493.88, .5)
E2 = note(659.26, .5)
intro = numpy.concatenate((E1, G, B, E2, B, G))
high1_long = note(987.77, 1)
high1_short = note(987.77, .5)
high2 = note(1046.50, .5)
high3 = note(880, .5)
high4_long = note(659.26, 1)
high4_medium = note(659.26, .5)
high4_short = note(659.26, .25)
high5 = note(739.99, .25)
pause_long = note(0, .5)
pause_short = note(0, .25)
song = numpy.concatenate(
(intro, intro, high1_long, pause_long, high1_long,
pause_long, pause_long,
high1_short, high2, high1_short, high3, high1_short,
high3, high4_short, pause_short, high4_long, pause_short,
high4_medium, high5, high4_short))
song *= max_amplitude
if echo:
song = add_echo(song, 0.6)
return song
# equal-tempered scale:
note2freq = {
'A#0': 29.14,
'A#1': 58.27,
'A#2': 116.54,
'A#3': 233.08,
'A#4': 466.16,
'A#5': 932.33,
'A#6': 1864.66,
'A#7': 3729.31,
'A0': 27.5,
'A1': 55,
'A2': 110,
'A3': 220,
'A4': 440,
'A5': 880,
'A6': 1760,
'A7': 3520,
'Ab0': 25.96,
'Ab1': 51.91,
'Ab2': 103.83,
'Ab3': 207.65,
'Ab4': 415.3,
'Ab5': 830.61,
'Ab6': 1661.22,
'Ab7': 3322.44,
'B0': 30.87,
'B1': 61.74,
'B2': 123.47,
'B3': 246.94,
'B4': 493.88,
'B5': 987.77,
'B6': 1975.53,
'B7': 3951.07,
'Bb0': 29.14,
'Bb1': 58.27,
'Bb2': 116.54,
'Bb3': 233.08,
'Bb4': 466.16,
'Bb5': 932.33,
'Bb6': 1864.66,
'Bb7': 3729.31,
'C#0': 17.32,
'C#1': 34.65,
'C#2': 69.3,
'C#3': 138.59,
'C#4': 277.18,
'C#5': 554.37,
'C#6': 1108.73,
'C#7': 2217.46,
'C#8': 4434.92,
'C1': 32.7,
'C2': 65.41,
'C3': 130.81,
'C4': 261.63,
'C5': 523.25,
'C6': 1046.5,
'C7': 2093,
'C8': 4186.01,
'D#0': 19.45,
'D#1': 38.89,
'D#2': 77.78,
'D#3': 155.56,
'D#4': 311.13,
'D#5': 622.25,
'D#6': 1244.51,
'D#7': 2489.02,
'D#8': 4978.03,
'D0': 18.35,
'D1': 36.71,
'D2': 73.42,
'D3': 146.83,
'D4': 293.66,
'D5': 587.33,
'D6': 1174.66,
'D7': 2349.32,
'D8': 4698.64,
'Db0': 17.32,
'Db1': 34.65,
'Db2': 69.3,
'Db3': 138.59,
'Db4': 277.18,
'Db5': 554.37,
'Db6': 1108.73,
'Db7': 2217.46,
'Db8': 4434.92,
'E0': 20.6,
'E1': 41.2,
'E2': 82.41,
'E3': 164.81,
'E4': 329.63,
'E5': 659.26,
'E6': 1318.51,
'E7': 2637.02,
'Eb0': 19.45,
'Eb1': 38.89,
'Eb2': 77.78,
'Eb3': 155.56,
'Eb4': 311.13,
'Eb5': 622.25,
'Eb6': 1244.51,
'Eb7': 2489.02,
'Eb8': 4978.03,
'F#0': 23.12,
'F#1': 46.25,
'F#2': 92.5,
'F#3': 185,
'F#4': 369.99,
'F#5': 739.99,
'F#6': 1479.98,
'F#7': 2959.96,
'F0': 21.83,
'F1': 43.65,
'F2': 87.31,
'F3': 174.61,
'F4': 349.23,
'F5': 698.46,
'F6': 1396.91,
'F7': 2793.83,
'G#0': 25.96,
'G#1': 51.91,
'G#2': 103.83,
'G#3': 207.65,
'G#4': 415.3,
'G#5': 830.61,
'G#6': 1661.22,
'G#7': 3322.44,
'G0': 24.5,
'G1': 49,
'G2': 98,
'G3': 196,
'G4': 392,
'G5': 783.99,
'G6': 1567.98,
'G7': 3135.96,
'Gb0': 23.12,
'Gb1': 46.25,
'Gb2': 92.5,
'Gb3': 185,
'Gb4': 369.99,
'Gb5': 739.99,
'Gb6': 1479.98,
'Gb7': 2959.96}
if __name__ == '__main__':
#_test1()
song = Nothing_Else_Matters(False)
play(song)