having a None variant in an enum that doesn't expect one, like Color, or here Song, leads to lots of weird, messy and buggy code. you should instead an Option<Song>.
this would for example remove all the panicky code in song.rs.
you could then make
impl TryFrom<[NoteButton; NUM_NOTES]> for Song
or a custom fn that returns an option intead, which would make clear to the caller that not all sequences are valid.
i am not familiar enough with rustysynth or tinyaudio to talk on the rest though
Ahh I considered it, but somehow settled on implementing my own None variant (twice). Looking at it now, it's obvious I should've used the more native Option<Song> and Option<NoteButton>.
also, it feels to me as if you use From too much, instead of specific functions that are named after what they do, like From<NoteButton> for &str.
when to implement From is not super cut and dry, although the From<NoteButton> for &str is one of the example cited in the do for when not to implement From
if self.current_note != new_note {
if let Some(current) = self.current_note {
ocarina_synth.note_off(MIDI_CHANNEL, current.midi_key());
}
if let Some(new) = new_note {
ocarina_synth.note_on(MIDI_CHANNEL, new.midi_key(), MIDI_VELOCITY);
}
}