Source code for scitools.sound

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)