From 4f7d62c6531bdcb1f6088042ffad663a67810591 Mon Sep 17 00:00:00 2001
From: c vw <dl1ycf@darc.de>
Date: Thu, 24 Oct 2019 17:20:01 +0200
Subject: [PATCH] for HERCULES midi controller

---
 alsa_midi.c |   9 ++++-
 mac_midi.c  |   9 ++++-
 midi.h      |  13 +++----
 midi2.c     |  85 +++++++++++++++++++++++++++---------------
 midi3.c     | 105 +++++++++++++++++++++++++++++++---------------------
 5 files changed, 141 insertions(+), 80 deletions(-)

diff --git a/alsa_midi.c b/alsa_midi.c
index 6893f8c..4c183a5 100644
--- a/alsa_midi.c
+++ b/alsa_midi.c
@@ -125,7 +125,14 @@ static void *midi_thread(void *arg) {
 		    // We have a command!
 		    switch (command) {
 			case CMD_NOTEON:
-			   NewMidiEvent(MIDI_NOTE, chan, arg1, 1);
+			   // Hercules MIDI controllers generate NoteOn
+			   // messages with velocity == 0 when releasing
+			   // a push-button
+			   if (arg2 == 0) {
+			     NewMidiEvent(MIDI_NOTE, chan, arg1, 0);
+			   } else {
+			     NewMidiEvent(MIDI_NOTE, chan, arg1, 1);
+			   }
 			   break;
 			case CMD_NOTEOFF:
 			   NewMidiEvent(MIDI_NOTE, chan, arg1, 0);
diff --git a/mac_midi.c b/mac_midi.c
index 2229f44..429a67d 100644
--- a/mac_midi.c
+++ b/mac_midi.c
@@ -115,7 +115,14 @@ static void ReadMIDIdevice(const MIDIPacketList *pktlist, void *refCon, void *co
                     // We have a command!
                     switch (command) {
                         case CMD_NOTEON:
-                           NewMidiEvent(MIDI_NOTE, chan, arg1, 1);
+                           // Hercules MIDI controllers generate NoteOn
+                           // messages with velocity == 0 when releasing
+                           // a push-button.
+                           if (arg2 == 0) {
+                             NewMidiEvent(MIDI_NOTE, chan, arg1, 0);
+                           } else {
+                             NewMidiEvent(MIDI_NOTE, chan, arg1, 1);
+                           }
                            break;
                         case CMD_NOTEOFF:
                            NewMidiEvent(MIDI_NOTE, chan, arg1, 0);
diff --git a/midi.h b/midi.h
index 28156d6..48061d7 100644
--- a/midi.h
+++ b/midi.h
@@ -160,13 +160,12 @@ struct desc {
    enum MIDIevent    event;	  // type of event (NOTE on/off, Controller change, Pitch value)
    int               onoff;       // 1: generate upstream event both for Note-on and Note-off
    enum MIDItype     type;        // Key, Knob, or Wheel
-   int               low_thr3;    // Wheel only: If controller value is <= this value, generate "very fast down"
-   int               low_thr2;    // Wheel only: If controller value is <= this value, generate "     fast down"
-   int               low_thr1;    // Wheel only: If controller value is <= this value, generate "          down"
-   int               up_thr1;     // Wheel only: If controller value is <= this value, generate "          up  "
-   int               up_thr2;     // Wheel only: If controller value is <= this value, generate "     fast up  "
-   int               up_thr3;     // Wheel only: If controller value is <= this value, generate "very fast up  "
-   int               leftright;   // Wheel: if set, swap left/right or up/down; Knob: map 0-127 onto 127-0
+   int               vfl1,vfl2;   // Wheel only: range of controller values for "very fast left"
+   int               fl1,fl2;     // Wheel only: range of controller values for "fast left"
+   int               lft1,lft2;   // Wheel only: range of controller values for "slow left"
+   int               vfr1,vfr2;   // Wheel only: range of controller values for "very fast right"
+   int               fr1,fr2;     // Wheel only: range of controller values for "fast right"
+   int               rgt1,rgt2;   // Wheel only: range of controller values for "slow right"
    int		     delay;       // Wheel only: delay (msec) before next message is given upstream
    enum MIDIaction   action;	  // SDR "action" to generate
    struct desc       *next;       // Next defined action for a controller/key with that note value (NULL for end of list)
diff --git a/midi2.c b/midi2.c
index e41484e..8000ec5 100644
--- a/midi2.c
+++ b/midi2.c
@@ -39,8 +39,6 @@ void NewMidiEvent(enum MIDIevent event, int channel, int note, int val) {
 		    if (desc->type == MIDI_KNOB) {
 			// normalize value to range 0 - 100
 			new = (val*100)/127;
-			// LEFTRIGHT: swap min/max value
-			if (desc->leftright) new=100-new;
 			DoTheMidi(desc->action, desc->type, new);
 		    } else if (desc->type == MIDI_WHEEL) {
 			if (desc->delay > 0) {
@@ -51,14 +49,12 @@ void NewMidiEvent(enum MIDIevent event, int channel, int note, int val) {
 			  last_wheel_tp = tp;
 			}
 			// translate value to direction
-			if (val <= desc->low_thr1) new=-1;
-			if (val <= desc->low_thr2) new=-10;
-			if (val <= desc->low_thr3) new=-100;
-			if (val >= desc->up_thr1 ) new=1;
-			if (val >= desc->up_thr2 ) new=10;
-			if (val >= desc->up_thr3 ) new=100;
-			// LEFTRIGHT: swap up/down
-			if (desc->leftright) new=-new;
+			if ((val >= desc->vfl1) && (val <= desc->vfl2)) new=-100;
+			if ((val >= desc-> fl1) && (val <= desc-> fl2)) new=-10;
+			if ((val >= desc->lft1) && (val <= desc->lft2)) new=-1;
+			if ((val >= desc->rgt1) && (val <= desc->rgt2)) new= 1;
+			if ((val >= desc-> fr1) && (val <= desc-> fr2)) new= 10;
+			if ((val >= desc->vfr1) && (val <= desc->vfr2)) new= 100;
 			DoTheMidi(desc->action, desc->type, new);
 			last_wheel_action=desc->action;
 		    }
@@ -67,8 +63,6 @@ void NewMidiEvent(enum MIDIevent event, int channel, int note, int val) {
 		    if (desc->type == MIDI_KNOB) {
 			// normalize value to 0 - 100
 			new = (val*100)/16383;
-			// possibly reverse scale
-			if (desc->leftright) new=100-new;
 			DoTheMidi(desc->action, desc->type, new);
 		    }
 		    break;
@@ -164,7 +158,7 @@ void MIDIstartup() {
     enum MIDIaction action;
     int chan;
     int swap_lr;
-    int lt3,lt2,lt1,ut1,ut2,ut3;
+    int t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12;
     int onoff, delay;
     struct desc *desc,*dp;
     enum MIDItype type;
@@ -196,8 +190,8 @@ void MIDIstartup() {
         continue; // nothing more in this line
       }
       chan=-1;  // default: any channel
-      lt3=lt2=lt1=-1;
-      ut3=ut2=ut1=128;
+      t1=t3=t5=t7= t9=t11=128;  // range that never occurs
+      t2=t4=t6=t8=t10=t12=-1;   // range that never occurs
       onoff=0;
       swap_lr=0;
       event=EVENT_NONE;
@@ -205,6 +199,11 @@ void MIDIstartup() {
       key=0;
       delay=0;
 
+      //
+      // The KEY=, CTRL=, and PITCH= cases are mutually exclusive
+      // If more than one keyword is in the line, PITCH wins over CTRL
+      // wins over KEY.
+      //
       if ((cp = strstr(zeile, "KEY="))) {
         sscanf(cp+4, "%d", &key);
         event=MIDI_NOTE;
@@ -219,12 +218,23 @@ void MIDIstartup() {
         event=MIDI_PITCH;
 	type=MIDI_KNOB;
       }
+      //
+      // If event is still undefined, skip line
+      //
+      if (event == EVENT_NONE) continue;
+
+      //
+      // beware of illegal key values
+      //
+      if (key < 0  ) key=0;
+      if (key > 127) key=127;
+
       if ((cp = strstr(zeile, "CHAN="))) {
         sscanf(cp+5, "%d", &chan);
 	chan--;
         if (chan<0 || chan>15) chan=-1;
       }
-      if ((cp = strstr(zeile, "WHEEL"))) {
+      if ((cp = strstr(zeile, "WHEEL")) && (type == MIDI_KNOB)) {
 	// change type from MIDI_KNOB to MIDI_WHEEL
         type=MIDI_WHEEL;
       }
@@ -238,7 +248,8 @@ void MIDIstartup() {
         sscanf(cp+6, "%d", &delay);
       }
       if ((cp = strstr(zeile, "THR="))) {
-        sscanf(cp+4, "%d %d %d %d %d %d", &lt3, &lt2, &lt1, &ut1, &ut2, &ut3);
+        sscanf(cp+4, "%d %d %d %d %d %d %d %d %d %d %d %d",
+               &t1,&t2,&t3,&t4,&t5,&t6,&t7,&t8,&t9,&t10,&t11,&t12);
       }
       if ((cp = strstr(zeile, "ACTION="))) {
         // cut zeile at the first blank character following
@@ -247,10 +258,18 @@ void MIDIstartup() {
 	*cq=0;
         action=keyword2action(cp+7);
       }
-      if (event == EVENT_NONE || type == TYPE_NONE || key < 0 || key > 127) continue;
-      // Now all entries of the line have been read. Construct descriptor
-//fprintf(stderr,"K=%d C=%d T=%d E=%d A=%d OnOff=%d LeftRight=%d THRs=%d %d %d %d %d %d\n",
-//               key,chan,type, event, action, onoff, swap_lr, lt3,lt2,lt1,ut1,ut2,ut3);
+#if 0
+  fprintf(stderr,"K=%d C=%d T=%d E=%d A=%d OnOff=%d\n",key,chan,type, event, action, onoff);
+  if (t1 <= t2 ) fprintf(stderr,"Range for very fast  left: %d -- %d\n",t1,t2);
+  if (t3 <= t4 ) fprintf(stderr,"Range for      fast  left: %d -- %d\n",t3,t4);
+  if (t5 <= t6 ) fprintf(stderr,"Range for    normal  left: %d -- %d\n",t5,t6);
+  if (t7 <= t8 ) fprintf(stderr,"Range for    normal right: %d -- %d\n",t7,t8);
+  if (t9 <= t10) fprintf(stderr,"Range for      fast right: %d -- %d\n",t9,t10);
+  if (t11<= t12) fprintf(stderr,"Range for very fast right: %d -- %d\n",t11,t12);
+#endif
+      //
+      // All data for a descriptor has been read. Construct it!
+      //
       desc = (struct desc *) malloc(sizeof(struct desc));
       desc->next = NULL;
       desc->action = action;
@@ -258,15 +277,23 @@ void MIDIstartup() {
       desc->event = event;
       desc->onoff = onoff;
       desc->delay = delay;
-      desc->low_thr3 = lt3;
-      desc->low_thr2 = lt2;
-      desc->low_thr1 = lt1;
-      desc->up_thr1  = ut1;
-      desc->up_thr2  = ut2;
-      desc->up_thr3  = ut3;
-      desc->leftright= swap_lr;
+      desc->vfl1  = t1;
+      desc->vfl2  = t2;
+      desc->fl1   = t3;
+      desc->fl2   = t4;
+      desc->lft1  = t5;
+      desc->lft2  = t6;
+      desc->rgt1  = t7;
+      desc->rgt2  = t8;
+      desc->fr1   = t9;
+      desc->fr2   = t10;
+      desc->vfr1  = t11;
+      desc->vfr2  = t12;
       desc->channel  = chan;
-      // insert descriptor
+      //
+      // insert descriptor into linked list.
+      // We have a linked list for each key value to speed up searches
+      //
       if (event == MIDI_PITCH) {
 	dp = MidiCommandsTable.pitch;
 	if (dp == NULL) {
diff --git a/midi3.c b/midi3.c
index 87f4213..c5ba82e 100644
--- a/midi3.c
+++ b/midi3.c
@@ -195,8 +195,8 @@ void DoTheMidi(enum MIDIaction action, enum MIDItype type, int val) {
 		}
 	    }
 	    break;
-	case PRE:	// only key supported
-	    if (filter_board == CHARLY25) {
+	case PRE:	// only key supported, and only CHARLY25
+	    if (filter_board == CHARLY25 && type == MIDI_KEY) {
 		//
 		// For hardware other than CHARLY25, we do not
 		// switch preamps
@@ -237,7 +237,7 @@ void DoTheMidi(enum MIDIaction action, enum MIDItype type, int val) {
 		      new=adc_attenuation[active_receiver->adc] + val;
 		      if (new > 31) new=31;
 		      if (new < 0 ) new=0;
-		    } else {
+	
 		      new=(31*val)/100;
 		    }
 		    dp=malloc(sizeof(double));
@@ -264,85 +264,106 @@ void DoTheMidi(enum MIDIaction action, enum MIDItype type, int val) {
 	    if (dnew > 0.5) transmitter->compressor=1;
 	    g_idle_add(ext_set_compression, NULL);
 	    break;
-	case MIDI_NB:
+	case MIDI_NB: // only key supported
 	    // cycle through NoiseBlanker settings
-	    if (active_receiver->nb) {
+            if (type == MIDI_KEY) {
+	      if (active_receiver->nb) {
 		active_receiver->nb = 0;
 		active_receiver->nb2= 1;
-	    } else if (active_receiver->nb2) {
+	      } else if (active_receiver->nb2) {
 		active_receiver->nb = 0;
 		active_receiver->nb2= 0;
-	    } else {
+	      } else {
 		active_receiver->nb = 1;
 		active_receiver->nb2= 0;
+	      }
+	      g_idle_add(ext_vfo_update, NULL);
 	    }
-	    g_idle_add(ext_vfo_update, NULL);
 	    break;
-	case MIDI_NR:
+	case MIDI_NR: // only key supported
 	    // cycle through NoiseReduction settings
-	    if (active_receiver->nr) {
+	    if (type == MIDI_KEY) {
+	      if (active_receiver->nr) {
 		active_receiver->nr = 0;
 		active_receiver->nr2= 1;
-	    } else if (active_receiver->nr2) {
+	      } else if (active_receiver->nr2) {
 		active_receiver->nr = 0;
 		active_receiver->nr2= 0;
-	    } else {
+	      } else {
 		active_receiver->nr = 1;
 		active_receiver->nr2= 0;
+	      }
+	      g_idle_add(ext_vfo_update, NULL);
 	    }
-	    g_idle_add(ext_vfo_update, NULL);
 	    break;
-	case VOX:
+	case VOX: // only key supported
 	    // toggle VOX
-	    vox_enabled = !vox_enabled;
-	    g_idle_add(ext_vfo_update, NULL);
+	    if (type == MIDI_KEY) {
+	      vox_enabled = !vox_enabled;
+	      g_idle_add(ext_vfo_update, NULL);
+	    }
 	    break;
-	case MIDI_CTUN:
+	case MIDI_CTUN: // only key supported
 	    // toggle CTUN
-	    new=active_receiver->id;
-	    if(!vfo[new].ctun) {
+	    if (type == MIDI_KEY) {
+	      new=active_receiver->id;
+	      if(!vfo[new].ctun) {
 		vfo[new].ctun=1;
 		vfo[new].offset=0;
-	    } else {
+	      } else {
 		vfo[new].ctun=0;
+	      }
+	      vfo[new].ctun_frequency=vfo[new].frequency;
+	      set_offset(active_receiver,vfo[new].offset);
+	      g_idle_add(ext_vfo_update, NULL);
 	    }
-	    vfo[new].ctun_frequency=vfo[new].frequency;
-	    set_offset(active_receiver,vfo[new].offset);
-	    g_idle_add(ext_vfo_update, NULL);
 	    break;
-	case MIDI_PS:
+	case MIDI_PS: // only key supported
 #ifdef PURESIGNAL
 	    // toggle PURESIGNAL
-	    new=!(transmitter->puresignal);
-	    g_idle_add(ext_tx_set_ps,GINT_TO_POINTER(new));
+	    if (type == MIDI_KEY) {
+	      new=!(transmitter->puresignal);
+	      g_idle_add(ext_tx_set_ps,GINT_TO_POINTER(new));
+	    }
 #endif
 	    break;
-	case MIDI_SPLIT:
+	case MIDI_SPLIT: // only key supported
 	    // toggle split mode
-	    if(!split) {
+	    if (type == MIDI_KEY) {
+	      if(!split) {
 		split=1;
 		tx_set_mode(transmitter,vfo[VFO_B].mode);
-	    } else {
+	      } else {
 		split=0;
 		tx_set_mode(transmitter,vfo[VFO_A].mode);
+	      }
+	      g_idle_add(ext_vfo_update, NULL);
 	    }
-	    g_idle_add(ext_vfo_update, NULL);
 	    break;
-	case VFO_A2B:
-	    g_idle_add(ext_vfo_a_to_b, NULL);
+	case VFO_A2B: // only key supported
+	    if (type == MIDI_KEY) {
+	      g_idle_add(ext_vfo_a_to_b, NULL);
+	    }
 	    break;
-	case VFO_B2A:
-	    g_idle_add(ext_vfo_b_to_a, NULL);
+	case VFO_B2A: // only key supported
+	    if (type == MIDI_KEY) {
+	      g_idle_add(ext_vfo_b_to_a, NULL);
+	    }
 	    break;
-	case MIDI_LOCK:
-	    locked=!locked;
-	    g_idle_add(ext_vfo_update, NULL);
+	case MIDI_LOCK: // only key supported
+	    if (type == MIDI_KEY) {
+	      locked=!locked;
+	      g_idle_add(ext_vfo_update, NULL);
+	    }
 	    break;
-	case AGCATTACK:
-	    new=active_receiver->agc + 1;
-	    if (new > AGC_FAST) new=0;
-	    active_receiver->agc=new;
-	    g_idle_add(ext_vfo_update, NULL);
+	case AGCATTACK: // only key supported
+	    // cycle through fast/med/slow AGC attack
+	    if (type == MIDI_KEY) {
+	      new=active_receiver->agc + 1;
+	      if (new > AGC_FAST) new=0;
+	      active_receiver->agc=new;
+	      g_idle_add(ext_vfo_update, NULL);
+	    }
 	    break;
 	case ACTION_NONE:
 	    // No error message, this is the "official" action for un-used controller buttons.
-- 
2.45.2