From 702e56817de00fc656e6cf9a632531b3dca96207 Mon Sep 17 00:00:00 2001 From: Robert Hargreaves Date: Sat, 27 Jul 2024 22:06:32 +0100 Subject: [PATCH] Apply fine tune parameter with bend/glide --- src/midi.c | 29 +++++++++++++++++++---------- tests/unit/main.c | 4 +++- tests/unit/test_midi_finetune.c | 16 ++++++++++++++++ tests/unit/test_midi_portamento.c | 16 ++++++++++++++++ 4 files changed, 54 insertions(+), 11 deletions(-) diff --git a/src/midi.c b/src/midi.c index 30ce756..07a982e 100644 --- a/src/midi.c +++ b/src/midi.c @@ -91,6 +91,7 @@ static void reset(void); static void init(void); static void devChanNoteOn(DeviceChannel* devChan, u8 pitch, u8 velocity); static void devChanNoteOff(DeviceChannel* devChan, u8 pitch); +static void setDownstreamPitch(DeviceChannel* devChan, MidiChannel* midiChannel); void midi_init( const FmChannel** presets, const PercussionPreset** percussionPresets, const u8** envelopes) @@ -347,9 +348,8 @@ static void updatePan(MidiChannel* midiChannel, DeviceChannel* devChan) static void updatePitchBend(MidiChannel* midiChannel, DeviceChannel* devChan) { if (devChan->pitchBend != midiChannel->pitchBend) { - PitchCents pc = pitchcents_bend(devChan->pitch, devChan->cents, midiChannel->pitchBend); - devChan->ops->pitch(devChan->number, pc.pitch, pc.cents); devChan->pitchBend = midiChannel->pitchBend; + setDownstreamPitch(devChan, midiChannel); } } @@ -390,6 +390,20 @@ static DeviceChannel* findSuitableDeviceChannel(u8 midiChan) return dynamicMode ? findFreeChannel(midiChan) : deviceChannelByMidiChannel(midiChan); } +static void setDownstreamPitch(DeviceChannel* devChan, MidiChannel* midiChannel) +{ + PitchCents pc = pitchcents_bend(devChan->pitch, devChan->cents, devChan->pitchBend); + pc = pitchcents_shift(pc, midiChannel->fineTune); + devChan->ops->pitch(devChan->number, pc.pitch, pc.cents); +} + +static void setDownstreamNoteOn(DeviceChannel* devChan, u8 velocity) +{ + PitchCents pc = pitchcents_bend(devChan->pitch, devChan->cents, devChan->pitchBend); + pc = pitchcents_shift(pc, midiChannels[devChan->midiChannel].fineTune); + devChan->ops->noteOn(devChan->number, pc.pitch, pc.cents, velocity); +} + void midi_note_on(u8 chan, u8 pitch, u8 velocity) { if (velocity == MIN_MIDI_VELOCITY) { @@ -426,9 +440,7 @@ void midi_note_on(u8 chan, u8 pitch, u8 velocity) devChan->cents = 0; devChan->pitch = pitch; updateDeviceChannelFromAssociatedMidiChannel(devChan); - PitchCents pc = pitchcents_bend(devChan->pitch, devChan->cents, devChan->pitchBend); - pc = pitchcents_shift(pc, midiChannel->fineTune); - devChan->ops->noteOn(devChan->number, pc.pitch, pc.cents, velocity); + setDownstreamNoteOn(devChan, velocity); } void midi_note_off(u8 chan, u8 pitch) @@ -458,8 +470,7 @@ static void devChanNoteOn(DeviceChannel* devChan, u8 pitch, u8 velocity) devChan->noteOn = true; devChan->cents = 0; devChan->pitch = pitch; - PitchCents pc = pitchcents_bend(devChan->pitch, devChan->cents, devChan->pitchBend); - devChan->ops->noteOn(devChan->number, pc.pitch, pc.cents, velocity); + setDownstreamNoteOn(devChan, velocity); } static void devChanNoteOff(DeviceChannel* devChan, u8 pitch) @@ -984,9 +995,7 @@ static void processChannelGlide(DeviceChannel* chan, u16 portamentoTime) chan->pitch = pc.pitch; chan->cents = pc.cents; - - pc = pitchcents_bend(pc.pitch, pc.cents, chan->pitchBend); - chan->ops->pitch(chan->number, pc.pitch, pc.cents); + setDownstreamPitch(chan, &midiChannels[chan->midiChannel]); } static void processPortamento(void) diff --git a/tests/unit/main.c b/tests/unit/main.c index a128edb..54c34a0 100644 --- a/tests/unit/main.c +++ b/tests/unit/main.c @@ -402,9 +402,11 @@ int main(void) midi_portamento_test(test_midi_portamento_sets_portamento_time_to_minimum), midi_portamento_test(test_midi_portamento_sets_portamento_time_to_maximum), midi_portamento_test(test_midi_portamento_default_portamento_time_set), + midi_portamento_test(test_midi_portamento_glides_with_fine_tune), midi_finetune_test(test_midi_finetune_max), - midi_finetune_test(test_midi_finetune_min) + midi_finetune_test(test_midi_finetune_min), + midi_finetune_test(test_midi_finetune_with_pitchbend), // clang-format on }; diff --git a/tests/unit/test_midi_finetune.c b/tests/unit/test_midi_finetune.c index 0ba2ec2..82b8cff 100644 --- a/tests/unit/test_midi_finetune.c +++ b/tests/unit/test_midi_finetune.c @@ -25,3 +25,19 @@ static void test_midi_finetune_min(UNUSED void** state) __real_midi_note_on(chan, MIDI_PITCH_A2, MAX_MIDI_VOLUME); } } + +static void test_midi_finetune_with_pitchbend(UNUSED void** state) +{ + for (u8 chan = 0; chan < MAX_FM_CHANS; chan++) { + debug_message("channel %d\n", chan); + __real_midi_cc(chan, CC_FINE_TUNE, 0); + + expect_synth_pitch(chan, 2, 0x492); + __real_midi_pitch_bend(chan, MIDI_PITCH_BEND_MAX); + + expect_synth_pitch(chan, 2, 0x492); + expect_synth_volume_any(); + expect_synth_noteOn(chan); + __real_midi_note_on(chan, MIDI_PITCH_A2, MAX_MIDI_VOLUME); + } +} diff --git a/tests/unit/test_midi_portamento.c b/tests/unit/test_midi_portamento.c index 75b6be2..b41727d 100644 --- a/tests/unit/test_midi_portamento.c +++ b/tests/unit/test_midi_portamento.c @@ -442,3 +442,19 @@ static void test_midi_portamento_default_portamento_time_set(UNUSED void** state expect_synth_pitch(chan, 2, 0x457); midi_tick(); } + +static void test_midi_portamento_glides_with_fine_tune(UNUSED void** state) +{ + const u8 chan = 0; + __real_midi_cc(chan, CC_PORTAMENTO_ENABLE, 127); + __real_midi_cc(chan, CC_FINE_TUNE, 127); + + expect_synth_pitch(chan, 2, 0x461); + expect_synth_volume_any(); + expect_synth_noteOn(chan); + __real_midi_note_on(chan, MIDI_PITCH_A2, MAX_MIDI_VOLUME); + __real_midi_note_on(chan, MIDI_PITCH_C4, MAX_MIDI_VOLUME); + + expect_synth_pitch(chan, 2, 0x468); + midi_tick(); +}