String and other sounds can be creating by repeating a random signal while filtering out the high frequency components.
In the note function, we take average of two nearby samples, which is a simple low-pass filter.
Below we have 2 programs. The only function of the first program is to define a dictionary Hz. You can see Dictionary Example. Here I go over the frequency dictionary in more detail.
In the second program, which imports the dictionary, we iterate over the elements of notes list. The duration is the fraction of a second for that particular note. Thus the first two notes are C4 played for 0.25 seconds each.
Notes = ['C','C#','D','D#','E','F','F#','G','G#','A','A#','B']
for i in range(88):
Octave = (i+9)/12
Pos = (i+9)%12
S = Notes[Pos]+str(Octave)
Hz[S] = 27.5*(2**(i/12.0))
from __future__ import division
import numpy as np
from scipy.io import wavfile
from Hz import Hz
SR = 44100
notes = [('C4', 4), ('C4', 4), ('C4', 3), ('D4', 6),
('E4', 4), ('E4', 3), ('D4', 6), ('E4', 3),
('F4', 6), ('G4', 2), ('C5', 6), ('C5', 6),
('C5', 6), ('G4', 6), ('G4', 6), ('G4', 6),
('E4', 6), ('E4', 6), ('E4', 6), ('C4', 6),
('C4', 6), ('C4', 6), ('G4', 3), ('F4', 6),
('E4', 3), ('D4', 6), ('C4', 2)]
for i in range(num):
buf = np.append(buf[1:],avg)
return np.array([x*max_pos for x in samples])
if __name__ == '__main__':
for i in range(len(notes)):
buff = note(Hz[notes[i]],SR//notes[i])
out = np.concatenate((out,buff))
fade_dist = 5000
x = np.arange(fade_dist-1,-1,-1)
fade_out = (1-np.exp(-x/fade_dist))/(1-np.exp(-1))
out[-fade_dist:] *= fade_out