[PATCH 2/3] WIP: Improve PortMidi devices handling

[ Thread Index | Date Index | More lists.tuxfamily.org/hatari-devel Archives ]


Get rid of several PortMidi related global variables by rewriting
related SDL GUI code, to query device file names from PortMidi on each
device change.

Unfortunately this does not help Hatari being able to use MIDI devices
added while it is running, because getting PortMidi to rescan devices
would require calling Pm_Terminate() and Pm_Initialize().  However,
that would mess current MIDI connection state, so Hatari will do that
only on startup.

I.e. seeing new MIDI device still needs Hatari restart.
---
 src/gui-sdl/dlgDevice.c |  69 ++++++++--------------
 src/includes/midi.h     |   5 +-
 src/midi.c              | 127 ++++++++++++++++------------------------
 3 files changed, 79 insertions(+), 122 deletions(-)

diff --git a/src/gui-sdl/dlgDevice.c b/src/gui-sdl/dlgDevice.c
index 5a5048e8..d0908d84 100644
--- a/src/gui-sdl/dlgDevice.c
+++ b/src/gui-sdl/dlgDevice.c
@@ -14,6 +14,7 @@ const char DlgDevice_fileid[] = "Hatari dlgDevice.c";
 #include "dialog.h"
 #include "sdlgui.h"
 #include "file.h"
+#include "midi.h"  /* needed only with PortMidi */
 #include "screen.h"
 
 
@@ -97,24 +98,6 @@ static SGOBJ devicedlg[] =
 };
 
 
-#ifdef HAVE_PORTMIDI
-#include "midi.h"
-static int midiInput  = -1;
-static int midiOutput = -1;
-
-static void setupMidiControls(void)
-{
-	const char *inportName,*outportName;
-	midiInput  = Midi_Host_GetPortIndex(ConfigureParams.Midi.sMidiInPortName,  true);
-	midiOutput = Midi_Host_GetPortIndex(ConfigureParams.Midi.sMidiOutPortName, false);
-	inportName  = (midiInput  < 0) ? "Off" : ConfigureParams.Midi.sMidiInPortName;
-	outportName = (midiOutput < 0) ? "Off" : ConfigureParams.Midi.sMidiOutPortName;
-	File_ShrinkName(dlgMidiInName,  inportName,  devicedlg[DEVDLG_MIDIINNAME].w);
-	File_ShrinkName(dlgMidiOutName, outportName, devicedlg[DEVDLG_MIDIOUTNAME].w);
-}
-#endif
-
-
 /*-----------------------------------------------------------------------*/
 /**
  * Show and process the "Device" dialog.
@@ -123,7 +106,7 @@ void Dialog_DeviceDlg(void)
 {
 	int but;
 #ifdef HAVE_PORTMIDI
-	const char* portName;
+	const char *name, *midiInName, *midiOutName;
 #endif
 
 	SDLGui_CenterDlg(devicedlg);
@@ -151,7 +134,11 @@ void Dialog_DeviceDlg(void)
 	File_ShrinkName(dlgMidiInName, ConfigureParams.Midi.sMidiInFileName, devicedlg[DEVDLG_MIDIINNAME].w);
 	File_ShrinkName(dlgMidiOutName, ConfigureParams.Midi.sMidiOutFileName, devicedlg[DEVDLG_MIDIOUTNAME].w);
 #else
-	setupMidiControls();
+	midiInName = Midi_Host_GetPortName(ConfigureParams.Midi.sMidiInPortName, 0, true);
+	File_ShrinkName(dlgMidiInName, midiInName ? midiInName : "Off", devicedlg[DEVDLG_MIDIINNAME].w);
+
+	midiOutName = Midi_Host_GetPortName(ConfigureParams.Midi.sMidiOutPortName, 0, false);
+	File_ShrinkName(dlgMidiOutName,  midiOutName ? midiOutName : "Off", devicedlg[DEVDLG_MIDIOUTNAME].w);
 #endif
 
 	/* The devices dialog main loop */
@@ -194,37 +181,31 @@ void Dialog_DeviceDlg(void)
 			break;
 #else
 		case DEVDLG_PREVIN:
-			if (midiInput >= 0)
-			{
-				midiInput--;
-				portName = (midiInput == -1) ? "Off" : Midi_Host_GetPortName(midiInput, true);
-				if (portName)
-					File_ShrinkName(dlgMidiInName, portName, devicedlg[DEVDLG_MIDIINNAME].w);
-			}
+			midiInName = Midi_Host_GetPortName(midiInName, -1, true);
+			File_ShrinkName(dlgMidiInName, midiInName ? midiInName : "Off",
+					devicedlg[DEVDLG_MIDIINNAME].w);
 			break;
 		case DEVDLG_NEXTIN:
-			portName = Midi_Host_GetPortName(midiInput + 1, true);
-			if (portName)
+			name = Midi_Host_GetPortName(midiInName, +1, true);
+			if (name)
 			{
-				midiInput++;
-				File_ShrinkName(dlgMidiInName, portName, devicedlg[DEVDLG_MIDIINNAME].w);
+				midiInName = name;
+				File_ShrinkName(dlgMidiInName, midiInName,
+						devicedlg[DEVDLG_MIDIINNAME].w);
 			}
 			break;
 		case DEVDLG_PREVOUT:
-			if (midiOutput >= 0)
-			{
-				midiOutput--;
-				portName = (midiOutput == -1) ? "Off" : Midi_Host_GetPortName(midiOutput, false);
-				if (portName)
-					File_ShrinkName(dlgMidiOutName, portName, devicedlg[DEVDLG_MIDIOUTNAME].w);
-			}
+			midiOutName = Midi_Host_GetPortName(midiOutName, -1, false);
+			File_ShrinkName(dlgMidiOutName, midiOutName ? midiOutName : "Off",
+					devicedlg[DEVDLG_MIDIOUTNAME].w);
 			break;
 		case DEVDLG_NEXTOUT:
-			portName = Midi_Host_GetPortName(midiOutput + 1, false);
-			if (portName)
+			name = Midi_Host_GetPortName(midiOutName, +1, false);
+			if (name)
 			{
-				midiOutput++;
-				File_ShrinkName(dlgMidiOutName, portName, devicedlg[DEVDLG_MIDIOUTNAME].w);
+				midiOutName = name;
+				File_ShrinkName(dlgMidiOutName, midiOutName,
+						devicedlg[DEVDLG_MIDIOUTNAME].w);
 			}
 			break;
 #endif
@@ -239,8 +220,8 @@ void Dialog_DeviceDlg(void)
 	ConfigureParams.Midi.bEnableMidi = (devicedlg[DEVDLG_MIDIENABLE].state & SG_SELECTED);
 #ifdef HAVE_PORTMIDI
 	assert(sizeof(dlgMidiInName) <= sizeof(ConfigureParams.Midi.sMidiInPortName));
-	strcpy(ConfigureParams.Midi.sMidiInPortName, dlgMidiInName);
+	strcpy(ConfigureParams.Midi.sMidiInPortName, midiInName ? midiInName : "Off");
 	assert(sizeof(dlgMidiOutName) <= sizeof(ConfigureParams.Midi.sMidiOutPortName));
-	strcpy(ConfigureParams.Midi.sMidiOutPortName, dlgMidiOutName);
+	strcpy(ConfigureParams.Midi.sMidiOutPortName, midiOutName ? midiOutName : "Off");
 #endif
 }
diff --git a/src/includes/midi.h b/src/includes/midi.h
index e9f776eb..48a85699 100644
--- a/src/includes/midi.h
+++ b/src/includes/midi.h
@@ -19,7 +19,8 @@ extern void Midi_Control_WriteByte(void);
 extern void Midi_Data_WriteByte(void);
 extern void Midi_InterruptHandler_Update(void);
 
-extern const char* Midi_Host_GetPortName(int index, bool forInput);
-extern int Midi_Host_GetPortIndex(const char* portName, bool forInput);
+#ifdef HAVE_PORTMIDI
+extern const char* Midi_Host_GetPortName(const char *name, int offset, bool forInput);
+#endif
 
 #endif
diff --git a/src/midi.c b/src/midi.c
index 7b0b95e3..48e07372 100644
--- a/src/midi.c
+++ b/src/midi.c
@@ -72,10 +72,6 @@ static FILE *pMidiFhOut = NULL;    /* File handle used for Midi output */
 #define INPUT_BUFFER_SIZE  1024		 // PortMidi handles buffering
 static PmStream* midiIn  = NULL;	 // current midi input port
 static PmStream* midiOut = NULL;	 // current midi output port
-static int numInputs  = 0;				 // number of available input ports
-static int numOutputs = 0;				 // number of available output ports
-static const PmDeviceInfo** inports  = NULL;	// array of available input ports
-static const PmDeviceInfo** outports = NULL;	// array of available output ports
 
 static bool Midi_Host_SwitchPort(const char* portName, bool forInput);
 static int Midi_GetDataLength(Uint8 status);
@@ -372,58 +368,25 @@ static bool Midi_Host_Open(void)
 			 ConfigureParams.Midi.sMidiInFileName);
 	}
 #else
-	/* Need to always get MIDI device info, for MIDI setup dialog */
-	int i;
-	int iindex = 0;
-	int oindex = 0;
-	int numPorts = 0;
-	
+	int i, ports;
 	if (Pm_Initialize() != pmNoError)
 	{
 		LOG_TRACE(TRACE_MIDI, "MIDI: PortMidi initialization failed\n");
 		return false;
 	}
-	// -- get rid of earlier portmidi descriptor arrays (if allocated)
-	// -- the information may be stale (USB Midi etc)
-	if (inports)
-		free (inports);
-	if (outports)
-		free (outports);
-	inports = outports = NULL;
-	numInputs = numOutputs = 0;
-
-	// -- count number of input and output ports
-	numPorts = Pm_CountDevices();
-	for (i = 0; i < numPorts; i++)
+	// -- log available ports
+	ports = Pm_CountDevices();
+	for (i = 0; i < ports; i++)
 	{
 		const PmDeviceInfo *info = Pm_GetDeviceInfo(i);
-		if (info->input)
-			numInputs++;
-		else if (info->output)
-			numOutputs++;
-	}
-
-	// -- allocate descriptor arrays
-	inports  = malloc(numInputs  * sizeof(PmDeviceInfo*));
-	outports = malloc(numOutputs * sizeof(PmDeviceInfo*));
-	
-	// -- populate descriptor arrays
-	for (i = 0; i < numPorts; i++)
-	{
-		const PmDeviceInfo* info = Pm_GetDeviceInfo(i);
-		if (info)
-		{
-			LOG_TRACE(TRACE_MIDI, "MIDI: device %d: '%s'\n", i, info->name);
-			if (info->input)
-				inports[iindex++] = info;
-			if (info->output)
-				outports[oindex++] = info;
-		}
-		else
-			LOG_TRACE(TRACE_MIDI, "MIDI: info disappeared for device %d!\n", i);
+		if (!info)
+			continue;
+		LOG_TRACE(TRACE_MIDI, "MIDI: %s %d: '%s'\n",
+			  info->input ? "input " : "output", i, info->name);
 	}
 
 	// -- open input and output ports according to configuration
+	// -- ignore errors to avoid MIDI being disabled
 	if (ConfigureParams.Midi.sMidiInPortName[0])
 		Midi_Host_SwitchPort(ConfigureParams.Midi.sMidiInPortName, true);
 	if (ConfigureParams.Midi.sMidiOutPortName[0])
@@ -458,42 +421,55 @@ static void Midi_Host_Close(void)
 
 
 
-/* ---------------------------------------------------------------------------- */
-/**
- * returns port name for input or output port at 'index'
- */
-const char* Midi_Host_GetPortName(int index, bool forInput)
-{
 #ifdef HAVE_PORTMIDI
-	if (forInput && index < numInputs)
-		return inports[index]->name;
-	else if (!forInput && index < numOutputs)
-		return outports[index]->name;
-#endif
-
-	return NULL;
-}
-
-/* ---------------------------------------------------------------------------- */
 /**
- * returns port descriptor array index for input or output 'portName'
+ * Returns port name if there's one matching the given port name
+ * with given offset.
+ *
+ * Regardless of offset size, they are interpreted only as:
+ *	-1, 0, 1
+ *
+ * As special case, for NULL name with positive offset,
+ * name of the first port in correct direction is returned.
  */
-int Midi_Host_GetPortIndex(const char* portName, bool forInput)
+const char* Midi_Host_GetPortName(const char *name, int offset, bool forInput)
 {
-#ifdef HAVE_PORTMIDI
-	int i = 0;
-	int numPorts = forInput ? numInputs : numOutputs;
-	const PmDeviceInfo** ports = forInput ? inports : outports;
+	const PmDeviceInfo* info;
+	const char *prev = NULL;
+	bool prev_matched = false;
+	int i, count;
 
-	if (ports)
+	// -- find port with given offset from named one
+	count = Pm_CountDevices();
+	for (i = 0; i < count; i++)
 	{
-		for (i = 0; i < numPorts; i++)
-			if (!strcmp(portName, ports[i]->name))
-				return i;
+		info = Pm_GetDeviceInfo(i);
+		if (!info)
+			continue;
+		if (forInput && !info->input)
+			continue;
+		if (!forInput && info->input)
+			continue;
+		if (!name)
+		{
+			if (offset <= 0)
+				return NULL;
+			return info->name;
+		}
+		if (!strcmp(info->name, name))
+		{
+			if (!offset)
+				return name;
+			if (offset < 0)
+				return prev;
+			prev_matched = true;
+			continue;
+		}
+		if (prev_matched)
+			return info->name;
+		prev = info->name;
 	}
-#endif
-
-	return -1;
+	return NULL;
 }
 
 /**
@@ -502,7 +478,6 @@ int Midi_Host_GetPortIndex(const char* portName, bool forInput)
  * matches beginning of the device name, is used. Returns true for
  * success, false otherwise
  */
-#ifdef HAVE_PORTMIDI
 static bool Midi_Host_SwitchPort(const char* portName, bool forInput)
 {
 	int i, prefixmatch, len, count;
-- 
2.30.2


--------------C13100BB4891F43814193EBB
Content-Type: text/x-patch; charset=UTF-8;
 name="0001-WIP-re-order-code-to-reduce-Midi_BuildEvent-indentat.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
 filename*0="0001-WIP-re-order-code-to-reduce-Midi_BuildEvent-indentat.pa";
 filename*1="tch"



Mail converted by MHonArc 2.6.19+ http://listengine.tuxfamily.org/