shorepine / amy

AMY - A high-performance fixed-point Music synthesizer librarY for microcontrollers
https://shorepine.github.io/amy/
MIT License
221 stars 14 forks source link

Playing a PCM patch changes oscillator's freq #207

Open dpwe opened 2 months ago

dpwe commented 2 months ago

Currently, pcm patch playback changes the frequency of the osc. It shouldn't do that.

Example:

amy.reset()
amy.send(osc=0, wave=amy.PCM, patch=2, vel=1)  # Plays 808 Snare as expected.
amy.reset()
amy.send(osc=0, wave=amy.PCM, patch=0, vel=1)  # Plays 808 Maracas as expected.
amy.send(osc=0, wave=amy.PCM, patch=2, vel=1)  # We expected the same snare as above, but it's massively slowed down

Somehow, after playing the Maracas, the log_freq_coef[COEF_CONST] becomes 3.98 (so 4 octaves above middle C), but the snare wants it to be 7.647, so the sound is pitched down by the difference (3.6 octaves).

dpwe commented 2 months ago

I have an idea for how to fix this, which I think also improves the rationality of the whole thing.

Right now, we squirm a little in the tutorial when we say you can set the frequency of an osc with freq= or with note= -- a new user asks, why have both?

I think a nice rationale is that note is purely associated with a given note, i.e. a single vel=1 to vel=0 timespan, after which it is invalid. Currently, midi_note is a property of the osc's synth structure. If you set it for one note, then later send another note-on to the same osc without specifying a note, it will re-use the midi_note from the last note-on.

This is what messes up the PCM voices, which default to different notes depending on the "natural" note of the PCM patch (at least, that's what I think is going on).

Instead, once midi_note has been set, then "consumed" by a note-on/note-off pair, it should be marked invalid. Then if it is explicitly set, it is marked as valid. Then, on a note-on, if the midi_note is not valid, it is cleared before the note is launched. That way, PCM oscs can avoid inheriting the irrelevant default midi_note of their predecessors when the patch in use is changed as in DrumSynth.