Skip to content

Commit

Permalink
Move pitch shift and bending utils to separate module
Browse files Browse the repository at this point in the history
  • Loading branch information
rhargreaves committed Jul 26, 2024
1 parent 1ed1410 commit 8081877
Show file tree
Hide file tree
Showing 9 changed files with 148 additions and 58 deletions.
29 changes: 6 additions & 23 deletions src/midi.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "ui_fm.h"
#include "note_priority.h"
#include "scheduler.h"
#include "pitchcents.h"

#define MIN_MIDI_VELOCITY 0
#define RANGE(value, range) (value / (128 / range))
Expand Down Expand Up @@ -333,8 +334,7 @@ static void updatePan(MidiChannel* midiChannel, DeviceChannel* devChan)
static void updatePitchBend(MidiChannel* midiChannel, DeviceChannel* devChan)
{
if (devChan->pitchBend != midiChannel->pitchBend) {
PitchCents pc
= midi_effectivePitchCents(devChan->pitch, devChan->cents, 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;
}
Expand Down Expand Up @@ -413,7 +413,7 @@ void midi_note_on(u8 chan, u8 pitch, u8 velocity)
devChan->cents = 0;
devChan->pitch = pitch;
updateDeviceChannelFromAssociatedMidiChannel(devChan);
PitchCents pc = midi_effectivePitchCents(devChan->pitch, devChan->cents, devChan->pitchBend);
PitchCents pc = pitchcents_bend(devChan->pitch, devChan->cents, devChan->pitchBend);
devChan->ops->noteOn(devChan->number, pc.pitch, pc.cents, velocity);
}

Expand Down Expand Up @@ -444,7 +444,7 @@ static void devChanNoteOn(DeviceChannel* devChan, u8 pitch, u8 velocity)
devChan->noteOn = true;
devChan->cents = 0;
devChan->pitch = pitch;
PitchCents pc = midi_effectivePitchCents(devChan->pitch, devChan->cents, devChan->pitchBend);
PitchCents pc = pitchcents_bend(devChan->pitch, devChan->cents, devChan->pitchBend);
devChan->ops->noteOn(devChan->number, pc.pitch, pc.cents, velocity);
}

Expand Down Expand Up @@ -940,11 +940,11 @@ static void processChannelGlide(DeviceChannel* chan)
}

PitchCents pc = { .pitch = chan->pitch, .cents = chan->cents };
pc = midi_pitchShift(pc, effectiveIncrement);
pc = pitchcents_shift(pc, effectiveIncrement);
chan->pitch = pc.pitch;
chan->cents = pc.cents;

pc = midi_effectivePitchCents(pc.pitch, pc.cents, chan->pitchBend);
pc = pitchcents_bend(pc.pitch, pc.cents, chan->pitchBend);
chan->ops->pitch(chan->number, pc.pitch, pc.cents);
}

Expand All @@ -965,20 +965,3 @@ void midi_tick(void)
{
processPortamento();
}

PitchCents midi_effectivePitchCents(u8 pitch, s8 cents, u16 pitchBend)
{
s16 centsAdd = ((pitchBend - MIDI_PITCH_BEND_CENTRE) * 25) / 1024;
PitchCents pc = { .pitch = pitch, .cents = cents };
return midi_pitchShift(pc, centsAdd);
}

PitchCents midi_pitchShift(PitchCents pc, s16 centsAdd)
{
u16 totalCents = (pc.pitch * 100) + pc.cents;
totalCents += centsAdd;

pc.pitch = totalCents / 100;
pc.cents = totalCents % 100;
return pc;
}
7 changes: 0 additions & 7 deletions src/midi.h
Original file line number Diff line number Diff line change
Expand Up @@ -143,11 +143,6 @@ typedef struct DeviceChannel {
u16 glideTargetPitch;
} DeviceChannel;

typedef struct PitchCents {
u8 pitch;
s8 cents;
} PitchCents;

void midi_init(const FmChannel** defaultPresets, const PercussionPreset** defaultPercussionPresets,
const u8** defaultEnvelopes);
void midi_note_on(u8 chan, u8 pitch, u8 velocity);
Expand All @@ -161,5 +156,3 @@ DeviceChannel* midi_channel_mappings(void);
void midi_remap_channel(u8 midiChannel, u8 deviceChannel);
void midi_reset(void);
void midi_tick(void);
PitchCents midi_effectivePitchCents(u8 pitch, s8 cents, u16 pitchBend);
PitchCents midi_pitchShift(PitchCents pc, s16 centsAdd);
17 changes: 9 additions & 8 deletions src/midi_psg.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "psg.h"
#include "types.h"
#include "sys.h"
#include "pitchcents.h"

#define MIN_PSG_CHAN 6
#define MAX_PSG_CHAN 9
Expand Down Expand Up @@ -128,16 +129,16 @@ static u16 envelopeTone(MidiPsgChannel* psgChan)
case 0:
break;
case 0x1:
pc = midi_pitchShift(pc, 5);
pc = pitchcents_shift(pc, 5);
break;
case 0x2:
pc = midi_pitchShift(pc, 10);
pc = pitchcents_shift(pc, 10);
break;
case 0x3:
pc = midi_pitchShift(pc, 20);
pc = pitchcents_shift(pc, 20);
break;
case 0x4:
pc = midi_pitchShift(pc, 50);
pc = pitchcents_shift(pc, 50);
break;
case 0x5:
pc.pitch += 1;
Expand All @@ -149,16 +150,16 @@ static u16 envelopeTone(MidiPsgChannel* psgChan)
pc.pitch += 5;
break;
case 0x8:
pc = midi_pitchShift(pc, -5);
pc = pitchcents_shift(pc, -5);
break;
case 0x9:
pc = midi_pitchShift(pc, -10);
pc = pitchcents_shift(pc, -10);
break;
case 0xA:
pc = midi_pitchShift(pc, -20);
pc = pitchcents_shift(pc, -20);
break;
case 0xB:
pc = midi_pitchShift(pc, -50);
pc = pitchcents_shift(pc, -50);
break;
case 0xC:
pc.pitch -= 1;
Expand Down
19 changes: 19 additions & 0 deletions src/pitchcents.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#include "pitchcents.h"
#include "midi.h"

PitchCents pitchcents_bend(u8 pitch, s8 cents, u16 pitchBend)
{
s16 centsAdd = ((pitchBend - MIDI_PITCH_BEND_CENTRE) * 25) / 1024;
PitchCents pc = { .pitch = pitch, .cents = cents };
return pitchcents_shift(pc, centsAdd);
}

PitchCents pitchcents_shift(PitchCents pc, s16 centsAdd)
{
u16 totalCents = (pc.pitch * 100) + pc.cents;
totalCents += centsAdd;

pc.pitch = totalCents / 100;
pc.cents = totalCents % 100;
return pc;
}
10 changes: 10 additions & 0 deletions src/pitchcents.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#pragma once
#include "types.h"

typedef struct PitchCents {
u8 pitch;
s8 cents;
} PitchCents;

PitchCents pitchcents_bend(u8 pitch, s8 cents, u16 pitchBend);
PitchCents pitchcents_shift(PitchCents pc, s16 centsAdd);
22 changes: 12 additions & 10 deletions tests/unit/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "test_buffer.c"
#include "test_note_priority.c"
#include "test_midi_portamento.c"
#include "test_pitchbend.c"

#define midi_test(test) cmocka_unit_test_setup(test, test_midi_setup)
#define midi_pcm_test(test) cmocka_unit_test_setup(test, test_midi_setup)
Expand All @@ -33,6 +34,7 @@
#define buffer_test(test) cmocka_unit_test_setup(test, test_buffer_setup)
#define midi_receiver_test(test) cmocka_unit_test_setup(test, test_midi_receiver_setup)
#define note_priority_test(test) cmocka_unit_test_setup(test, test_note_priority_setup)
#define pitchbend_test(test) cmocka_unit_test(test)

int main(void)
{
Expand Down Expand Up @@ -184,16 +186,16 @@ int main(void)
midi_test(test_midi_hides_fm_parameter_ui),
midi_test(test_midi_resets_fm_values_to_defaults),
midi_test(test_midi_resets_psg_values_to_defaults),
midi_test(test_midi_effectivePitchCents),
midi_test(test_midi_effectivePitchCents_2),
midi_test(test_midi_effectivePitchCents_3),
midi_test(test_midi_effectivePitchCents_4),
midi_test(test_midi_effectivePitchCents_5),
midi_test(test_midi_effectivePitchCents_6),
midi_test(test_midi_effectivePitchCents_cents_with_partial_bend_down),
midi_test(test_midi_effectivePitchCents_high_cents_with_partial_bend_down),
midi_test(test_midi_effectivePitchCents_cents_with_full_bend_up),
midi_test(test_midi_effectivePitchCents_high_cents_with_full_bend_up),
pitchbend_test(test_pitchcents_bend_nil),
pitchbend_test(test_pitchcents_bend_down_fully),
pitchbend_test(test_pitchcents_bend_up_fully),
pitchbend_test(test_pitchcents_bend_up),
pitchbend_test(test_pitchcents_bend_down),
pitchbend_test(test_pitchcents_bend_up_2),
pitchbend_test(test_pitchcents_bend_cents_with_partial_bend_down),
pitchbend_test(test_pitchcents_bend_high_cents_with_partial_bend_down),
pitchbend_test(test_pitchcents_bend_cents_with_full_bend_up),
pitchbend_test(test_pitchcents_bend_high_cents_with_full_bend_up),

midi_pcm_test(test_midi_enables_dac),
midi_pcm_test(test_midi_disables_dac),
Expand Down
1 change: 1 addition & 0 deletions tests/unit/test_midi.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "midi_fm.h"
#include "midi_psg.h"
#include "synth.h"
#include "pitchcents.h"

#define MIDI_PITCH_A2 45
#define MIDI_PITCH_C3 48
Expand Down
20 changes: 10 additions & 10 deletions tests/unit/test_midi_fm.c
Original file line number Diff line number Diff line change
Expand Up @@ -738,79 +738,79 @@ static void test_midi_drops_note_when_note_priority_stack_full(UNUSED void** sta

static void test_midi_effectivePitchCents(UNUSED void** state)
{
PitchCents pc = midi_effectivePitchCents(50, 0, 0x2000);
PitchCents pc = pitchcents_bend(50, 0, 0x2000);

assert_int_equal(pc.pitch, 50);
assert_int_equal(pc.cents, 0);
}

static void test_midi_effectivePitchCents_2(UNUSED void** state)
{
PitchCents pc = midi_effectivePitchCents(50, 0, 0);
PitchCents pc = pitchcents_bend(50, 0, 0);

assert_int_equal(pc.pitch, 48);
assert_int_equal(pc.cents, 0);
}

static void test_midi_effectivePitchCents_3(UNUSED void** state)
{
PitchCents pc = midi_effectivePitchCents(50, 0, 0x4000);
PitchCents pc = pitchcents_bend(50, 0, 0x4000);

assert_int_equal(pc.pitch, 52);
assert_int_equal(pc.cents, 0);
}

static void test_midi_effectivePitchCents_4(UNUSED void** state)
{
PitchCents pc = midi_effectivePitchCents(50, 0, 0x3000);
PitchCents pc = pitchcents_bend(50, 0, 0x3000);

assert_int_equal(pc.pitch, 51);
assert_int_equal(pc.cents, 0);
}

static void test_midi_effectivePitchCents_5(UNUSED void** state)
{
PitchCents pc = midi_effectivePitchCents(50, 0, 0x1800);
PitchCents pc = pitchcents_bend(50, 0, 0x1800);

assert_int_equal(pc.pitch, 49);
assert_int_equal(pc.cents, 50);
}

static void test_midi_effectivePitchCents_6(UNUSED void** state)
{
PitchCents pc = midi_effectivePitchCents(50, 0, 0x2800);
PitchCents pc = pitchcents_bend(50, 0, 0x2800);

assert_int_equal(pc.pitch, 50);
assert_int_equal(pc.cents, 50);
}

static void test_midi_effectivePitchCents_cents_with_partial_bend_down(UNUSED void** state)
{
PitchCents pc = midi_effectivePitchCents(50, 25, 0x1800);
PitchCents pc = pitchcents_bend(50, 25, 0x1800);

assert_int_equal(pc.pitch, 49);
assert_int_equal(pc.cents, 75);
}

static void test_midi_effectivePitchCents_high_cents_with_partial_bend_down(UNUSED void** state)
{
PitchCents pc = midi_effectivePitchCents(50, 80, 0x1800);
PitchCents pc = pitchcents_bend(50, 80, 0x1800);

assert_int_equal(pc.pitch, 50);
assert_int_equal(pc.cents, 30);
}

static void test_midi_effectivePitchCents_cents_with_full_bend_up(UNUSED void** state)
{
PitchCents pc = midi_effectivePitchCents(50, 25, 0x4000);
PitchCents pc = pitchcents_bend(50, 25, 0x4000);

assert_int_equal(pc.pitch, 52);
assert_int_equal(pc.cents, 25);
}

static void test_midi_effectivePitchCents_high_cents_with_full_bend_up(UNUSED void** state)
{
PitchCents pc = midi_effectivePitchCents(50, 80, 0x4000);
PitchCents pc = pitchcents_bend(50, 80, 0x4000);

assert_int_equal(pc.pitch, 52);
assert_int_equal(pc.cents, 80);
Expand Down
81 changes: 81 additions & 0 deletions tests/unit/test_pitchbend.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
#include "test_midi.h"

static void test_pitchcents_bend_nil(UNUSED void** state)
{
PitchCents pc = pitchcents_bend(50, 0, 0x2000);

assert_int_equal(pc.pitch, 50);
assert_int_equal(pc.cents, 0);
}

static void test_pitchcents_bend_down_fully(UNUSED void** state)
{
PitchCents pc = pitchcents_bend(50, 0, 0);

assert_int_equal(pc.pitch, 48);
assert_int_equal(pc.cents, 0);
}

static void test_pitchcents_bend_up_fully(UNUSED void** state)
{
PitchCents pc = pitchcents_bend(50, 0, 0x4000);

assert_int_equal(pc.pitch, 52);
assert_int_equal(pc.cents, 0);
}

static void test_pitchcents_bend_up(UNUSED void** state)
{
PitchCents pc = pitchcents_bend(50, 0, 0x3000);

assert_int_equal(pc.pitch, 51);
assert_int_equal(pc.cents, 0);
}

static void test_pitchcents_bend_down(UNUSED void** state)
{
PitchCents pc = pitchcents_bend(50, 0, 0x1800);

assert_int_equal(pc.pitch, 49);
assert_int_equal(pc.cents, 50);
}

static void test_pitchcents_bend_up_2(UNUSED void** state)
{
PitchCents pc = pitchcents_bend(50, 0, 0x2800);

assert_int_equal(pc.pitch, 50);
assert_int_equal(pc.cents, 50);
}

static void test_pitchcents_bend_cents_with_partial_bend_down(UNUSED void** state)
{
PitchCents pc = pitchcents_bend(50, 25, 0x1800);

assert_int_equal(pc.pitch, 49);
assert_int_equal(pc.cents, 75);
}

static void test_pitchcents_bend_high_cents_with_partial_bend_down(UNUSED void** state)
{
PitchCents pc = pitchcents_bend(50, 80, 0x1800);

assert_int_equal(pc.pitch, 50);
assert_int_equal(pc.cents, 30);
}

static void test_pitchcents_bend_cents_with_full_bend_up(UNUSED void** state)
{
PitchCents pc = pitchcents_bend(50, 25, 0x4000);

assert_int_equal(pc.pitch, 52);
assert_int_equal(pc.cents, 25);
}

static void test_pitchcents_bend_high_cents_with_full_bend_up(UNUSED void** state)
{
PitchCents pc = pitchcents_bend(50, 80, 0x4000);

assert_int_equal(pc.pitch, 52);
assert_int_equal(pc.cents, 80);
}

0 comments on commit 8081877

Please sign in to comment.