import numpy as np def synthesize_note_dynamics(note_on, duration, amplitude, sr=22050): v = np.zeros(round((duration + note_on + 1.0) * sr)) for itr in range(len(v)): t = itr / sr if t >= note_on and t < note_on + 1.25: amp_attack = np.cos(((t - note_on) / 1.25) * (np.pi / 2.0)) * 0.4 + 0.6 else: amp_attack = 0.0 if t > note_on + 1.25: amp_decay = 0.6 + (np.exp(-(t - (note_on + 1.25)) / (duration - 1.25)) - 1.0) * 0.175 else: amp_decay = 0.0 if t >= note_on - 0.015 and t < note_on + 0.005: amp_spike1 = (1.0 - abs((t - (note_on - 0.005)) / 0.01)) / 4.0 else: amp_spike1 = 0.0 # Note: There is also a fade of about 33% that occurs near the end that lasts about 100ms. # The rest of the fade is handled by an articulation from phoneme to silence. # The fade is not modeled here since its time depends on the length of that articulation. v[itr] = (amp_spike1 + amp_attack + amp_decay) * amplitude return v # In cents/log-scale # XXX: Special case for very large legato, >1 ocatve def synthesize_legato(start_time, duration, start_pitch, end_pitch, sr=22050): v = np.zeros(round((duration + start_time + 1.0) * sr)) for itr in range(len(v)): t = itr / sr if t >= start_time and t < start_time + duration: if end_pitch >= start_pitch: v[itr] = start_pitch + (end_pitch - start_pitch) * (((t - start_time) / duration) ** 0.8) else: v[itr] = end_pitch + (start_pitch - end_pitch) * ((1.0 - (t - start_time) / duration) ** 1.5) elif t < start_time: v[itr] = start_pitch else: v[itr] = end_pitch return v