]> git.rkrishnan.org Git - pihpsdr.git/commitdiff
- Added MIDI level-1 code for ALSA/LINUX
authorc vw <dl1ycf@darc.de>
Fri, 24 May 2019 15:25:39 +0000 (17:25 +0200)
committerc vw <dl1ycf@darc.de>
Fri, 24 May 2019 15:25:39 +0000 (17:25 +0200)
- Fixed TX panadapter display
- Fixed WDSP wisdom stuff

Makefile
alsa_midi.c [new file with mode: 0644]
mac_midi.c
main.c
midi.inp
midi2.c
radio.c
tx_panadapter.c

index ef76aeddd2990eb9cc1c4a8e0d7667b2ac3ed221..ad0dbd8ed31ce1d73bafe8f1bc8f3e4a26c1871e 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -39,6 +39,9 @@ GIT_VERSION := $(shell git describe --abbrev=0 --tags)
 # uncomment the line below to include support for Pi SDR
 #PI_SDR_INCLUDE=PI_SDR
 
+# uncomment the line below to include MIDI support
+#MIDI_INCLUDE=MIDI
+
 #uncomment the line below for the platform being compiled on (actually not used)
 UNAME_N=raspberrypi
 #UNAME_N=odroid
@@ -52,6 +55,14 @@ LINK=gcc
 # uncomment the line below for various debug facilities
 #DEBUG_OPTION=-D DEBUG
 
+ifeq ($(MIDI_INCLUDE),MIDI)
+MIDI_OPTIONS=-D MIDI
+MIDI_SOURCES= alsa_midi.c midi2.c midi3.c
+MIDI_HEADERS= midi.h
+MIDI_OBJS= alsa_midi.o midi2.o midi3.o
+MIDI_LIBS= -lasound
+endif
+
 ifeq ($(PURESIGNAL_INCLUDE),PURESIGNAL)
 PURESIGNAL_OPTIONS=-D PURESIGNAL
 PURESIGNAL_SOURCES= \
@@ -201,11 +212,12 @@ GTKLIBS=`pkg-config --libs gtk+-3.0`
 AUDIO_LIBS=-lasound
 #AUDIO_LIBS=-lsoundio
 
-OPTIONS=-g -Wno-deprecated-declarations $(PURESIGNAL_OPTIONS) $(REMOTE_OPTIONS) $(USBOZY_OPTIONS) $(I2C_OPTIONS) $(GPIO_OPTIONS) $(LIMESDR_OPTIONS) \
-               $(FREEDV_OPTIONS) $(LOCALCW_OPTIONS) $(RADIOBERRY_OPTIONS) $(PI_SDR_OPTIONS) $(PSK_OPTIONS) $(STEMLAB_OPTIONS) $(STEMLAB_FIX_OPTION) \
-               -D GIT_DATE='"$(GIT_DATE)"' -D GIT_VERSION='"$(GIT_VERSION)"' $(DEBUG_OPTION) -O3
+OPTIONS=-g -Wno-deprecated-declarations $(MIDI_OPTIONS) $(PURESIGNAL_OPTIONS) $(REMOTE_OPTIONS) $(USBOZY_OPTIONS) \
+       $(I2C_OPTIONS) $(GPIO_OPTIONS) $(LIMESDR_OPTIONS) $(FREEDV_OPTIONS) $(LOCALCW_OPTIONS) $(RADIOBERRY_OPTIONS) \
+       $(PI_SDR_OPTIONS) $(PSK_OPTIONS) $(STEMLAB_OPTIONS) $(STEMLAB_FIX_OPTION) \
+       -D GIT_DATE='"$(GIT_DATE)"' -D GIT_VERSION='"$(GIT_VERSION)"' $(DEBUG_OPTION) -O3
 
-LIBS=-lrt -lm -lwdsp -lpthread $(AUDIO_LIBS) $(USBOZY_LIBS) $(PSKLIBS) $(GTKLIBS) $(GPIO_LIBS) $(SOAPYSDRLIBS) $(FREEDVLIBS) $(STEMLAB_LIBS)
+LIBS=-lrt -lm -lwdsp -lpthread $(AUDIO_LIBS) $(USBOZY_LIBS) $(PSKLIBS) $(GTKLIBS) $(GPIO_LIBS) $(SOAPYSDRLIBS) $(FREEDVLIBS) $(STEMLAB_LIBS) $(MIDI_LIBS)
 INCLUDES=$(GTKINCLUDES)
 
 COMPILE=$(CC) $(OPTIONS) $(INCLUDES)
@@ -425,10 +437,18 @@ ext.o \
 error_handler.o \
 cwramp.o
 
-$(PROGRAM):  $(OBJS) $(REMOTE_OBJS) $(USBOZY_OBJS) $(LIMESDR_OBJS) $(FREEDV_OBJS) $(LOCALCW_OBJS) $(I2C_OBJS) $(GPIO_OBJS) $(PSK_OBJS) $(PURESIGNAL_OBJS) $(STEMLAB_OBJS)
-       $(LINK) -o $(PROGRAM) $(OBJS) $(REMOTE_OBJS) $(USBOZY_OBJS) $(I2C_OBJS) $(GPIO_OBJS) $(LIMESDR_OBJS) $(FREEDV_OBJS) $(LOCALCW_OBJS) $(PSK_OBJS) $(PURESIGNAL_OBJS) $(STEMLAB_OBJS) $(LIBS)
-
-all: prebuild  $(PROGRAM) $(HEADERS) $(REMOTE_HEADERS) $(USBOZY_HEADERS) $(LIMESDR_HEADERS) $(FREEDV_HEADERS) $(LOCALCW_HEADERS) $(I2C_HEADERS) $(GPIO_HEADERS) $(PSK_HEADERS) $(PURESIGNAL_HEADERS) $(STEMLAB_HEADERS) $(SOURCES) $(REMOTE_SOURCES) $(USBOZY_SOURCES) $(LIMESDR_SOURCES) $(FREEDV_SOURCES) $(I2C_SOURCES) $(GPIO_SOURCES) $(PSK_SOURCES) $(PURESIGNAL_SOURCES) $(STEMLAB_SOURCES)
+$(PROGRAM):  $(OBJS) $(REMOTE_OBJS) $(USBOZY_OBJS) $(LIMESDR_OBJS) $(FREEDV_OBJS) \
+               $(LOCALCW_OBJS) $(I2C_OBJS) $(GPIO_OBJS) $(PSK_OBJS) $(PURESIGNAL_OBJS) \
+               $(MIDI_OBJS) $(STEMLAB_OBJS)
+       $(LINK) -o $(PROGRAM) $(OBJS) $(REMOTE_OBJS) $(USBOZY_OBJS) $(I2C_OBJS) $(GPIO_OBJS) \
+               $(LIMESDR_OBJS) $(FREEDV_OBJS) $(LOCALCW_OBJS) $(PSK_OBJS) $(PURESIGNAL_OBJS) \
+               $(MIDI_OBJS) $(STEMLAB_OBJS) $(LIBS)
+
+all:   prebuild  $(PROGRAM) $(HEADERS) $(REMOTE_HEADERS) $(USBOZY_HEADERS) $(LIMESDR_HEADERS) \
+       $(FREEDV_HEADERS) $(LOCALCW_HEADERS) $(I2C_HEADERS) $(GPIO_HEADERS) $(PSK_HEADERS) \
+       $(PURESIGNAL_HEADERS) $(MIDI_HEADERS) $(STEMLAB_HEADERS) $(SOURCES) $(REMOTE_SOURCES) \
+       $(USBOZY_SOURCES) $(LIMESDR_SOURCES) $(FREEDV_SOURCES) $(I2C_SOURCES) $(GPIO_SOURCES) \
+       $(PSK_SOURCES) $(PURESIGNAL_SOURCES) $(MIDI_SOURCES)$(STEMLAB_SOURCES)
 
 prebuild:
        rm -f version.o
diff --git a/alsa_midi.c b/alsa_midi.c
new file mode 100644 (file)
index 0000000..6893f8c
--- /dev/null
@@ -0,0 +1,236 @@
+/*
+ * MIDI support for pihpsdr
+ * (C) Christoph van Wullen, DL1YCF.
+ *
+ * This is the "Layer-1" for ALSA-MIDI (Linux)
+ * For further comments see file mac_midi.c
+ */
+
+/*
+ * ALSA: MIDI devices are sub-devices to sound cards.
+ *       Therefore we have to loop through the sound cards
+ *       and then, for each sound card, through the
+ *       sub-devices until we have found "our" MIDI
+ *       input device.
+ *
+ *       The procedure how to find and talk with
+ *       a MIDI device is taken from the sample
+ *       program amidi.c in alsautils.
+ */
+
+#include "midi.h"
+
+#ifndef __APPLE__
+
+#include <pthread.h>
+#include <alsa/asoundlib.h>
+
+static pthread_t midi_thread_id;
+static void* midi_thread(void *);
+
+static char portname[64];
+
+static enum {
+        STATE_SKIP,            // skip bytes
+        STATE_ARG1,             // one arg byte to come
+        STATE_ARG2,             // two arg bytes to come
+} state=STATE_SKIP;
+
+static enum {
+       CMD_NOTEON,
+       CMD_NOTEOFF,
+       CMD_CTRL,
+       CMD_PITCH,
+} command;
+
+static void *midi_thread(void *arg) {
+    int ret;
+    snd_rawmidi_t *input;
+    int npfds;
+    struct pollfd *pfds;
+    unsigned char buf[32];
+    unsigned char byte;
+    unsigned short revents;
+    int i;
+    int chan,arg1,arg2;
+
+    if ((ret = snd_rawmidi_open(&input, NULL, portname, SND_RAWMIDI_NONBLOCK)) < 0) {
+        fprintf(stderr,"cannot open port \"%s\": %s\n", portname, snd_strerror(ret));
+        return NULL;
+    }
+    snd_rawmidi_read(input, NULL, 0); /* trigger reading */
+
+    npfds = snd_rawmidi_poll_descriptors_count(input);
+    pfds = alloca(npfds * sizeof(struct pollfd));
+    snd_rawmidi_poll_descriptors(input, pfds, npfds);
+    for (;;) {
+       ret = poll(pfds, npfds, 250);
+       if (ret < 0) {
+            fprintf(stderr,"poll failed: %s\n", strerror(errno));
+           // Do not give up, but also do not fire too rapidly
+           usleep(250000);
+       }
+       if (ret <= 0) continue;  // nothing arrived, do next poll()
+       if ((ret = snd_rawmidi_poll_descriptors_revents(input, pfds, npfds, &revents)) < 0) {
+            fprintf(stderr,"cannot get poll events: %s\n", snd_strerror(errno));
+            continue;
+        }
+        if (revents & (POLLERR | POLLHUP)) continue;
+        if (!(revents & POLLIN)) continue;
+       // something has arrived
+       ret = snd_rawmidi_read(input, buf, 64);
+        if (ret == 0) continue;
+        if (ret < 0) {
+            fprintf(stderr,"cannot read from port \"%s\": %s\n", portname, snd_strerror(ret));
+            continue;
+        }
+        // process bytes in buffer. Since they no not necessarily form complete messages
+        // we need a state machine here. 
+        for (i=0; i< ret; i++) {
+           byte=buf[i];
+           switch (state) {
+               case STATE_SKIP:
+                   chan=byte & 0x0F;
+                   switch (byte & 0xF0) {
+                       case 0x80:      // Note-OFF command
+                           command=CMD_NOTEOFF;
+                           state=STATE_ARG2;
+                           break;
+                       case 0x90:      // Note-ON command
+                           command=CMD_NOTEON;
+                           state=STATE_ARG2;
+                           break;    
+                       case 0xB0:      // Controller Change
+                           command=CMD_CTRL;
+                           state=STATE_ARG2;
+                           break;
+                       case 0xE0:      // Pitch Bend
+                           command=CMD_PITCH;
+                           state=STATE_ARG2;
+                           break;
+                       case 0xA0:      // Polyphonic Pressure
+                       case 0xC0:      // Program change
+                       case 0xD0:      // Channel pressure
+                       case 0xF0:      // System Message: continue waiting for bit7 set
+                       default:        // Remain in STATE_SKIP until bit7 is set
+                           break;
+                   }
+                   break;
+               case STATE_ARG2:
+                   arg1=byte;
+                    state=STATE_ARG1;
+                    break;
+               case STATE_ARG1:
+                   arg2=byte;
+                   // We have a command!
+                   switch (command) {
+                       case CMD_NOTEON:
+                          NewMidiEvent(MIDI_NOTE, chan, arg1, 1);
+                          break;
+                       case CMD_NOTEOFF:
+                          NewMidiEvent(MIDI_NOTE, chan, arg1, 0);
+                          break;
+                       case CMD_CTRL:
+                          NewMidiEvent(MIDI_CTRL, chan, arg1, arg2);
+                          break;
+                       case CMD_PITCH:
+                          NewMidiEvent(MIDI_PITCH, chan, 0, arg1+128*arg2);
+                          break;
+                    }
+                   state=STATE_SKIP;
+                   break;
+           }
+        }
+    }
+}
+
+void register_midi_device(char *myname) {
+
+    int mylen=strlen(myname);
+    snd_ctl_t *ctl;
+    snd_rawmidi_info_t *info;
+    int card, device, subs, sub, ret;
+    const char *devnam, *subnam;
+    int found=0;
+    char name[64];
+
+    card=-1;
+    if ((ret = snd_card_next(&card)) < 0) {
+        fprintf(stderr,"cannot determine card number: %s\n", snd_strerror(ret));
+        return;
+    }
+    while (card >= 0) {
+       fprintf(stderr,"Found Sound Card=%d\n",card);
+       sprintf(name,"hw:%d", card);
+        if ((ret = snd_ctl_open(&ctl, name, 0)) < 0) {
+                fprintf(stderr,"cannot open control for card %d: %s\n", card, snd_strerror(ret));
+                return;
+        }
+       device = -1;
+       // loop through devices of the card
+       for (;;) {
+           if ((ret = snd_ctl_rawmidi_next_device(ctl, &device)) < 0) {
+                fprintf(stderr,"cannot determine device number: %s\n", snd_strerror(ret));
+                break;
+            }
+           if (device < 0) break;
+           fprintf(stderr,"Found Device=%d on Card=%d\n", device, card);
+           // found sub-device
+           snd_rawmidi_info_alloca(&info);
+            snd_rawmidi_info_set_device(info, device);
+            snd_rawmidi_info_set_stream(info, SND_RAWMIDI_STREAM_INPUT);
+            ret = snd_ctl_rawmidi_info(ctl, info);
+            if (ret >= 0) {
+                subs = snd_rawmidi_info_get_subdevices_count(info);
+            } else {
+                subs = 0;
+           }
+           fprintf(stderr,"Number of MIDI input devices: %d\n", subs);
+           if (!subs) break;
+           // subs: number of sub-devices to device on card
+            for (sub = 0; sub < subs; ++sub) {
+                snd_rawmidi_info_set_stream(info, SND_RAWMIDI_STREAM_INPUT);
+                snd_rawmidi_info_set_subdevice(info, sub);
+                ret = snd_ctl_rawmidi_info(ctl, info);
+                if (ret < 0) {
+                    fprintf(stderr,"cannot get rawmidi information %d:%d:%d: %s\n",
+                                   card, device, sub, snd_strerror(ret));
+                    break;
+                }
+               if (found) break;
+               devnam = snd_rawmidi_info_get_name(info);
+               subnam = snd_rawmidi_info_get_subdevice_name(info);
+               // If there is only one sub-device and it has no name, we  use
+               // devnam for comparison and make a portname of form "hw:x,y",
+               // else we use subnam for comparison and make a portname of form "hw:x,y,z".
+                if (sub == 0 && subnam[0] == '\0') {
+                   sprintf(portname,"hw:%d,%d", card, device);
+               } else {
+                   sprintf(portname,"hw:%d,%d,%d", card, device, sub);
+                   devnam=subnam;
+               }
+               if (!strncmp(myname, devnam, mylen)) {
+                   found=1;
+                   fprintf(stderr,"MIDI device %s selected (PortName=%s)\n", devnam, portname);
+               } else {
+                    fprintf(stderr,"MIDI device found BUT NOT SELECTED: %s\n", devnam);
+               }
+           }
+       }
+       snd_ctl_close(ctl);
+       // next card
+        if ((ret = snd_card_next(&card)) < 0) {
+            fprintf(stderr,"cannot determine card number: %s\n", snd_strerror(ret));
+            break;
+        }
+    }
+    if (!found) {
+       fprintf(stderr,"MIDI device %s NOT FOUND!\n", myname);
+    }
+    // Found our MIDI input device. Spawn off a thread reading data
+    ret = pthread_create(&midi_thread_id, NULL, midi_thread, NULL);
+    if (ret < 0) {
+       fprintf(stderr,"Failed to create MIDI read thread\n");
+    }
+}
+#endif
index 06c84ca106de0bcf59cb56a935baf00ef7fad7f0..2229f44f75c952219f3d78971b3e6a39f3012ca1 100644 (file)
 // We process *all* data but only generate calls to layer-2 for Note On/Off
 // and ControllerChange events.
 //
+
+//
+// Although MacOS does all the grouping of MIDI bytes into commands for us,
+// we use here the same state machine as we have in the ALSA MIDI implementation
+// That is, we look at each MIDI byte separately
+//
+
+static enum {
+        STATE_SKIP,            // skip bytes until command bit is set
+        STATE_ARG1,             // one arg byte to come
+        STATE_ARG2,             // two arg bytes to come
+} state=STATE_SKIP;
+
+static enum {
+        CMD_NOTEON,
+        CMD_NOTEOFF,
+        CMD_CTRL,
+        CMD_PITCH,
+} command;
+
 static void ReadMIDIdevice(const MIDIPacketList *pktlist, void *refCon, void *connRefCon) {
-    int i,j,k,command,chan;
+    int i,j,k,byte,chan,arg1,arg2;
     MIDIPacket *packet = (MIDIPacket *)pktlist->packet;
        
        
     // loop through all packets in the current list
     for (j=0; j < pktlist->numPackets; ++j) {
-        if (packet->length > 0) { 
-           for ( i = 0; i<(packet->length); ) {
-               command=packet->data[i];
-                if ((command & 128) != 128) continue;
-                
-                chan = command & 0x0F;
-
-                switch (command & 0xF0) {
-                  case 0x80:  // Note off
-                       NewMidiEvent(MIDI_NOTE, chan, packet->data[i+1], 0);
-                       //fprintf(stderr,"NOTE OFF: Note=%d Chan=%d Vel=%d\n", packet->data[i+1], chan, packet->data[i+2]);
-                       i +=3;
-                       break;
-                  case 0x90:  // Note on
-                       NewMidiEvent(MIDI_NOTE, chan, packet->data[i+1], 1);
-                       //fprintf(stderr,"NOTE ON : Note=%d Chan=%d Vel=%d\n", packet->data[i+1], chan, packet->data[i+2]);
-                       i +=3;
-                       break;
-                  case 0xA0:  // Polyph. Press.
-                       fprintf(stderr,"PolPress: Note=%d Chan=%d Prs=%d\n", packet->data[i+1], chan, packet->data[i+2]);
-                       i +=3;
-                       break;
-                  case 0xB0:  // Control change
-                       NewMidiEvent(MIDI_CTRL, chan, packet->data[i+1], packet->data[i+2]);
-                       //fprintf(stderr,"CtlChang: Ctrl=%d Chan=%d Val=%d\n", packet->data[i+1], chan, packet->data[i+2]);
-                       i +=3;
-                       break;
-                  case 0xC0:  // Program change
-                       fprintf(stderr,"PgmChang: Prog=%d Chan=%d\n", packet->data[i+1], chan);
-                       i +=2;
-                       break;
-                  case 0xD0:  // Channel Pressure
-                       fprintf(stderr, "ChanPres: Pres=%d Chan=%d\n", packet->data[i+1], chan);
-                       i +=2;
-                       break;
-                  case 0xE0:  // Pitch Bend
-                       NewMidiEvent(MIDI_PITCH, chan, 0, packet->data[i+1] + 128*packet->data[i+2]);
-                       //fprintf(stderr,"Pitch   : val =%d Chan=%d\n", packet->data[i+1] + 128*packet->data[i+2], chan);
-                       i +=3;
-                       break;
-                  case 0xF0:  
-                       fprintf(stderr, "System  : %x", command);
-                        while ((command = (packet->data[++i]) & 128) != 128) {
-                          fprintf(stderr," %x",command);
-                        }
-                        fprintf(stderr,"\n");
-                       break;
-                }
-           } // i-loop through the packet
-           packet = MIDIPacketNext(packet);
-        } // if packet length > 1
+       for (i=0; i<packet->length; i++) {
+           byte=packet->data[i];
+            switch (state) {
+                case STATE_SKIP:
+                    chan=byte & 0x0F;
+                    switch (byte & 0xF0) {
+                        case 0x80:      // Note-OFF command
+                            command=CMD_NOTEOFF;
+                            state=STATE_ARG2;
+                            break;
+                        case 0x90:      // Note-ON command
+                            command=CMD_NOTEON;
+                            state=STATE_ARG2;
+                            break;
+                        case 0xB0:      // Controller Change
+                            command=CMD_CTRL;
+                            state=STATE_ARG2;
+                            break;
+                        case 0xE0:      // Pitch Bend
+                            command=CMD_PITCH;
+                            state=STATE_ARG2;
+                            break;
+                        case 0xA0:      // Polyphonic Pressure: skip args
+                        case 0xC0:      // Program change: skip args
+                        case 0xD0:      // Channel pressure: skip args
+                        case 0xF0:      // System Message: skip args
+                        default:       // Remain in STATE_SKIP until "interesting" command seen
+                            break;
+                    }
+                    break;
+                case STATE_ARG2:       // store byte as first argument
+                    arg1=byte;
+                    state=STATE_ARG1;
+                    break;
+                case STATE_ARG1:       // store byte as second argument, process command
+                    arg2=byte;
+                    // We have a command!
+                    switch (command) {
+                        case CMD_NOTEON:
+                           NewMidiEvent(MIDI_NOTE, chan, arg1, 1);
+                           break;
+                        case CMD_NOTEOFF:
+                           NewMidiEvent(MIDI_NOTE, chan, arg1, 0);
+                           break;
+                        case CMD_CTRL:
+                           NewMidiEvent(MIDI_CTRL, chan, arg1, arg2);
+                           break;
+                        case CMD_PITCH:
+                           NewMidiEvent(MIDI_PITCH, chan, 0, arg1+128*arg2);
+                           break;
+                    }
+                    state=STATE_SKIP;
+                    break;
+            }
+       } // i-loop through the packet
+       packet = MIDIPacketNext(packet);
     } // j-loop through the list of packets
 }
 
diff --git a/main.c b/main.c
index 4265922353af8d3c6cab825c0144418ac85ca045..ffb0242cd06a10ea19caae15c7e62de3b0280836 100644 (file)
--- a/main.c
+++ b/main.c
@@ -65,12 +65,6 @@ gint full_screen=1;
 
 static GtkWidget *discovery_dialog;
 
-#ifdef __APPLE__
-static sem_t *wisdom_sem;
-#else
-static sem_t wisdom_sem;
-#endif
-
 static GdkCursor *cursor_arrow;
 static GdkCursor *cursor_watch;
 
@@ -97,16 +91,11 @@ static gint save_cb(gpointer data) {
 }
 
 static pthread_t wisdom_thread_id;
+static int wisdom_running=0;
 
 static void* wisdom_thread(void *arg) {
-  fprintf(stderr,"Securing wisdom file in directory: %s\n", (char *)arg);
-  status_text("Creating FFTW Wisdom file ...");
   WDSPwisdom ((char *)arg);
-#ifdef __APPLE__
-  sem_post(wisdom_sem);
-#else
-  sem_post(&wisdom_sem);
-#endif
+  wisdom_running=0;
   return NULL;
 }
 
@@ -161,7 +150,6 @@ gboolean main_delete (GtkWidget *widget) {
 static int init(void *data) {
   char *res;
   char wisdom_directory[1024];
-  char wisdom_file[1024];
   int rc;
 
   fprintf(stderr,"init\n");
@@ -177,25 +165,21 @@ static int init(void *data) {
   // Let WDSP (via FFTW) check for wisdom file in current dir
   // If there is one, the "wisdom thread" takes no time
   // Depending on the WDSP version, the file is wdspWisdom or wdspWisdom00.
+  // sem_trywait() is not elegant, replaced this with wisdom_running variable.
   //
   res=getcwd(wisdom_directory, sizeof(wisdom_directory));
   strcpy(&wisdom_directory[strlen(wisdom_directory)],"/");
-  strcpy(wisdom_file,wisdom_directory);
-#ifdef __APPLE__
-  wisdom_sem=sem_open("WISDOM", O_CREAT, 0700, 0);
-#else
-  rc=sem_init(&wisdom_sem, 0, 0);
-#endif
-  rc=pthread_create(&wisdom_thread_id, NULL, wisdom_thread, (void *)wisdom_directory);
-#ifdef __APPLE__
-  while(sem_trywait(wisdom_sem)<0) {
-#else
-  while(sem_trywait(&wisdom_sem)<0) {
-#endif
-      status_text("WDSP wisdom done.");
-      while (gtk_events_pending ())
-        gtk_main_iteration ();
+  fprintf(stderr,"Securing wisdom file in directory: %s\n", wisdom_directory);
+  status_text("Creating FFTW Wisdom file ...");
+  wisdom_running=1;
+  rc=pthread_create(&wisdom_thread_id, NULL, wisdom_thread, wisdom_directory);
+  while (wisdom_running) {
+      // wait for the wisdom thread to complete, meanwhile
+      // handling any GTK events.
       usleep(100000); // 100ms
+      while (gtk_events_pending ()) {
+        gtk_main_iteration ();
+      }
   }
 
   g_idle_add(ext_discovery,NULL);
index 88076cef4e09416ea705c64b3eed3fc684b78de4..0e6ebcafadbd551f723b01ca88b3ff4dec59cfd2 100644 (file)
--- a/midi.inp
+++ b/midi.inp
@@ -5,7 +5,7 @@
 # The key is suitable for radios with a step (ALEX) attenuator, the wheel
 # fits best for radios with a programmable attenuator (0-31 dB)
 #
-DEVICE=CMD PL 1
+DEVICE=CMD PL-1
 CTRL=31 WHEEL THR=59 61 63 65 67 69 ACTION=VFO           # Big wheel:    : main VFO knob
 PITCH ACTION=AFGAIN                                      # Big slider    : AF gain
 KEY=16 ACTION=PREAMP                                    # Key 1         : Cycle through Preamp settings
diff --git a/midi2.c b/midi2.c
index 377a86efc546494c25ec67212b8591fc882fe194..0d4d300f1747b930178963597d0a97e1c659fca2 100644 (file)
--- a/midi2.c
+++ b/midi2.c
@@ -160,9 +160,11 @@ void MIDIstartup() {
       if (cp) *cp=0;               // ignore trailing comment
 
       if ((cp = strstr(zeile, "DEVICE="))) {
-        // Delete trailing blanks and newlines
+        // Delete comments and trailing blanks
        cq=cp+7;
-        while (*cq != 0 && *cq != '\n' && *cq != ' ' && *cq != '\t') cq++;
+       while (*cq != 0 && *cq != '#') cq++;
+       *cq--=0;
+       while (cq > cp+7 && (*cq == ' ' || *cq == '\t')) cq--;
        *cq=0;
        register_midi_device(cp+7);
         continue; // nothing more in this line
diff --git a/radio.c b/radio.c
index 3c029b4cd7236b0a3c58e7f8163f97c0404d43b8..74a4445fa3e10b99fe03244d8d616898455d4072 100644 (file)
--- a/radio.c
+++ b/radio.c
@@ -760,6 +760,7 @@ static void rxtx(int state) {
     SetChannelState(transmitter->id,1,0);
     tx_set_displaying(transmitter,1);
   } else {
+    // switch to rx
     SetChannelState(transmitter->id,0,1);
     if(protocol==NEW_PROTOCOL) {
       schedule_high_priority();
index 852220f541c78508302ccf0ea164225032f7b450..7a8d590daaf123c3d724e116af9a0060ddfd5f69 100644 (file)
@@ -208,25 +208,34 @@ void tx_panadapter_update(TRANSMITTER *tx) {
   cairo_rectangle(cr, filter_left, 0.0, filter_right-filter_left, (double)display_height);
   cairo_fill(cr);
 
-  // plot the levels
-  int V = (int)(tx->panadapter_high - tx->panadapter_low);
-  int numSteps = V / 20;
-  for (i = 1; i < numSteps; i++) {
-    int num = tx->panadapter_high - i * 20;
-    int y = (int)floor((tx->panadapter_high - num) * display_height / V);
-    cairo_set_source_rgb (cr, 0.0, 1.0, 1.0);
-    cairo_set_line_width(cr, 1.0);
-    cairo_move_to(cr,0.0,(double)y);
-    cairo_line_to(cr,(double)display_width,(double)y);
-
-    cairo_set_source_rgb (cr, 0.0, 1.0, 1.0);
-    cairo_select_font_face(cr, "FreeMono", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
-    cairo_set_font_size(cr, 12);
+  // plot the levels 0, -20, 40, ... dBm (green line with label)
+  // also plot gray lines at -10, -30, -50, ... dBm (without label)
+  double dbm_per_line=(double)display_height/((double)tx->panadapter_high-(double)tx->panadapter_low);
+  cairo_set_source_rgb (cr, 0.00, 1.00, 1.00);
+  cairo_set_line_width(cr, 1.0);
+  cairo_select_font_face(cr, "FreeMono", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
+  cairo_set_font_size(cr, 12);
+
+  for(i=tx->panadapter_high;i>=tx->panadapter_low;i--) {
     char v[32];
-    sprintf(v,"%d dBm",num);
-    cairo_move_to(cr, 1, (double)y);  
-    cairo_show_text(cr, v);
-    cairo_stroke(cr);
+    if((abs(i)%10) ==0) {
+      double y = (double)(tx->panadapter_high-i)*dbm_per_line;
+      if ((abs(i) % 20) == 0) {
+        cairo_set_source_rgb (cr, 0.00, 1.00, 1.00);
+        cairo_move_to(cr,0.0,y);
+        cairo_line_to(cr,(double)display_width,y);
+
+        sprintf(v,"%d dBm",i);
+        cairo_move_to(cr, 1, y);
+        cairo_show_text(cr, v);
+        cairo_stroke(cr);
+      } else {
+        cairo_set_source_rgb (cr, 0.25, 0.25, 0.25);
+        cairo_move_to(cr,0.0,y);
+        cairo_line_to(cr,(double)display_width,y);
+        cairo_stroke(cr);
+      }
+    }
   }
 
   // plot frequency markers