diff --git a/bank.h b/bank.h index fe01280..332e153 100644 --- a/bank.h +++ b/bank.h @@ -4,6 +4,7 @@ typedef enum { Oevent_type_midi_note, Oevent_type_midi_cc, + Oevent_type_midi_pb, Oevent_type_osc_ints, Oevent_type_udp_string, } Oevent_types; @@ -22,6 +23,11 @@ typedef struct { U8 channel, control, value; } Oevent_midi_cc; +typedef struct { + U8 oevent_type; + U8 channel, lsb, msb; +} Oevent_midi_pb; + enum { Oevent_osc_int_count = 16 }; typedef struct { @@ -43,6 +49,7 @@ typedef union { Oevent_any any; Oevent_midi_note midi_note; Oevent_midi_cc midi_cc; + Oevent_midi_pb midi_pb; Oevent_osc_ints osc_ints; Oevent_udp_string udp_string; } Oevent; diff --git a/sim.c b/sim.c index a46b0e3..9b37726 100644 --- a/sim.c +++ b/sim.c @@ -187,7 +187,8 @@ static void oper_poke_and_stun(Glyph *restrict gbuffer, Mark *restrict mbuffer, _('*', bang) \ _(':', midi) \ _(';', udp) \ - _('=', osc) + _('=', osc) \ + _('?', midipb) #define ALPHA_OPERATORS(_) \ _('A', add) \ @@ -274,14 +275,12 @@ BEGIN_OPERATOR(midicc) 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; + oe->control = (U8)index_of(control_g); + oe->value = (U8)(safe_index_of(value_g) * 127 / 35); // 0~35 -> 0~127 END_OPERATOR BEGIN_OPERATOR(comment) @@ -402,6 +401,27 @@ BEGIN_OPERATOR(osc) } END_OPERATOR +BEGIN_OPERATOR(midipb) + for (Usz i = 1; i < 4; ++i) { + PORT(0, (Isz)i, IN); + } + STOP_IF_NOT_BANGED; + Glyph channel_g = PEEK(0, 1); + Glyph msb_g = PEEK(0, 2); + Glyph lsb_g = PEEK(0, 3); + if (channel_g == '.') + return; + Usz channel = index_of(channel_g); + if (channel > 15) + return; + Oevent_midi_pb *oe = + (Oevent_midi_pb *)oevent_list_alloc_item(extra_params->oevent_list); + oe->oevent_type = Oevent_type_midi_pb; + oe->channel = (U8)channel; + oe->msb = (U8)(safe_index_of(msb_g) * 127 / 35); // 0~35 -> 0~127 + oe->lsb = (U8)(safe_index_of(lsb_g) * 127 / 35); +END_OPERATOR + BEGIN_OPERATOR(add) LOWERCASE_REQUIRES_BANG; PORT(0, -1, IN | PARAM); diff --git a/tui_main.c b/tui_main.c index b786f24..e13910b 100644 --- a/tui_main.c +++ b/tui_main.c @@ -93,6 +93,7 @@ static Glyph_class glyph_class_of(Glyph glyph) { case ':': case ';': case '=': + case '?': return Glyph_class_lowercase; case '*': return Glyph_class_bang; @@ -641,6 +642,12 @@ void draw_oevent_list(WINDOW *win, Oevent_list const *oevent_list) { (int)ec->channel, (int)ec->control, (int)ec->value); break; } + case Oevent_type_midi_pb: { + Oevent_midi_pb const *ep = &ev->midi_pb; + wprintw(win, "MIDI PB\tchannel %d\tmsb %d\tlsb %d", (int)ep->channel, + (int)ep->msb, (int)ep->lsb); + break; + } case Oevent_type_osc_ints: { Oevent_osc_ints const *eo = &ev->osc_ints; wprintw(win, "OSC\t%c\tcount: %d ", eo->glyph, eo->count, eo->count); @@ -1102,6 +1109,36 @@ void send_output_events(Oosc_dev *oosc_dev, Midi_mode const *midi_mode, Usz bpm, (void)pme; break; } +#endif + } + break; + } + case Oevent_type_midi_pb: { + Oevent_midi_pb const *ep = &e->midi_pb; + // Same caveat regarding ordering with MIDI CC also applies here. + switch (midi_mode_type) { + case Midi_mode_type_null: + break; + case Midi_mode_type_osc_bidule: { + // TODO ok this is getting highly redundant + if (!oosc_dev) + break; // not sure if needed + I32 ints[3]; + ints[0] = (0xe << 4) | ep->channel; + ints[1] = ep->lsb; + ints[2] = ep->msb; + oosc_send_int32s(oosc_dev, midi_mode->osc_bidule.path, ints, + ORCA_ARRAY_COUNTOF(ints)); + } +#ifdef FEAT_PORTMIDI + case Midi_mode_type_portmidi: { + int istatus = (0xe << 4) | (int)ep->channel; + PmError pme = + Pm_WriteShort(midi_mode->portmidi.stream, 0, + Pm_Message(istatus, (int)ep->lsb, (int)ep->msb)); + (void)pme; + break; + } #endif } break; @@ -2161,7 +2198,7 @@ void push_opers_guide_msg(void) { // {'*', "self", "Sends ORCA command."}, {':', "midi", "Sends MIDI note."}, {'!', "cc", "Sends MIDI control change."}, - // {'?', "pb", "Sends MIDI pitch bend."}, + {'?', "pb", "Sends MIDI pitch bend."}, // {'%', "mono", "Sends MIDI monophonic note."}, {'=', "osc", "Sends OSC message."}, {';', "udp", "Sends UDP message."}, @@ -3557,7 +3594,12 @@ int main(int argc, char **argv) { ged_input_cmd(&t.ged, Ged_input_cmd_toggle_append_mode); break; case '/': - // Currently unused. Formerly 'piano'/trigger mode toggle. + // Formerly 'piano'/trigger mode toggle. We're repurposing it here to + // input a '?' instead of a '/' because '?' opens the help guide, and it + // might be a bad idea to take that away, since orca will take over the + // TTY and may leave users confused. I know of at least 1 person who was + // saved by pressing '?' after they didn't know what to do. Hmm. + ged_input_character(&t.ged, '?'); break; case '<': ged_adjust_bpm(&t.ged, -1);