shithub: orca

Download patch

ref: a09c84877de96f042e6ac545c4a7420b5049e694
parent: 378b374451a8c94aa85821fd18ddec4f7e88eab0
author: cancel <cancel@cancel.fm>
date: Mon Jan 20 14:32:52 EST 2020

Add MIDI pitch bend operator

--- 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 @@
   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 @@
   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;
--- a/sim.c
+++ b/sim.c
@@ -187,7 +187,8 @@
   _('*', bang)                                                                 \
   _(':', midi)                                                                 \
   _(';', udp)                                                                  \
-  _('=', osc)
+  _('=', osc)                                                                  \
+  _('?', midipb)
 
 #define ALPHA_OPERATORS(_)                                                     \
   _('A', add)                                                                  \
@@ -274,14 +275,12 @@
   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)
@@ -400,6 +399,27 @@
       oe->numbers[i] = buff[i];
     }
   }
+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)
--- a/tui_main.c
+++ b/tui_main.c
@@ -93,6 +93,7 @@
   case ':':
   case ';':
   case '=':
+  case '?':
     return Glyph_class_lowercase;
   case '*':
     return Glyph_class_bang;
@@ -641,6 +642,12 @@
               (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);
@@ -1106,6 +1113,36 @@
       }
       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;
+    }
     case Oevent_type_osc_ints: {
       // kinda lame
       if (!oosc_dev)
@@ -2161,7 +2198,7 @@
       // {'*', "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 @@
       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);