diff --git a/bank.h b/bank.h index 28d0361..fe01280 100644 --- a/bank.h +++ b/bank.h @@ -2,7 +2,8 @@ #include "base.h" typedef enum { - Oevent_type_midi, + Oevent_type_midi_note, + Oevent_type_midi_cc, Oevent_type_osc_ints, Oevent_type_udp_string, } Oevent_types; @@ -14,7 +15,12 @@ typedef struct { typedef struct { U8 oevent_type; U8 channel, octave, note, velocity, duration; -} Oevent_midi; +} Oevent_midi_note; + +typedef struct { + U8 oevent_type; + U8 channel, control, value; +} Oevent_midi_cc; enum { Oevent_osc_int_count = 16 }; @@ -35,7 +41,8 @@ typedef struct { typedef union { Oevent_any any; - Oevent_midi midi; + Oevent_midi_note midi_note; + Oevent_midi_cc midi_cc; Oevent_osc_ints osc_ints; Oevent_udp_string udp_string; } Oevent; diff --git a/sim.c b/sim.c index 8478600..a46b0e3 100644 --- a/sim.c +++ b/sim.c @@ -262,7 +262,26 @@ BEGIN_OPERATOR(movement) END_OPERATOR BEGIN_OPERATOR(midicc) - // TODO unimplemented + for (Usz i = 1; i < 4; ++i) { + PORT(0, (Isz)i, IN); + } + STOP_IF_NOT_BANGED; + Glyph channel_g = PEEK(0, 1); + Glyph control_g = PEEK(0, 2); + Glyph value_g = PEEK(0, 3); + if (channel_g == '.' || control_g == '.') + return; + Usz channel = index_of(channel_g); + if (channel > 15) + return; + Usz control = index_of(control_g); + Usz value = safe_index_of(value_g) * 127 / 35; + Oevent_midi_cc *oe = + (Oevent_midi_cc *)oevent_list_alloc_item(extra_params->oevent_list); + oe->oevent_type = Oevent_type_midi_cc; + oe->channel = (U8)channel; + oe->control = (U8)control; + oe->value = (U8)value; END_OPERATOR BEGIN_OPERATOR(comment) @@ -320,9 +339,9 @@ BEGIN_OPERATOR(midi) if (vel_num > 127) vel_num = 127; } - Oevent_midi *oe = - (Oevent_midi *)oevent_list_alloc_item(extra_params->oevent_list); - oe->oevent_type = (U8)Oevent_type_midi; + Oevent_midi_note *oe = + (Oevent_midi_note *)oevent_list_alloc_item(extra_params->oevent_list); + oe->oevent_type = (U8)Oevent_type_midi_note; oe->channel = (U8)channel_num; oe->octave = octave_num; oe->note = note_num; diff --git a/tui_main.c b/tui_main.c index 3e96223..9c06f32 100644 --- a/tui_main.c +++ b/tui_main.c @@ -626,12 +626,19 @@ void draw_oevent_list(WINDOW *win, Oevent_list const *oevent_list) { Oevent const *ev = oevent_list->buffer + i; Oevent_types evt = ev->any.oevent_type; switch (evt) { - case Oevent_type_midi: { - Oevent_midi const *em = &ev->midi; - wprintw(win, - "MIDI\tchannel %d\toctave %d\tnote %d\tvelocity %d\tlength %d", - (int)em->channel, (int)em->octave, (int)em->note, - (int)em->velocity, (int)em->duration); + case Oevent_type_midi_note: { + Oevent_midi_note const *em = &ev->midi_note; + wprintw( + win, + "MIDI Note\tchannel %d\toctave %d\tnote %d\tvelocity %d\tlength %d", + (int)em->channel, (int)em->octave, (int)em->note, (int)em->velocity, + (int)em->duration); + break; + } + case Oevent_type_midi_cc: { + Oevent_midi_cc const *ec = &ev->midi_cc; + wprintw(win, "MIDI CC\tchannel %d\tcontrol %d\tvalue %d", + (int)ec->channel, (int)ec->control, (int)ec->value); break; } case Oevent_type_osc_ints: { @@ -1043,8 +1050,8 @@ void send_output_events(Oosc_dev *oosc_dev, Midi_mode const *midi_mode, Usz bpm, break; Oevent const *e = events + i; switch ((Oevent_types)e->any.oevent_type) { - case Oevent_type_midi: { - Oevent_midi const *em = &e->midi; + case Oevent_type_midi_note: { + Oevent_midi_note const *em = &e->midi_note; Usz note_number = (Usz)(12u * em->octave + em->note); if (note_number > 127) note_number = 127; @@ -1064,6 +1071,41 @@ void send_output_events(Oosc_dev *oosc_dev, Midi_mode const *midi_mode, Usz bpm, ++midi_note_count; break; } + case Oevent_type_midi_cc: { + Oevent_midi_cc const *ec = &e->midi_cc; + // Note that we're not preserving the exact order of MIDI events as + // emitted by the orca VM. Notes and CCs that are emitted in the same + // step will always have the CCs sent first. Not sure if this is OK or + // not. If it's not OK, we can either loop again a second time to always + // send CCs after notes, or if that's not also OK, we can make the stack + // buffer more complicated and interleave the CCs in it. + switch (midi_mode_type) { + case Midi_mode_type_null: + break; + case Midi_mode_type_osc_bidule: { + if (!oosc_dev) + break; // not sure if needed + I32 ints[3]; + ints[0] = (0xb << 4) | ec->channel; // status + ints[1] = ec->control; + ints[2] = ec->value; + oosc_send_int32s(oosc_dev, midi_mode->osc_bidule.path, ints, + ORCA_ARRAY_COUNTOF(ints)); + break; + } +#ifdef FEAT_PORTMIDI + case Midi_mode_type_portmidi: { + int istatus = (0x9 << 4) | (int)ec->channel; + PmError pme = Pm_WriteShort( + midi_mode->portmidi.stream, 0, + Pm_Message(istatus, (int)ec->control, (int)ec->value)); + (void)pme; + break; + } +#endif + } + break; + } case Oevent_type_osc_ints: { // kinda lame if (!oosc_dev) @@ -1091,7 +1133,7 @@ void send_output_events(Oosc_dev *oosc_dev, Midi_mode const *midi_mode, Usz bpm, } } - if (midi_note_count > 0 && midi_mode) { + if (midi_note_count > 0) { Usz start_note_offs, end_note_offs; susnote_list_add_notes(susnote_list, new_susnotes, midi_note_count, &start_note_offs, &end_note_offs);