Skip to content

Commit

Permalink
Set pitch for first Ch 3 special mode operator using MIDI channel 11.
Browse files Browse the repository at this point in the history
  • Loading branch information
rhargreaves committed Jun 24, 2024
1 parent ec02e46 commit 34dec7f
Show file tree
Hide file tree
Showing 13 changed files with 143 additions and 5 deletions.
20 changes: 17 additions & 3 deletions src/midi.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "memory.h"
#include "midi_fm.h"
#include "midi_psg.h"
#include "midi_fm_sm.h"
#include "midi_sender.h"
#include "synth.h"
#include "ui_fm.h"
Expand Down Expand Up @@ -43,6 +44,10 @@ static const VTable FM_VTable = { midi_fm_note_on, midi_fm_note_off,
midi_fm_channel_volume, midi_fm_pitch_bend, midi_fm_program,
midi_fm_all_notes_off, midi_fm_pan };

static const VTable SpecialMode_VTable = { midi_fm_sm_note_on, midi_fm_sm_note_off,
midi_fm_sm_channel_volume, midi_fm_sm_pitch_bend, midi_fm_sm_program,
midi_fm_sm_all_notes_off, midi_fm_sm_pan };

static MappingMode mappingModePref;
static MidiChannel midiChannels[MIDI_CHANNELS];
static bool dynamicMode;
Expand Down Expand Up @@ -74,9 +79,18 @@ static void initMidiChannel(u8 midiChan)
static void initDeviceChannel(u8 devChan)
{
DeviceChannel* chan = &deviceChannels[devChan];
bool isFm = devChan < DEV_CHAN_MIN_PSG;
chan->number = isFm ? devChan : devChan - DEV_CHAN_MIN_PSG;
chan->ops = isFm ? &FM_VTable : &PSG_VTable;

if(devChan <= DEV_CHAN_MAX_FM) {
chan->number = devChan;
chan->ops = &FM_VTable;
} else if(devChan <= DEV_CHAN_MAX_PSG) {
chan->number = devChan - DEV_CHAN_MIN_PSG;
chan->ops = &PSG_VTable;
} else {
chan->number = devChan - DEV_CHAN_MIN_SPECIAL_MODE;
chan->ops = &SpecialMode_VTable;
}

chan->noteOn = false;
chan->midiChannel = devChan;
chan->pitch = 0;
Expand Down
4 changes: 3 additions & 1 deletion src/midi.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,15 @@
#define PSG_NOISE_CHAN 3
#define GENERAL_MIDI_PERCUSSION_CHANNEL 9

#define DEV_CHANS 10
#define DEV_CHANS 11
#define DEV_CHAN_MIN_FM 0
#define DEV_CHAN_MAX_FM 5
#define DEV_CHAN_MIN_PSG 6
#define DEV_CHAN_MAX_TONE_PSG 8
#define DEV_CHAN_PSG_NOISE 9
#define DEV_CHAN_MAX_PSG 9
#define DEV_CHAN_MIN_SPECIAL_MODE 11
#define DEV_CHAN_MAX_SPECIAL_MODE 11

#define CC_DATA_ENTRY_MSB 6
#define CC_VOLUME 7
Expand Down
49 changes: 49 additions & 0 deletions src/midi_fm_sm.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#include "midi_fm_sm.h"
#include "midi_fm.h"

static const u8 SEMITONES = 12;
static const u16 FREQS[] = {
607, // B
644, 681, 722, 765, 810, 858, 910, 964, 1021, 1081,
1146 // A#
};

static u8 octave(u8 pitch)
{
return (pitch - MIN_MIDI_PITCH) / SEMITONES;
}

static u16 freqNumber(u8 pitch)
{
return FREQS[((u8)(pitch - MIN_MIDI_PITCH)) % SEMITONES];
}

void midi_fm_sm_note_on(u8 chan, u8 pitch, u8 velocity)
{
synth_specialModePitch(0, octave(pitch), freqNumber(pitch));
}

void midi_fm_sm_pitch_bend(u8 chan, u16 bend)
{
}

// no-ops
void midi_fm_sm_note_off(u8 chan, u8 pitch)
{
}

void midi_fm_sm_channel_volume(u8 chan, u8 volume)
{
}

void midi_fm_sm_pan(u8 chan, u8 pan)
{
}

void midi_fm_sm_program(u8 chan, u8 program)
{
}

void midi_fm_sm_all_notes_off(u8 chan)
{
}
14 changes: 14 additions & 0 deletions src/midi_fm_sm.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#pragma once
#include "synth.h"
#include <stdbool.h>
#include <types.h>

void midi_fm_sm_note_on(u8 chan, u8 pitch, u8 velocity);
void midi_fm_sm_pitch_bend(u8 chan, u16 bend);

// no-ops
void midi_fm_sm_note_off(u8 chan, u8 pitch);
void midi_fm_sm_channel_volume(u8 chan, u8 volume);
void midi_fm_sm_pan(u8 chan, u8 pan);
void midi_fm_sm_program(u8 chan, u8 program);
void midi_fm_sm_all_notes_off(u8 chan);
6 changes: 6 additions & 0 deletions src/synth.c
Original file line number Diff line number Diff line change
Expand Up @@ -424,3 +424,9 @@ void synth_setCh3SpecialMode(bool enable)
global.ch3SpecialMode = enable;
writeSpecialModeReg();
}

void synth_specialModePitch(u8 op, u8 octave, u16 freqNumber)
{
YM2612_writeReg(0, 0xAC, (freqNumber >> 8) | (octave << 3));
YM2612_writeReg(0, 0xA8, freqNumber);
}
1 change: 1 addition & 0 deletions src/synth.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,4 @@ const FmChannel* synth_channelParameters(u8 channel);
const Global* synth_globalParameters();
void synth_setParameterUpdateCallback(ParameterUpdatedCallback* cb);
void synth_setCh3SpecialMode(bool enable);
void synth_specialModePitch(u8 op, u8 octave, u16 freqNumber);
1 change: 1 addition & 0 deletions tests/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ MOCKS=midi_process \
synth_channelParameters \
synth_globalParameters \
synth_setCh3SpecialMode \
synth_specialModePitch \
fm_writeReg \
midi_note_off \
midi_note_on \
Expand Down
3 changes: 2 additions & 1 deletion tests/system/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ int main(void)
e2e_test(test_set_device_for_midi_channel_1_to_psg),
e2e_test(test_pong_received_after_ping_sent),
e2e_test(test_loads_psg_envelope),
e2e_test(test_enables_ch3_special_mode)
e2e_test(test_enables_ch3_special_mode),
e2e_test(test_sets_separate_ch3_operator_frequencies)
// clang-format on
};

Expand Down
29 changes: 29 additions & 0 deletions tests/system/test_e2e.c
Original file line number Diff line number Diff line change
Expand Up @@ -290,3 +290,32 @@ static void test_enables_ch3_special_mode(void** state)

midi_receiver_read();
}

static void test_sets_separate_ch3_operator_frequencies(void** state)
{
const u8 status = 0xB0;
const u8 specialModeCC = 80;
const u8 specialModeEnable = 64;

stub_usb_receive_byte(status);
stub_usb_receive_byte(specialModeCC);
stub_usb_receive_byte(specialModeEnable);

expect_ym2612_write_reg(0, 0x27, 0x40);

midi_receiver_read();

const u8 op2MidiChannel = 10;
const u8 noteOnStatus = 0x90 + op2MidiChannel;
const u8 noteOnKey = 60;
const u8 noteOnVelocity = 127;

stub_usb_receive_byte(noteOnStatus);
stub_usb_receive_byte(noteOnKey);
stub_usb_receive_byte(noteOnVelocity);

expect_ym2612_write_channel(0, 0xAC, 0x22);
expect_ym2612_write_channel(0, 0xA8, 0x84);

midi_receiver_read();
}
1 change: 1 addition & 0 deletions tests/unit/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ int main(void)
midi_test(test_midi_switching_program_retains_pan_setting),
midi_test(test_midi_enables_fm_special_mode),
midi_test(test_midi_disables_fm_special_mode),
midi_test(test_midi_sets_pitch_of_special_mode_ch3_operator),

midi_test(test_midi_sets_genmdm_stereo_mode),
midi_test(test_midi_sysex_enables_dynamic_channel_mode),
Expand Down
12 changes: 12 additions & 0 deletions tests/unit/test_midi_fm.c
Original file line number Diff line number Diff line change
Expand Up @@ -530,3 +530,15 @@ static void test_midi_disables_fm_special_mode(UNUSED void** state)

__real_midi_cc(0, expectedController, expectedValue);
}

static void test_midi_sets_pitch_of_special_mode_ch3_operator(
UNUSED void** state)
{
int chan = 10;

expect_value(__wrap_synth_specialModePitch, op, 0);
expect_value(__wrap_synth_specialModePitch, octave, 4);
expect_value(__wrap_synth_specialModePitch, freqNumber, SYNTH_NTSC_C);

__real_midi_note_on(chan, MIDI_PITCH_C4, MAX_MIDI_VOLUME);
}
7 changes: 7 additions & 0 deletions tests/wraps.c
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,13 @@ void __wrap_synth_setCh3SpecialMode(bool enable)
check_expected(enable);
}

void __wrap_synth_specialModePitch(u8 op, u8 octave, u16 freqNumber)
{
check_expected(op);
check_expected(octave);
check_expected(freqNumber);
}

void __wrap_comm_write(u8 data)
{
check_expected(data);
Expand Down
1 change: 1 addition & 0 deletions tests/wraps.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ void __wrap_synth_volume(u8 channel, u8 volume);
const FmChannel* __wrap_synth_channelParameters(u8 channel);
const Global* __wrap_synth_globalParameters();
void __wrap_synth_setCh3SpecialMode(bool enable);
void __wrap_synth_specialModePitch(u8 op, u8 octave, u16 freqNumber);

bool __wrap_comm_read_ready(void);
u8 __wrap_comm_read(void);
Expand Down

0 comments on commit 34dec7f

Please sign in to comment.