From 52a702d7f175298787bfc22df160e7b8511400a6 Mon Sep 17 00:00:00 2001 From: c vw Date: Fri, 7 May 2021 11:13:34 +0200 Subject: [PATCH] Finished "multi-device" code, this eliminates the midi_enable variable since we now enable each device separately. --- mac_midi.c | 137 +++++++++++++++++++++++++++++++++++++++++----------- midi2.c | 1 - midi_menu.c | 70 ++++++++------------------- radio.c | 31 ++++++------ radio.h | 4 -- 5 files changed, 144 insertions(+), 99 deletions(-) diff --git a/mac_midi.c b/mac_midi.c index fb45b29..15bace7 100644 --- a/mac_midi.c +++ b/mac_midi.c @@ -180,13 +180,15 @@ static void ReadMIDIdevice(const MIDIPacketList *pktlist, void *refCon, void *co // // store the ports and clients locally such that we -// can properly close a MIDI connection +// can properly close a MIDI connection. +// This can be local static data, no one outside this file +// needs it. // static MIDIPortRef myMIDIports[MAX_MIDI_DEVICES]; static MIDIClientRef myClients[MAX_MIDI_DEVICES]; void close_midi_device(index) { - fprintf(stderr,"%s index=\n",__FUNCTION__); + fprintf(stderr,"%s index=%d\n",__FUNCTION__, index); if (index < 0 || index > n_midi_devices) return; // // This should release the resources associated with the pending connection @@ -196,64 +198,145 @@ void close_midi_device(index) { MIDIClientDispose(myClients[index]); myMIDIports[index]=0; myClients[index]=0; + midi_devices[index].active=0; } int register_midi_device(int index) { - int ret; + OSStatus osret; g_print("%s: index=%d\n",__FUNCTION__,index); - - // // Register a callback routine for the device // + if (index < 0 || index > MAX_MIDI_DEVICES) return -1; - if (index >= 0 && index < n_midi_devices) { + myClients[index]=0; + myMIDIports[index] = 0; + //Create client and port, and connect + osret=MIDIClientCreate(CFSTR("piHPSDR"),NULL,NULL, &myClients[index]); + if (osret !=0) { + g_print("%s: MIDIClientCreate failed with ret=%d\n", __FUNCTION__, (int) osret); + return -1; + } + osret=MIDIInputPortCreate(myClients[index], CFSTR("FromMIDI"), ReadMIDIdevice, NULL, &myMIDIports[index]); + if (osret !=0) { + g_print("%s: MIDIInputPortCreate failed with ret=%d\n", __FUNCTION__, (int) osret); + MIDIClientDispose(myClients[index]); myClients[index]=0; - myMIDIports[index] = 0; - //Create client and port, and connect - MIDIClientCreate(CFSTR("piHPSDR"),NULL,NULL, &myClients[index]); - MIDIInputPortCreate(myClients[index], CFSTR("FromMIDI"), ReadMIDIdevice, NULL, &myMIDIports[index]); - MIDIPortConnectSource(myMIDIports[index] ,MIDIGetSource(index), NULL); - ret=0; - } else { - ret=-1; - } - - return ret; + return -1; + } + osret=MIDIPortConnectSource(myMIDIports[index] ,MIDIGetSource(index), NULL); + if (osret != 0) { + g_print("%s: MIDIPortConnectSource failed with ret=%d\n", __FUNCTION__, (int) osret); + MIDIClientDispose(myClients[index]); + myClients[index]=0; + MIDIPortDispose(myMIDIports[index]); + myMIDIports[index]=0; + return -1; + } + // + // Now we have successfully opened the device. + // + midi_devices[index].active=1; + return 0; } void get_midi_devices() { int n; int i; - CFStringRef pname; - char name[100]; - int FoundMIDIref=-1; + CFStringRef pname; // MacOS name of the device + char name[100]; // C name of the device + OSStatus osret; + static int first=1; + + if (first) { + // + // perhaps not necessary in C, but good programming practise: + // initialize the table upon the first call + // + first=0; + for (i=0; i" // - if (strlen(name) == 0) strcpy(name,"NoPort"); + if (strlen(name) == 0) sprintf(name,"NoPort%d",n_midi_devices); g_print("%s: %s\n",__FUNCTION__,name); if (midi_devices[n_midi_devices].name != NULL) { - g_free(midi_devices[n_midi_devices].name); + if (strncmp(name, midi_devices[n_midi_devices].name,sizeof(name))) { + // + // This slot was occupied and the names do not match: + // Close device (if active), insert new name + // + if (midi_devices[n_midi_devices].active) { + close_midi_device(n_midi_devices); + } + g_free(midi_devices[n_midi_devices].name); + midi_devices[n_midi_devices].name=g_new(gchar,strlen(name)+1); + strcpy(midi_devices[n_midi_devices].name, name); + } else { + // + // This slot was occupied and the names match: do nothing! + // If there was no hot-plug or hot-unplug, we should always + // arrive here! + // + } + } else { + // + // This slot was unoccupied. Insert name and mark inactive + // + midi_devices[n_midi_devices].name=g_new(gchar,strlen(name)+1); + strcpy(midi_devices[n_midi_devices].name, name); + midi_devices[n_midi_devices].active=0; } - midi_devices[n_midi_devices].name=g_new(gchar,strlen(name)+1); - strcpy(midi_devices[n_midi_devices].name,name); n_midi_devices++; } + // + // If there are more devices than we have slots in our Table + // just stop processing. + // + if (n_midi_devices >= MAX_MIDI_DEVICES) break; + } + g_print("%s: number of devices=%d\n",__FUNCTION__,n_midi_devices); + // + // Get rid of all devices lingering around above the high-water mark + // (this happens in the case of hot-unplugging) + // + for (i=n_midi_devices; iaction].str); - g_print("%s: Event=%s Channel=%s Note=%s Type=%s Action=%s\n", __FUNCTION__, str_event, str_channel, str_note, str_type, str_action); + //g_print("%s: Event=%s Channel=%s Note=%s Type=%s Action=%s\n", __FUNCTION__, str_event, str_channel, str_note, str_type, str_action); gtk_list_store_prepend(store,&iter); gtk_list_store_set(store,&iter, EVENT_COLUMN,str_event, @@ -647,6 +621,7 @@ static void delete_cb(GtkButton *widget,gpointer user_data) { g_print("%s: remove first\n",__FUNCTION__); MidiCommandsTable[thisNote]=current_cmd->next; g_free(current_cmd); + current_cmd=NULL; } else { previous_cmd=MidiCommandsTable[thisNote]; while(previous_cmd->next!=NULL) { @@ -655,6 +630,7 @@ static void delete_cb(GtkButton *widget,gpointer user_data) { g_print("%s: remove next\n",__FUNCTION__); previous_cmd->next=next_cmd->next; g_free(next_cmd); + current_cmd=NULL; // note next_cmd == current_cmd break; } previous_cmd=next_cmd; @@ -676,10 +652,6 @@ void midi_menu(GtkWidget *parent) { int row=0; GtkCellRenderer *renderer; - g_print("MENU: ndev=%d\n", n_midi_devices); - for (i=0; i 0) { GtkWidget *devices_label=gtk_label_new(NULL); gtk_label_set_markup(GTK_LABEL(devices_label), "Select MIDI device(s)"); @@ -734,13 +706,6 @@ void midi_menu(GtkWidget *parent) { col=0; } - - midi_enable_b=gtk_check_button_new_with_label("MIDI Enable"); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (midi_enable_b), midi_enabled); - gtk_grid_attach(GTK_GRID(grid),midi_enable_b,col,row,2,1); - g_signal_connect(midi_enable_b,"toggled",G_CALLBACK(midi_enable_cb),NULL); - - col+=2; configure_b=gtk_check_button_new_with_label("MIDI Configure"); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (configure_b), FALSE); gtk_grid_attach(GTK_GRID(grid),configure_b,col,row,2,1); @@ -1150,7 +1115,7 @@ void midi_save_state() { index=0; cmd=MidiCommandsTable[i]; while(cmd!=NULL) { - g_print("%s: channel=%d key=%d event=%s onoff=%d type=%s action=%s\n",__FUNCTION__,cmd->channel,i,midi_events[cmd->event],cmd->onoff,midi_types[cmd->type],ActionTable[cmd->action].str); + //g_print("%s: channel=%d key=%d event=%s onoff=%d type=%s action=%s\n",__FUNCTION__,cmd->channel,i,midi_events[cmd->event],cmd->onoff,midi_types[cmd->type],ActionTable[cmd->action].str); // // There might be events that share the channel and the note value (one NOTE and one CTRL, for example) @@ -1200,9 +1165,14 @@ void midi_restore_state() { //g_print("%s\n",__FUNCTION__); + // + // Note this is too early to open the MIDI devices, since the + // radio has not yet fully been configured. Therefore, only + // set the "active" flag, and the devices will be opened in + // radio.c when it is appropriate + // for(int i=0; i