summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEero Tamminen <oak@helsinkinet.fi>2017-11-05 17:40:05 (GMT)
committerEero Tamminen <oak@helsinkinet.fi>2017-11-05 17:40:05 (GMT)
commit7eea8eafd7553234502183f6b14b66d9f0d5e164 (patch)
treef34705fe161fb40d8c266f0f50f3a4e9c517b82f
parent5b22d05c4f5be0ab9298011d7fd9f9652a824192 (diff)
downloadhatari-7eea8eafd7553234502183f6b14b66d9f0d5e164.zip
hatari-7eea8eafd7553234502183f6b14b66d9f0d5e164.tar.gz
Optional PortMidi library support from Jari Kleimola
With few fixes + command line option from Eero.
-rw-r--r--src/change.c11
-rw-r--r--src/configuration.c4
-rw-r--r--src/includes/configuration.h2
-rw-r--r--src/includes/midi.h3
-rw-r--r--src/midi.c568
-rw-r--r--src/options.c17
6 files changed, 537 insertions, 68 deletions
diff --git a/src/change.c b/src/change.c
index 2d2e954..fff440e 100644
--- a/src/change.c
+++ b/src/change.c
@@ -332,9 +332,14 @@ void Change_CopyChangedParamsToConfiguration(CNF_PARAMS *current, CNF_PARAMS *ch
/* Did change MIDI settings? */
if (current->Midi.bEnableMidi != changed->Midi.bEnableMidi
- || ((strcmp(changed->Midi.sMidiOutFileName, current->Midi.sMidiOutFileName)
- || strcmp(changed->Midi.sMidiInFileName, current->Midi.sMidiInFileName))
- && changed->Midi.bEnableMidi))
+#ifdef HAVE_PORTMIDI
+ || strcmp(changed->Midi.sMidiOutPortName, current->Midi.sMidiOutPortName)
+ || strcmp(changed->Midi.sMidiInPortName, current->Midi.sMidiInPortName)
+#else
+ || strcmp(changed->Midi.sMidiOutFileName, current->Midi.sMidiOutFileName)
+ || strcmp(changed->Midi.sMidiInFileName, current->Midi.sMidiInFileName)
+#endif
+ )
{
Dprintf("- midi>\n");
Midi_UnInit();
diff --git a/src/configuration.c b/src/configuration.c
index ca91311..332acb7 100644
--- a/src/configuration.c
+++ b/src/configuration.c
@@ -517,6 +517,8 @@ static const struct Config_Tag configs_Midi[] =
{ "bEnableMidi", Bool_Tag, &ConfigureParams.Midi.bEnableMidi },
{ "sMidiInFileName", String_Tag, ConfigureParams.Midi.sMidiInFileName },
{ "sMidiOutFileName", String_Tag, ConfigureParams.Midi.sMidiOutFileName },
+ { "sMidiInPortName", String_Tag, ConfigureParams.Midi.sMidiInPortName },
+ { "sMidiOutPortName", String_Tag, ConfigureParams.Midi.sMidiOutPortName },
{ NULL , Error_Tag, NULL }
};
@@ -730,6 +732,8 @@ void Configuration_SetDefault(void)
ConfigureParams.Midi.bEnableMidi = false;
strcpy(ConfigureParams.Midi.sMidiInFileName, "/dev/snd/midiC1D0");
strcpy(ConfigureParams.Midi.sMidiOutFileName, "/dev/snd/midiC1D0");
+ strcpy(ConfigureParams.Midi.sMidiInPortName, "Off");
+ strcpy(ConfigureParams.Midi.sMidiOutPortName, "Off");
/* Set defaults for Screen */
ConfigureParams.Screen.bFullScreen = false;
diff --git a/src/includes/configuration.h b/src/includes/configuration.h
index 190166f..6308d19 100644
--- a/src/includes/configuration.h
+++ b/src/includes/configuration.h
@@ -295,6 +295,8 @@ typedef struct
bool bEnableMidi;
char sMidiInFileName[FILENAME_MAX];
char sMidiOutFileName[FILENAME_MAX];
+ char sMidiInPortName[FILENAME_MAX];
+ char sMidiOutPortName[FILENAME_MAX];
} CNF_MIDI;
diff --git a/src/includes/midi.h b/src/includes/midi.h
index 5d69a46..e9f776e 100644
--- a/src/includes/midi.h
+++ b/src/includes/midi.h
@@ -19,4 +19,7 @@ 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);
+
#endif
diff --git a/src/midi.c b/src/midi.c
index 2418919..63e372d 100644
--- a/src/midi.c
+++ b/src/midi.c
@@ -53,8 +53,6 @@ const char Midi_fileid[] = "Hatari midi.c : " __DATE__ " " __TIME__;
#define MIDI_TRANSFER_BYTE_CYCLE (MIDI_TRANSFER_BIT_CYCLE * 10)
#endif
-static FILE *pMidiFhIn = NULL; /* File handle used for Midi input */
-static FILE *pMidiFhOut = NULL; /* File handle used for Midi output */
static Uint8 MidiControlRegister;
static Uint8 MidiStatusRegister;
static Uint8 nRxDataByte;
@@ -63,42 +61,43 @@ static Uint64 TDR_Empty_Time; /* Time when TDR will be empty after a write to f
static Uint64 TSR_Complete_Time; /* Time when TSR will be completely transferred */
+/*
+** Host MIDI I/O
+*/
+static bool Midi_Host_Open(void);
+static void Midi_Host_Close(void);
+static int Midi_Host_ReadByte(void);
+static bool Midi_Host_WriteByte(Uint8 byte);
+
+#ifndef HAVE_PORTMIDI
+static FILE *pMidiFhIn = NULL; /* File handle used for Midi input */
+static FILE *pMidiFhOut = NULL; /* File handle used for Midi output */
+#else
+#include "portmidi.h"
+#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);
+static int Midi_SplitEvent(PmEvent* midiEvent, Uint8* msg);
+static PmEvent* Midi_BuildEvent(Uint8 byte);
+#endif
+
/**
* Initialization: Open MIDI device.
*/
void Midi_Init(void)
{
- if (!ConfigureParams.Midi.bEnableMidi)
- return;
-
- if (ConfigureParams.Midi.sMidiOutFileName[0])
+ if (!Midi_Host_Open())
{
- /* Open MIDI output file */
- pMidiFhOut = File_Open(ConfigureParams.Midi.sMidiOutFileName, "wb");
- if (!pMidiFhOut)
- {
- Log_AlertDlg(LOG_ERROR, "MIDI output file open failed. MIDI support disabled.");
- ConfigureParams.Midi.bEnableMidi = false;
- return;
- }
- setvbuf(pMidiFhOut, NULL, _IONBF, 0); /* No output buffering! */
- LOG_TRACE(TRACE_MIDI, "MIDI: Opened file '%s' for output\n",
- ConfigureParams.Midi.sMidiOutFileName);
- }
- if (ConfigureParams.Midi.sMidiInFileName[0])
- {
- /* Try to open MIDI input file */
- pMidiFhIn = File_Open(ConfigureParams.Midi.sMidiInFileName, "rb");
- if (!pMidiFhIn)
- {
- Log_AlertDlg(LOG_ERROR, "MIDI input file open failed. MIDI support disabled.");
- ConfigureParams.Midi.bEnableMidi = false;
- return;
- }
- setvbuf(pMidiFhIn, NULL, _IONBF, 0); /* No input buffering! */
- LOG_TRACE(TRACE_MIDI, "MIDI: Opened file '%s' for input\n",
- ConfigureParams.Midi.sMidiInFileName);
+ Log_AlertDlg(LOG_ERROR, "MIDI i/o open failed. MIDI support disabled.");
+ ConfigureParams.Midi.bEnableMidi = false;
}
}
@@ -108,9 +107,7 @@ void Midi_Init(void)
*/
void Midi_UnInit(void)
{
- pMidiFhIn = File_Close(pMidiFhIn);
- pMidiFhOut = File_Close(pMidiFhOut);
-
+ Midi_Host_Close();
CycInt_RemovePendingInterrupt(INTERRUPT_MIDI);
}
@@ -257,7 +254,8 @@ void Midi_Data_ReadByte(void)
void Midi_Data_WriteByte(void)
{
Uint8 nTxDataByte;
-
+ bool ok;
+
ACIA_AddWaitCycles (); /* Additional cycles when accessing the ACIA */
nTxDataByte = IoMem[0xfffc06];
@@ -287,20 +285,14 @@ void Midi_Data_WriteByte(void)
if (!ConfigureParams.Midi.bEnableMidi)
return;
- if (pMidiFhOut)
- {
- int ret;
-
- /* Write the character to the output file: */
- ret = fputc(nTxDataByte, pMidiFhOut);
+ ok = Midi_Host_WriteByte(nTxDataByte);
- /* If there was an error then stop the midi emulation */
- if (ret == EOF)
- {
- LOG_TRACE(TRACE_MIDI, "MIDI: write error -> stop MIDI\n");
- Midi_UnInit();
- return;
- }
+ /* If there was an error then stop the midi emulation */
+ if (!ok)
+ {
+ LOG_TRACE(TRACE_MIDI, "MIDI: write error -> stop MIDI\n");
+ Midi_UnInit();
+ return;
}
}
@@ -331,25 +323,24 @@ void Midi_InterruptHandler_Update(void)
}
/* Read the bytes in, if we have any */
- if (pMidiFhIn && File_InputAvailable(pMidiFhIn))
+ nInChar = Midi_Host_ReadByte();
+ if (nInChar != EOF)
{
- nInChar = fgetc(pMidiFhIn);
- if (nInChar != EOF)
- {
- LOG_TRACE(TRACE_MIDI, "MIDI: Read character -> $%x\n", nInChar);
- /* Copy into our internal queue */
- nRxDataByte = nInChar;
- MidiStatusRegister |= ACIA_SR_RX_FULL;
+ LOG_TRACE(TRACE_MIDI, "MIDI: Read character -> $%x\n", nInChar);
+ /* Copy into our internal queue */
+ nRxDataByte = nInChar;
+ MidiStatusRegister |= ACIA_SR_RX_FULL;
- /* Do we need to generate a receive interrupt? */
- MIDI_UpdateIRQ ();
- }
- else
- {
- LOG_TRACE(TRACE_MIDI, "MIDI: read error (doesn't stop MIDI)\n");
- clearerr(pMidiFhIn);
- }
+ /* Do we need to generate a receive interrupt? */
+ MIDI_UpdateIRQ ();
+ }
+#ifndef HAVE_PORTMIDI
+ else if (pMidiFhIn)
+ {
+ LOG_TRACE(TRACE_MIDI, "MIDI: read error (doesn't stop MIDI)\n");
+ clearerr(pMidiFhIn);
}
+#endif
/* Set timer */
#ifdef OLD_CPU_SHIFT
@@ -359,3 +350,452 @@ void Midi_InterruptHandler_Update(void)
#endif
}
+
+// ============================================================================
+// Host MIDI I/O
+// ============================================================================
+
+/**
+ * open MIDI streams
+ * return true for no errors
+ */
+static bool Midi_Host_Open(void)
+{
+#ifndef HAVE_PORTMIDI
+ if (!ConfigureParams.Midi.bEnableMidi)
+ return true;
+
+ if (ConfigureParams.Midi.sMidiOutFileName[0])
+ {
+ /* Open MIDI output file */
+ pMidiFhOut = File_Open(ConfigureParams.Midi.sMidiOutFileName, "wb");
+ if (!pMidiFhOut)
+ return false;
+ setvbuf(pMidiFhOut, NULL, _IONBF, 0); /* No output buffering! */
+ LOG_TRACE(TRACE_MIDI, "MIDI: Opened file '%s' for output\n",
+ ConfigureParams.Midi.sMidiOutFileName);
+ }
+ if (ConfigureParams.Midi.sMidiInFileName[0])
+ {
+ /* Try to open MIDI input file */
+ pMidiFhIn = File_Open(ConfigureParams.Midi.sMidiInFileName, "rb");
+ if (!pMidiFhIn)
+ return false;
+ setvbuf(pMidiFhIn, NULL, _IONBF, 0); /* No input buffering! */
+ LOG_TRACE(TRACE_MIDI, "MIDI: Opened file '%s' for input\n",
+ 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;
+
+ 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++)
+ {
+ 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);
+ }
+
+ // -- open input and output ports according to configuration
+ if (ConfigureParams.Midi.sMidiInPortName[0])
+ Midi_Host_SwitchPort(ConfigureParams.Midi.sMidiInPortName, true);
+ if (ConfigureParams.Midi.sMidiOutPortName[0])
+ Midi_Host_SwitchPort(ConfigureParams.Midi.sMidiOutPortName, false);
+#endif
+
+ return true;
+}
+
+
+/* ---------------------------------------------------------------------------- */
+/**
+ * close MIDI streams
+ */
+static void Midi_Host_Close(void)
+{
+#ifndef HAVE_PORTMIDI
+ pMidiFhIn = File_Close(pMidiFhIn);
+ pMidiFhOut = File_Close(pMidiFhOut);
+#else
+ if (midiIn)
+ Pm_Close(midiIn);
+ if (midiOut)
+ Pm_Close(midiOut);
+ midiIn = midiOut = NULL;
+
+ // Can't terminate PM or free descriptor arrays as this gets
+ // called by any write errors and GUI won't then work.
+ // Pm_Terminate();
+#endif
+}
+
+
+
+/* ---------------------------------------------------------------------------- */
+/**
+ * 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'
+ */
+int Midi_Host_GetPortIndex(const char* portName, bool forInput)
+{
+#ifdef HAVE_PORTMIDI
+ int i = 0;
+ int numPorts = forInput ? numInputs : numOutputs;
+ const PmDeviceInfo** ports = forInput ? inports : outports;
+
+ if (ports)
+ {
+ for (i = 0; i < numPorts; i++)
+ if (!strcmp(portName, ports[i]->name))
+ return i;
+ }
+#endif
+
+ return -1;
+}
+
+/**
+ * closes current midi port (if any) and opens 'portName' if MIDI enabled
+ * returns true if successful, false otherwise
+ */
+static bool Midi_Host_SwitchPort(const char* portName, bool forInput)
+{
+#ifdef HAVE_PORTMIDI
+ int i, count;
+ bool err;
+
+ if (!ConfigureParams.Midi.bEnableMidi)
+ return false;
+
+ // -- find PortMidi index for 'portName'
+ count = Pm_CountDevices();
+ for (i = 0; i < count; i++)
+ {
+ const PmDeviceInfo* info = Pm_GetDeviceInfo(i);
+ if (info)
+ {
+ if (forInput && !info->input)
+ continue;
+ else if (!forInput && info->input)
+ continue;
+ if (!strcmp(info->name, portName))
+ break;
+ }
+ }
+ if (i >= count)
+ return false;
+
+ // -- close current port in any case, then try open new one
+ if (forInput == true)
+ {
+ if (midiIn) {
+ Pm_Close(midiIn);
+ midiIn = NULL;
+ }
+ err = (Pm_OpenInput(&midiIn, i, NULL, INPUT_BUFFER_SIZE, NULL, NULL) == pmNoError);
+ LOG_TRACE(TRACE_MIDI, "MIDI: input port %d '%s' open %s\n", i, portName, err ? "succeeded" : "failed");
+ return err;
+ }
+ else
+ {
+ if (midiOut) {
+ Pm_Close(midiOut);
+ midiOut = NULL;
+ }
+ err = (Pm_OpenOutput(&midiOut, i, NULL, 0, NULL, NULL, 0) == pmNoError);
+ LOG_TRACE(TRACE_MIDI, "MIDI: output port %d '%s' open %s\n", i, portName, err ? "succeeded" : "failed");
+ return err;
+ }
+#endif
+ return false;
+}
+
+
+/**
+ * returns byte from input stream, or EOF if it is empty
+ */
+static int Midi_Host_ReadByte(void)
+{
+#ifndef HAVE_PORTMIDI
+ if (pMidiFhIn && File_InputAvailable(pMidiFhIn))
+ return fgetc(pMidiFhIn);
+ else return EOF;
+#else
+ static Uint8 msg[4];
+ static Uint8 ibyte = 0;
+ static int bytesAvailable = 0;
+
+ if (midiIn)
+ {
+ // -- we have not yet returned all bytes from previous event
+ if (bytesAvailable > 0)
+ {
+ bytesAvailable--;
+ return msg[ibyte++];
+ }
+
+ // -- read new event (if any)
+ else if (Pm_Poll(midiIn) == TRUE) {
+ PmEvent midiEvent;
+ if (Pm_Read(midiIn, &midiEvent, 1) != 1)
+ return EOF;
+ if ((bytesAvailable = Midi_SplitEvent(&midiEvent, msg)) > 0)
+ {
+ bytesAvailable--;
+ ibyte = 1;
+ return msg[0];
+ }
+ }
+ }
+
+ // -- no more midi data
+ return EOF;
+#endif
+}
+
+
+/**
+ * writes 'byte' into output stream, returns true on success
+ */
+static bool Midi_Host_WriteByte(Uint8 byte)
+{
+#ifndef HAVE_PORTMIDI
+ if (pMidiFhOut)
+ {
+ /* Write the character to the output file: */
+ int ret = fputc(byte, pMidiFhOut);
+ return (ret != EOF);
+ }
+#else
+ if (midiOut)
+ {
+ PmEvent* midiEvent = Midi_BuildEvent(byte);
+ if (midiEvent)
+ {
+ PmError error = Pm_Write(midiOut, midiEvent, 1);
+ if (error == pmNoError)
+ return true;
+ LOG_TRACE(TRACE_MIDI, "MIDI: PortMidi write error %d\n", error);
+ return false;
+ }
+ return true;
+ }
+#endif
+
+ return false;
+}
+
+
+#ifdef HAVE_PORTMIDI
+// ============================================================================
+// PortMidi utils
+//
+// PortMidi (as most native MIDI APIs) operate on complete MIDI messages
+// we need therefore handle running status, variable number of data bytes
+// and sysex correctly.
+//
+// ============================================================================
+
+/**
+ * return number of databytes that should accompany 'status' byte
+ * four bytes for sysex is a special case to simplify Midi_BuildEvent()
+ */
+static int Midi_GetDataLength(Uint8 status)
+{
+ static const Uint8 dataLength[] = { 2,2,2,2,1,2,2, 4,1,2,1,0,0,0,0 };
+
+ if (status >= 0xF8 || status == 0)
+ return 0;
+ if (status >= 0xF0)
+ return dataLength[(status & 0x0F) + 7];
+ return dataLength[(status >> 4) - 8];
+}
+
+/**
+ * collect bytes until valid MIDI event has been formed / four bytes of sysex data has been gathered
+ * returns PmEvent when done, or NULL if it needs still more data
+ * see MIDI 1.0 Detailed Spec 4.2, pages A-1..A-2 for discussion on running status
+ */
+static PmEvent* Midi_BuildEvent(Uint8 byte)
+{
+ static const Uint8 shifts[] = { 0,8,16,24 };
+ static PmEvent midiEvent = { 0,0 };
+ static Uint32 midimsg;
+ static Uint8 runningStatus = 0;
+ static Uint8 bytesToWait = 0;
+ static Uint8 bytesCollected = 0;
+ static bool processingSysex = false;
+
+ // -- status byte
+ if (byte & 0x80)
+ {
+ if (byte >= 0xF8)
+ {
+ midiEvent.message = Pm_Message(byte,0,0);
+ return &midiEvent;
+ }
+ else
+ {
+ processingSysex = false;
+ if (byte >= 0xF0)
+ {
+ runningStatus = 0;
+ if (byte == 0xF0)
+ {
+ processingSysex = true;
+ bytesCollected = 1;
+ }
+ else if (byte == 0xF7)
+ {
+ midiEvent.message = midimsg | (((Uint32)byte) << shifts[bytesCollected]);
+ midimsg = bytesToWait = bytesCollected = 0;
+ return &midiEvent;
+ }
+ else
+ bytesCollected = 0;
+ }
+ else
+ {
+ runningStatus = byte;
+ bytesCollected = 0;
+ }
+ }
+ midimsg = byte;
+ bytesToWait = Midi_GetDataLength(byte);
+ }
+
+ // -- data byte
+ else
+ {
+ if (processingSysex)
+ midimsg |= ((Uint32)byte) << shifts[bytesCollected++];
+ else
+ midimsg |= ((Uint32)byte) << shifts[++bytesCollected];
+ if (bytesCollected >= bytesToWait)
+ {
+ midiEvent.message = midimsg;
+ midimsg = 0;
+ bytesCollected = 0;
+ bytesToWait = processingSysex ? 4 : 0;
+ return &midiEvent;
+ }
+ }
+
+ return NULL;
+}
+
+
+/**
+ * extracts raw bytes from 'midiEvent' into 'msg'
+ * returns number of bytes available in 'msg'
+ *
+ * this method is required for sysex handling
+ * native framework has already handled running status
+ */
+static int Midi_SplitEvent(PmEvent* midiEvent, Uint8* msg)
+{
+ static bool processingSysex = false;
+ PmMessage midiMessage = midiEvent->message;
+ int i, bytesAvailable = 0;
+
+ msg[0] = Pm_MessageStatus(midiMessage);
+
+ // -- sysex start or continuation
+ if ((msg[0] == 0xF0) || (msg[0] < 0x80))
+ {
+ if (msg[0] == 0xF0)
+ processingSysex = true;
+
+ if (processingSysex)
+ {
+ for (i = 0; i <= 3; i++)
+ {
+ msg[i] = midiMessage & 0xFF;
+ bytesAvailable = i;
+ if (msg[i] == 0xF7)
+ {
+ processingSysex = false;
+ break;
+ }
+ midiMessage >>= 8;
+ }
+ }
+ else bytesAvailable = -1;
+ }
+
+ // -- non-sysex
+ else
+ {
+ if (msg[0] < 0xF8) // non-realtime
+ {
+ processingSysex = false;
+ midiMessage >>= 8;
+ bytesAvailable = Midi_GetDataLength(msg[0]);
+ for (i = 1; i <= bytesAvailable; i++)
+ {
+ msg[i] = midiMessage & 0xFF;
+ midiMessage >>= 8;
+ }
+ }
+ }
+
+ return bytesAvailable + 1;
+}
+#endif
diff --git a/src/options.c b/src/options.c
index 1be4f68..82a48bc 100644
--- a/src/options.c
+++ b/src/options.c
@@ -107,8 +107,12 @@ enum {
OPT_JOYSTICK4,
OPT_JOYSTICK5,
OPT_PRINTER,
+#ifdef HAVE_PORTMIDI
+ OPT_MIDI,
+#else
OPT_MIDI_IN,
OPT_MIDI_OUT,
+#endif
OPT_RS232_IN,
OPT_RS232_OUT,
OPT_DRIVEA, /* disk options */
@@ -308,10 +312,15 @@ static const opt_t HatariOptions[] = {
"<type>", "Set joystick type (none/keys/real) for given port" },
{ OPT_PRINTER, NULL, "--printer",
"<file>", "Enable printer support and write data to <file>" },
+#ifdef HAVE_PORTMIDI
+ { OPT_MIDI, NULL, "--midi",
+ "<bool>", "Whether to use MIDI (with PortMidi devices)" },
+#else
{ OPT_MIDI_IN, NULL, "--midi-in",
"<file>", "Enable MIDI and use <file> as the input device" },
{ OPT_MIDI_OUT, NULL, "--midi-out",
"<file>", "Enable MIDI and use <file> as the output device" },
+#endif
{ OPT_RS232_IN, NULL, "--rs232-in",
"<file>", "Enable serial port and use <file> as the input device" },
{ OPT_RS232_OUT, NULL, "--rs232-out",
@@ -1376,6 +1385,11 @@ bool Opt_ParseParameters(int argc, const char * const argv[])
&ConfigureParams.Printer.bEnablePrinting);
break;
+#ifdef HAVE_PORTMIDI
+ case OPT_MIDI:
+ ok = Opt_Bool(argv[++i], OPT_MIDI, &ConfigureParams.Midi.bEnableMidi);
+ break;
+#else
case OPT_MIDI_IN:
i += 1;
ok = Opt_StrCpy(OPT_MIDI_IN, true, ConfigureParams.Midi.sMidiInFileName,
@@ -1389,7 +1403,8 @@ bool Opt_ParseParameters(int argc, const char * const argv[])
argv[i], sizeof(ConfigureParams.Midi.sMidiOutFileName),
&ConfigureParams.Midi.bEnableMidi);
break;
-
+#endif
+
case OPT_RS232_IN:
i += 1;
ok = Opt_StrCpy(OPT_RS232_IN, true, ConfigureParams.RS232.szInFileName,