def sounds_to_key_and_stream(sounds): key = set() stream = Stream() for sound in sounds: stream.add_sound(sound) key.add( KeySound( frequency=sound.frequency, duration=sound.duration, volume=sound.volume, ) ) return frozenset(key), stream
twinkle_twinkle_little_star = Stream() current_time = 0 for phrase in twinkle_twinkle_little_star_notes: for note, timing in zip( phrase.split(" "), tinkle_twinkle_little_star_timings ): duration = note_length * timing twinkle_twinkle_little_star.add_sound( Tone( start=current_time, duration=duration, frequency=scientific_note_frequency(note), overtones=[], volume=0.4, attack_seconds=0.1, decay_seconds=0.1, sustain_level=0.75, release_seconds=0.2, ) ) current_time += duration def fuzzy_start(sounds): for sound in sounds: yield sound.delayed( random.uniform(-note_length / 32.0, note_length / 32.0) )
def build_stream_from_midi(filename): mid = mido.MidiFile(filename) merged_tracks = mido.merge_tracks(mid.tracks) bpm = None current_time = 0 active_notes = { channel: defaultdict(list) for channel in set( msg.channel for msg in merged_tracks if "channel" in msg.dict()) } stream = Stream() for msg in merged_tracks: if msg.type == "note_on" and msg.velocity == 0: # turn a zero velocity note on into an equivalent note off data = msg.dict() data["type"] = "note_off" msg = msg.from_dict(data) if bpm is not None: current_time += msg.time / mid.ticks_per_beat / bpm * 60 if msg.type == "set_tempo": bpm = mido.tempo2bpm(msg.tempo) elif msg.type == "note_on": if bpm is None: raise Exception(f"no tempo found before the first note") active_notes[msg.channel][msg.note].append( (current_time, msg.velocity)) elif msg.type == "note_off": if not active_notes[msg.channel][msg.note]: raise Exception( f"notes: {active_notes}, disabling note: {msg}") if current_time is None: raise Exception(f"no tempo found before the first note") if msg.velocity != 0: raise Exception( f"do not konw how to work with non-zero note_off velocity: {msg}" ) started, initial_velocity = active_notes[msg.channel][ msg.note].pop() if msg.channel == 2: continue duration = current_time - started if duration > 5: raise Exception(f"would have created a very long note: {msg}") stream.add_sound( Tone( start=started, duration=duration, frequency=midi_note_frequency(msg.note), overtones=[ Overtone(2, 0.5 * pi, 0.5), Overtone(3, 0, 0.3), Overtone(4, 0.25 * pi, 0.2), Overtone(5, 0, 0.2), ], volume=0.4 * initial_velocity / 127, attack_seconds=0.1, decay_seconds=0.1, sustain_level=0.75, release_seconds=0.1, )) elif msg.type in ( "time_signature", "key_signature", "program_change", "control_change", "track_name", "smpte_offset", "midi_port", "end_of_track", ): continue else: raise Exception(f"unkown message: {msg}") return stream