commit 459e13975d774605e2ac841ed5791296346d8318
parent 7d116f5046059d1dfb3811be767b183327b858a8
Author: Olav Sørensen <olav.sorensen@live.no>
Date: Tue, 9 Apr 2024 19:31:20 +0200
MIDI init/close refactor (+ disable on WinXP, buggy)
Diffstat:
6 files changed, 162 insertions(+), 108 deletions(-)
diff --git a/src/ft2_config.c b/src/ft2_config.c
@@ -290,7 +290,7 @@ bool loadConfig(bool showErrorFlag)
audio.currInputDevice = getAudioInputDeviceFromConfig();
#ifdef HAS_MIDI
- if (midi.initThreadDone)
+ if (midi.supported && midi.initThreadDone)
{
setMidiInputDeviceFromConfig();
if (ui.configScreenShown && editor.currConfigScreen == CONFIG_SCREEN_MIDI_INPUT)
@@ -390,7 +390,8 @@ bool saveConfig(bool showErrorFlag)
saveAudioDevicesToConfig(audio.currOutputDevice, audio.currInputDevice);
#ifdef HAS_MIDI
- saveMidiInputDeviceToConfig();
+ if (midi.supported)
+ saveMidiInputDeviceToConfig();
#endif
FILE *f = UNICHAR_FOPEN(editor.configFileLocationU, "wb");
@@ -673,7 +674,9 @@ static void setConfigFileLocation(void) // kinda hackish
strcat(editor.configFileLocationU, "/FT2.CFG");
#endif
- editor.midiConfigFileLocationU = getFullMidiDevConfigPathU();
+ if (midi.supported)
+ editor.midiConfigFileLocationU = getFullMidiDevConfigPathU();
+
editor.audioDevConfigFileLocationU = getFullAudDevConfigPathU();
}
@@ -781,6 +784,8 @@ static void setConfigRadioButtonStates(void)
{
uint16_t tmpID;
+
+
uncheckRadioButtonGroup(RB_GROUP_CONFIG_SELECT);
switch (editor.currConfigScreen)
{
@@ -795,6 +800,14 @@ static void setConfigRadioButtonStates(void)
radioButtons[tmpID].state = RADIOBUTTON_CHECKED;
showRadioButtonGroup(RB_GROUP_CONFIG_SELECT);
+
+ // hide MIDI radio button if MIDI is not supported (hackish)
+ if (!midi.supported)
+ {
+ radioButton_t *t = &radioButtons[RB_CONFIG_MIDI_INPUT];
+ hideRadioButton(RB_CONFIG_MIDI_INPUT);
+ fillRect(t->x, t->y, RADIOBUTTON_W, RADIOBUTTON_H, PAL_DESKTOP);
+ }
}
void setConfigAudioRadioButtonStates(void) // accessed by other .c files
@@ -1018,7 +1031,10 @@ static void setConfigMiscCheckButtonStates(void)
checkBoxes[CB_CONF_CHANGE_PATTLEN_INS_DEL].checked = config.recTrueInsert;
checkBoxes[CB_CONF_MIDI_ALLOW_PC].checked = config.recMIDIAllowPC;
#ifdef HAS_MIDI
- checkBoxes[CB_CONF_MIDI_ENABLE].checked = midi.enable;
+ if (midi.supported)
+ checkBoxes[CB_CONF_MIDI_ENABLE].checked = midi.enable;
+ else
+ checkBoxes[CB_CONF_MIDI_ENABLE].checked = false;
#else
checkBoxes[CB_CONF_MIDI_ENABLE].checked = false;
#endif
@@ -1109,7 +1125,8 @@ void showConfigScreen(void)
textOutShadow(21, 35, PAL_FORGRND, PAL_DSKTOP2, "Layout");
textOutShadow(21, 51, PAL_FORGRND, PAL_DSKTOP2, "Miscellaneous");
#ifdef HAS_MIDI
- textOutShadow(21, 67, PAL_FORGRND, PAL_DSKTOP2, "MIDI input");
+ if (midi.supported)
+ textOutShadow(21, 67, PAL_FORGRND, PAL_DSKTOP2, "MIDI input");
#endif
textOutShadow(20, 93, PAL_FORGRND, PAL_DSKTOP2, "Auto save");
@@ -1377,6 +1394,7 @@ void showConfigScreen(void)
}
break;
+#ifdef HAS_MIDI
case CONFIG_SCREEN_MIDI_INPUT:
{
drawFramework(110, 0, 394, 173, FRAMEWORK_TYPE1);
@@ -1387,15 +1405,14 @@ void showConfigScreen(void)
blitFast(517, 51, bmp.midiLogo, 103, 55);
-#ifdef HAS_MIDI
showPushButton(PB_CONFIG_MIDI_INPUT_DOWN);
showPushButton(PB_CONFIG_MIDI_INPUT_UP);
rescanMidiInputDevices();
drawMidiInputList();
showScrollBar(SB_MIDI_INPUT_SCROLL);
-#endif
}
break;
+#endif
}
}
@@ -2072,7 +2089,17 @@ void cbMIDIAllowPC(void)
void cbMIDIEnable(void)
{
#ifdef HAS_MIDI
- midi.enable ^= 1;
+ if (midi.supported)
+ {
+ midi.enable ^= 1;
+ }
+ else
+ {
+ checkBoxes[CB_CONF_MIDI_ENABLE].checked = false;
+ drawCheckBox(CB_CONF_MIDI_ENABLE);
+
+ okBox(0, "System message", "MIDI support is disabled for Windows XP as it is buggy!", NULL);
+ }
#else
checkBoxes[CB_CONF_MIDI_ENABLE].checked = false;
drawCheckBox(CB_CONF_MIDI_ENABLE);
diff --git a/src/ft2_config.h b/src/ft2_config.h
@@ -13,7 +13,9 @@ enum
CONFIG_SCREEN_AUDIO,
CONFIG_SCREEN_LAYOUT,
CONFIG_SCREEN_MISCELLANEOUS,
+#ifdef HAS_MIDI
CONFIG_SCREEN_MIDI_INPUT,
+#endif
CONFIG_HIDE_ERRORS = 0,
CONFIG_SHOW_ERRORS = 1,
diff --git a/src/ft2_keyboard.c b/src/ft2_keyboard.c
@@ -24,6 +24,7 @@
#include "ft2_audio.h"
#include "ft2_trim.h"
#include "ft2_sample_ed_features.h"
+#include "ft2_midi.h"
#include "ft2_structs.h"
keyb_t keyb; // globalized
@@ -1280,16 +1281,18 @@ static bool checkModifiedKeys(SDL_Keycode keycode)
return true;
}
-#ifdef HAS_MIDI
else if (keyb.leftCtrlPressed)
{
- editor.currConfigScreen = 3;
- showConfigScreen();
- checkRadioButton(RB_CONFIG_MIDI_INPUT);
-
+#ifdef HAS_MIDI
+ if (midi.supported)
+ {
+ editor.currConfigScreen = 3;
+ showConfigScreen();
+ checkRadioButton(RB_CONFIG_MIDI_INPUT);
+ }
+#endif
return true;
}
-#endif
}
break;
diff --git a/src/ft2_main.c b/src/ft2_main.c
@@ -9,6 +9,7 @@
#ifdef _WIN32
#define WIN32_MEAN_AND_LEAN
#include <windows.h>
+#include <versionhelpers.h>
#include <SDL2/SDL_syswm.h>
#else
#include <unistd.h> // chdir()
@@ -35,10 +36,6 @@
#include "ft2_structs.h"
#include "ft2_hpc.h"
-#ifdef HAS_MIDI
-static SDL_Thread *initMidiThread;
-#endif
-
static void initializeVars(void);
static void cleanUpAndExit(void); // never call this inside the main loop
#ifdef __APPLE__
@@ -99,6 +96,10 @@ int main(int argc, char *argv[])
#endif
#ifdef _WIN32
+ // disable MIDI support if using Windows XP, as it is unstable
+ if (!IsWindowsVistaOrGreater())
+ midi.supported = false;
+
#ifndef _MSC_VER
SetProcessDPIAware();
#endif
@@ -231,14 +232,16 @@ int main(int argc, char *argv[])
#ifdef HAS_MIDI
// set up MIDI input (in a thread because it can take quite a while on f.ex. macOS)
- initMidiThread = SDL_CreateThread(initMidiFunc, NULL, NULL);
- if (initMidiThread == NULL)
+ if (midi.supported)
{
- showErrorMsgBox("Couldn't create MIDI initialization thread!");
- cleanUpAndExit();
- return 1;
+ midi.initMidiThread = SDL_CreateThread(initMidiFunc, NULL, NULL);
+ if (midi.initMidiThread == NULL)
+ {
+ showErrorMsgBox("Couldn't create MIDI initialization thread!");
+ cleanUpAndExit();
+ return 1;
+ }
}
- SDL_DetachThread(initMidiThread); // don't wait for this thread, let it clean up when done
#endif
hpc_ResetCounters(&video.vblankHpc); // quirk: this is needed for potential okBox() calls in handleModuleLoadFromArg()
@@ -271,6 +274,10 @@ static void initializeVars(void)
cpu.hasSSE2 = SDL_HasSSE2();
// clear common structs
+#ifdef HAS_MIDI
+ memset(&midi, 0, sizeof (midi));
+ midi.supported = true;
+#endif
memset(&video, 0, sizeof (video));
memset(&keyb, 0, sizeof (keyb));
memset(&mouse, 0, sizeof (mouse));
@@ -289,7 +296,7 @@ static void initializeVars(void)
// now set data that must be initialized to non-zero values...
- audio.locked = true;
+ audio.locked = true; // XXX: Why..?
audio.rescanAudioDevicesSupported = true;
// set non-zero values
@@ -305,7 +312,7 @@ static void initializeVars(void)
editor.srcInstr = 1;
editor.curInstr = 1;
editor.curOctave = 4;
- editor.smpEd_NoteNr = 48 + 1; // middle-C
+ editor.smpEd_NoteNr = 1+NOTE_C4;
editor.ptnJumpPos[0] = 0x00;
editor.ptnJumpPos[1] = 0x10;
@@ -316,25 +323,41 @@ static void initializeVars(void)
memset(editor.copyMask, 1, sizeof (editor.copyMask));
memset(editor.pasteMask, 1, sizeof (editor.pasteMask));
-#ifdef HAS_MIDI
- midi.enable = true;
-#endif
-
editor.diskOpReadOnOpen = true;
audio.linearPeriodsFlag = true;
calcReplayerLogTab();
+#ifdef HAS_MIDI
+ midi.enable = true;
+#endif
+
editor.programRunning = true;
}
static void cleanUpAndExit(void) // never call this inside the main loop!
{
#ifdef HAS_MIDI
- if (midi.closeMidiOnExit)
+ if (midi.supported)
{
+ if (midi.initMidiThread != NULL)
+ {
+ SDL_WaitThread(midi.initMidiThread, NULL);
+ midi.initMidiThread = NULL;
+ }
+
+ midi.enable = false; // stop MIDI callback from doing things
+ while (midi.callbackBusy) SDL_Delay(1); // wait for MIDI callback to finish
+
closeMidiInDevice();
freeMidiIn();
+ freeMidiInputDeviceList();
+
+ if (midi.inputDeviceName != NULL)
+ {
+ free(midi.inputDeviceName);
+ midi.inputDeviceName = NULL;
+ }
}
#endif
@@ -345,22 +368,11 @@ static void cleanUpAndExit(void) // never call this inside the main loop!
freeDiskOp();
clearCopyBuffer();
freeAudioDeviceSelectorBuffers();
-#ifdef HAS_MIDI
- freeMidiInputDeviceList();
-#endif
windUpFTHelp();
freeTextBoxes();
freeMouseCursors();
freeBMPs();
-#ifdef HAS_MIDI
- if (midi.inputDeviceName != NULL)
- {
- free(midi.inputDeviceName);
- midi.inputDeviceName = NULL;
- }
-#endif
-
if (editor.audioDevConfigFileLocationU != NULL)
{
free(editor.audioDevConfigFileLocationU);
@@ -396,7 +408,7 @@ static void cleanUpAndExit(void) // never call this inside the main loop!
static void osxSetDirToProgramDirFromArgs(char **argv)
{
/* OS X/macOS: hackish way of setting the current working directory to the place where we double clicked
- ** on the icon (for protracker.ini loading)
+ ** on the icon (for FT2.CFG loading)
*/
// if we launched from the terminal, argv[0][0] would be '.'
diff --git a/src/ft2_midi.c b/src/ft2_midi.c
@@ -1,3 +1,5 @@
+// this implements MIDI input only!
+
#ifdef HAS_MIDI
// for finding memory leaks in debug mode with Visual Studio
@@ -18,20 +20,16 @@
#include "ft2_structs.h"
#include "rtmidi/rtmidi_c.h"
-#define MAX_DEV_STR_LEN 256
-
// hide POSIX warnings
#ifdef _MSC_VER
#pragma warning(disable: 4996)
#endif
-// This implements MIDI input only!
-
midi_t midi; // globalized
static volatile bool midiDeviceOpened;
static bool recMIDIValidChn = true;
-static RtMidiPtr midiDev;
+static RtMidiPtr midiInDev;
static inline void midiInSetChannel(uint8_t status)
{
@@ -97,13 +95,15 @@ static inline void midiInPitchBendChange(uint8_t data1, uint8_t data2)
}
}
-static void midiInCallback(double dTimeStamp, const unsigned char *message, size_t messageSize, void *userData)
+static void midiInCallback(double timeStamp, const unsigned char *message, size_t messageSize, void *userData)
{
uint8_t byte[3];
if (!midi.enable || messageSize < 2)
return;
+ midi.callbackBusy = true;
+
byte[0] = message[0];
if (byte[0] > 127 && byte[0] < 240)
{
@@ -122,25 +122,27 @@ static void midiInCallback(double dTimeStamp, const unsigned char *message, size
else if (byte[0] >= 224 && byte[0] <= 224+15) midiInPitchBendChange(byte[1], byte[2]);
}
- (void)dTimeStamp;
+ midi.callbackBusy = false;
+
+ (void)timeStamp;
(void)userData;
}
static uint32_t getNumMidiInDevices(void)
{
- if (midiDev == NULL)
+ if (midiInDev == NULL)
return 0;
- return rtmidi_get_port_count(midiDev);
+ return rtmidi_get_port_count(midiInDev);
}
static char *getMidiInDeviceName(uint32_t deviceID)
{
- if (midiDev == NULL)
- return NULL;
+ if (midiInDev == NULL)
+ return NULL; // MIDI not initialized
- char *devStr = (char *)rtmidi_get_port_name(midiDev, deviceID);
- if (!midiDev->ok)
+ char *devStr = (char *)rtmidi_get_port_name(midiInDev, deviceID);
+ if (devStr == NULL || !midiInDev->ok)
return NULL;
return devStr;
@@ -148,14 +150,12 @@ static char *getMidiInDeviceName(uint32_t deviceID)
void closeMidiInDevice(void)
{
- while (!midi.initThreadDone);
-
if (midiDeviceOpened)
{
- if (midiDev != NULL)
+ if (midiInDev != NULL)
{
- rtmidi_in_cancel_callback(midiDev);
- rtmidi_close_port(midiDev);
+ rtmidi_in_cancel_callback(midiInDev);
+ rtmidi_close_port(midiInDev);
}
midiDeviceOpened = false;
@@ -164,51 +164,48 @@ void closeMidiInDevice(void)
void freeMidiIn(void)
{
- while (!midi.initThreadDone);
-
- if (midiDev != NULL)
+ if (midiInDev != NULL)
{
- rtmidi_in_free(midiDev);
- midiDev = NULL;
+ rtmidi_in_free(midiInDev);
+ midiInDev = NULL;
}
}
bool initMidiIn(void)
{
- if (midiDev != NULL)
- return false; // already initialized
+ midiInDev = rtmidi_in_create_default();
+ if (midiInDev == NULL)
+ return false;
- midiDev = rtmidi_in_create_default();
- if (!midiDev->ok)
+ if (!midiInDev->ok)
{
- midiDev = NULL;
+ rtmidi_in_free(midiInDev);
return false;
}
- midiDeviceOpened = false;
return true;
}
bool openMidiInDevice(uint32_t deviceID)
{
- if (midiDev == NULL)
+ if (midiDeviceOpened)
return false;
- if (getNumMidiInDevices() == 0)
+ if (midiInDev == NULL || getNumMidiInDevices() == 0)
return false;
- rtmidi_open_port(midiDev, deviceID, "FT2 Clone MIDI Port");
- if (!midiDev->ok)
+ rtmidi_open_port(midiInDev, deviceID, "FT2 Clone MIDI Port");
+ if (!midiInDev->ok)
return false;
- rtmidi_in_set_callback(midiDev, midiInCallback, NULL);
- if (!midiDev->ok)
+ rtmidi_in_set_callback(midiInDev, midiInCallback, NULL);
+ if (!midiInDev->ok)
{
- rtmidi_close_port(midiDev);
+ rtmidi_close_port(midiInDev);
return false;
}
- rtmidi_in_ignore_types(midiDev, true, true, true);
+ rtmidi_in_ignore_types(midiInDev, true, true, true);
midiDeviceOpened = true;
return true;
@@ -255,7 +252,7 @@ void recordMIDIEffect(uint8_t efx, uint8_t efxData)
bool saveMidiInputDeviceToConfig(void)
{
- if (!midi.initThreadDone || midiDev == NULL || !midiDeviceOpened)
+ if (!midi.initThreadDone || midiInDev == NULL || !midiDeviceOpened)
return false;
const uint32_t numDevices = getNumMidiInDevices();
@@ -284,8 +281,10 @@ bool setMidiInputDeviceFromConfig(void)
{
uint32_t i;
- if (midi.inputDeviceName != NULL)
- free(midi.inputDeviceName);
+ // XXX: Something in here is corrupting!
+
+ if (editor.midiConfigFileLocationU == NULL)
+ goto setDefMidiInputDev;
const uint32_t numDevices = getNumMidiInDevices();
if (numDevices == 0)
@@ -295,16 +294,15 @@ bool setMidiInputDeviceFromConfig(void)
if (f == NULL)
goto setDefMidiInputDev;
- char *devString = (char *)malloc((MAX_DEV_STR_LEN+4) * sizeof (char));
+ char *devString = (char *)malloc(1024+2);
if (devString == NULL)
{
fclose(f);
goto setDefMidiInputDev;
}
-
devString[0] = '\0';
- if (fgets(devString, MAX_DEV_STR_LEN, f) == NULL)
+ if (fgets(devString, 1024, f) == NULL)
{
fclose(f);
free(devString);
@@ -334,6 +332,12 @@ bool setMidiInputDeviceFromConfig(void)
if (i == numDevices)
goto setDefMidiInputDev;
+ if (midi.inputDeviceName != NULL)
+ {
+ free(midi.inputDeviceName);
+ midi.inputDeviceName = NULL;
+ }
+
midi.inputDevice = i;
midi.inputDeviceName = midiInStr;
midi.numInputDevices = numDevices;
@@ -342,9 +346,15 @@ bool setMidiInputDeviceFromConfig(void)
// couldn't load device, set default
setDefMidiInputDev:
+ if (midi.inputDeviceName != NULL)
+ {
+ free(midi.inputDeviceName);
+ midi.inputDeviceName = NULL;
+ }
+
midi.inputDevice = 0;
midi.inputDeviceName = strdup("RtMidi");
- midi.numInputDevices = numDevices;
+ midi.numInputDevices = 1;
return false;
}
@@ -371,7 +381,7 @@ void rescanMidiInputDevices(void)
if (midi.numInputDevices > MAX_MIDI_DEVICES)
midi.numInputDevices = MAX_MIDI_DEVICES;
- for (int32_t i = 0; i < midi.numInputDevices; i++)
+ for (uint32_t i = 0; i < midi.numInputDevices; i++)
{
char *deviceName = getMidiInDeviceName(i);
if (deviceName == NULL)
@@ -393,7 +403,7 @@ void drawMidiInputList(void)
{
clearRect(114, 4, 365, 165);
- if (!midi.initThreadDone || midiDev == NULL || midi.numInputDevices == 0)
+ if (!midi.initThreadDone || midiInDev == NULL || midi.numInputDevices == 0)
{
textOut(114, 4 + (0 * 11), PAL_FORGRND, "No MIDI input devices found!");
textOut(114, 4 + (1 * 11), PAL_FORGRND, "Either wait a few seconds for MIDI to initialize, or restart the");
@@ -403,7 +413,10 @@ void drawMidiInputList(void)
for (uint16_t i = 0; i < 15; i++)
{
- const int32_t deviceEntry = getScrollBarPos(SB_MIDI_INPUT_SCROLL) + i;
+ uint32_t deviceEntry = getScrollBarPos(SB_MIDI_INPUT_SCROLL) + i;
+ if (deviceEntry > MAX_MIDI_DEVICES)
+ deviceEntry = MAX_MIDI_DEVICES;
+
if (deviceEntry < midi.numInputDevices)
{
if (midi.inputDeviceNames[deviceEntry] == NULL)
@@ -448,19 +461,19 @@ void sbMidiInputSetPos(uint32_t pos)
bool testMidiInputDeviceListMouseDown(void)
{
if (!ui.configScreenShown || editor.currConfigScreen != CONFIG_SCREEN_MIDI_INPUT)
- return false; // we didn't click the area
+ return false;
+
+ if (mouse.x < 114 || mouse.x > 479 || mouse.y < 4 || mouse.y > 166)
+ return false; // we didn't click inside the list area
if (!midi.initThreadDone)
return true;
- const int32_t mx = mouse.x;
- const int32_t my = mouse.y;
+ uint32_t deviceNum = (uint32_t)scrollBars[SB_MIDI_INPUT_SCROLL].pos + ((mouse.y - 4) / 11);
+ if (deviceNum > MAX_MIDI_DEVICES)
+ deviceNum = MAX_MIDI_DEVICES;
- if (my < 4 || my > 166 || mx < 114 || mx > 479)
- return false; // we didn't click the area
-
- const int32_t deviceNum = (int32_t)scrollBars[SB_MIDI_INPUT_SCROLL].pos + ((my - 4) / 11);
- if (midi.numInputDevices <= 0 || deviceNum >= midi.numInputDevices)
+ if (midi.numInputDevices == 0 || deviceNum >= midi.numInputDevices)
return true;
if (midi.inputDeviceName != NULL)
@@ -469,6 +482,7 @@ bool testMidiInputDeviceListMouseDown(void)
return true; // we clicked the currently selected device, do nothing
free(midi.inputDeviceName);
+ midi.inputDeviceName = NULL;
}
midi.inputDeviceName = strdup(midi.inputDeviceNames[deviceNum]);
@@ -485,21 +499,17 @@ bool testMidiInputDeviceListMouseDown(void)
int32_t SDLCALL initMidiFunc(void *ptr)
{
- midi.closeMidiOnExit = true;
-
midi.initThreadDone = false;
initMidiIn();
setMidiInputDeviceFromConfig();
openMidiInDevice(midi.inputDevice);
- midi.initThreadDone = true;
-
midi.rescanDevicesFlag = true;
-
+ midi.initThreadDone = true;
return true;
(void)ptr;
}
#else
-typedef int make_iso_compilers_happy; // kludge: prevent warning about empty .c file if HAS_MIDI is not defined
+typedef int prevent_compiler_warning; // kludge: prevent warning about empty .c file if HAS_MIDI is not defined
#endif
diff --git a/src/ft2_midi.h b/src/ft2_midi.h
@@ -12,11 +12,11 @@
typedef struct midi_t
{
char *inputDeviceName, *inputDeviceNames[MAX_MIDI_DEVICES];
- volatile bool closeMidiOnExit, initThreadDone;
- uint32_t inputDevice;
- bool enable, rescanDevicesFlag;
+ volatile bool supported, initThreadDone, callbackBusy, enable;
+ bool rescanDevicesFlag;
+ uint32_t inputDevice, numInputDevices;
int16_t currMIDIVibDepth, currMIDIPitch;
- int32_t numInputDevices;
+ SDL_Thread *initMidiThread;
} midi_t;
extern midi_t midi; // ft2_midi.c