Add MIDI support

This commit is contained in:
Zoran Vuckovic 2018-06-04 07:48:08 +02:00
parent 0045e1fff2
commit b487c3cace
32 changed files with 1832 additions and 7 deletions

View File

@ -264,6 +264,8 @@ OBJ += frontend/frontend.o \
$(LIBRETRO_COMM_DIR)/features/features_cpu.o \ $(LIBRETRO_COMM_DIR)/features/features_cpu.o \
performance_counters.o \ performance_counters.o \
verbosity.o \ verbosity.o \
midi/midi_driver.o \
midi/drivers/null_midi.o
ifeq ($(HAVE_RUNAHEAD), 1) ifeq ($(HAVE_RUNAHEAD), 1)
DEFINES += -DHAVE_RUNAHEAD DEFINES += -DHAVE_RUNAHEAD
@ -686,6 +688,12 @@ ifeq ($(HAVE_XAUDIO), 1)
LIBS += -lole32 LIBS += -lole32
endif endif
ifeq ($(HAVE_WINMM), 1)
OBJ += midi/drivers/winmm_midi.o
DEFINES += -DHAVE_WINMM
LIBS += -lwinmm
endif
# Audio Resamplers # Audio Resamplers
ifeq ($(HAVE_NEON),1) ifeq ($(HAVE_NEON),1)

View File

@ -25,6 +25,7 @@ HAVE_XAUDIO := 1
HAVE_XINPUT := 1 HAVE_XINPUT := 1
HAVE_WASAPI := 0 HAVE_WASAPI := 0
HAVE_THREAD_STORAGE := 1 HAVE_THREAD_STORAGE := 1
HAVE_WINMM := 1
HAVE_RPNG := 1 HAVE_RPNG := 1
HAVE_ZLIB := 1 HAVE_ZLIB := 1

View File

@ -18,6 +18,7 @@ HAVE_PYTHON = 0
DYNAMIC = 1 DYNAMIC = 1
HAVE_XINPUT = 1 HAVE_XINPUT = 1
HAVE_WINMM = 1
HAVE_SDL := 0 HAVE_SDL := 0
HAVE_SDL2 := 0 HAVE_SDL2 := 0

View File

@ -26,6 +26,7 @@
#include <string/stdstring.h> #include <string/stdstring.h>
#include <streams/file_stream.h> #include <streams/file_stream.h>
#include <streams/stdin_stream.h> #include <streams/stdin_stream.h>
#include <midi/midi_driver.h>
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include "config.h" #include "config.h"
@ -2040,6 +2041,7 @@ TODO: Add a setting for these tweaks */
command_event_save_auto_state(); command_event_save_auto_state();
break; break;
case CMD_EVENT_AUDIO_STOP: case CMD_EVENT_AUDIO_STOP:
midi_driver_set_all_sounds_off();
return audio_driver_stop(); return audio_driver_stop();
case CMD_EVENT_AUDIO_START: case CMD_EVENT_AUDIO_START:
return audio_driver_start(rarch_ctl(RARCH_CTL_IS_SHUTDOWN, NULL)); return audio_driver_start(rarch_ctl(RARCH_CTL_IS_SHUTDOWN, NULL));

View File

@ -689,6 +689,11 @@ static enum resampler_quality audio_resampler_quality_level = RESAMPLER_QUALITY_
static enum resampler_quality audio_resampler_quality_level = RESAMPLER_QUALITY_NORMAL; static enum resampler_quality audio_resampler_quality_level = RESAMPLER_QUALITY_NORMAL;
#endif #endif
/* MIDI */
static const char *midi_input = "Off";
static const char *midi_output = "Off";
static const unsigned midi_volume = 100;
#if defined(ANDROID) #if defined(ANDROID)
#if defined(ANDROID_ARM) #if defined(ANDROID_ARM)
static char buildbot_server_url[] = "http://buildbot.libretro.com/nightly/android/latest/armeabi-v7a/"; static char buildbot_server_url[] = "http://buildbot.libretro.com/nightly/android/latest/armeabi-v7a/";

View File

@ -52,6 +52,8 @@
#include "tasks/tasks_internal.h" #include "tasks/tasks_internal.h"
#include "../list_special.h"
static const char* invalid_filename_chars[] = { static const char* invalid_filename_chars[] = {
/* https://support.microsoft.com/en-us/help/905231/information-about-the-characters-that-you-cannot-use-in-site-names--fo */ /* https://support.microsoft.com/en-us/help/905231/information-about-the-characters-that-you-cannot-use-in-site-names--fo */
"~", "#", "%", "&", "*", "{", "}", "\\", ":", "[", "]", "?", "/", "|", "\'", "\"", "~", "#", "%", "&", "*", "{", "}", "\\", ":", "[", "]", "?", "/", "|", "\'", "\"",
@ -281,6 +283,11 @@ enum record_driver_enum
RECORD_NULL RECORD_NULL
}; };
enum midi_driver_enum
{
MIDI_WINMM = RECORD_NULL + 1,
MIDI_NULL
};
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) || defined(__CELLOS_LV2__) #if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) || defined(__CELLOS_LV2__)
static enum video_driver_enum VIDEO_DEFAULT_DRIVER = VIDEO_GL; static enum video_driver_enum VIDEO_DEFAULT_DRIVER = VIDEO_GL;
@ -386,6 +393,12 @@ static enum record_driver_enum RECORD_DEFAULT_DRIVER = RECORD_FFMPEG;
static enum record_driver_enum RECORD_DEFAULT_DRIVER = RECORD_NULL; static enum record_driver_enum RECORD_DEFAULT_DRIVER = RECORD_NULL;
#endif #endif
#ifdef HAVE_WINMM
static enum midi_driver_enum MIDI_DEFAULT_DRIVER = MIDI_WINMM;
#else
static enum midi_driver_enum MIDI_DEFAULT_DRIVER = MIDI_NULL;
#endif
#if defined(XENON) #if defined(XENON)
static enum input_driver_enum INPUT_DEFAULT_DRIVER = INPUT_XENON360; static enum input_driver_enum INPUT_DEFAULT_DRIVER = INPUT_XENON360;
#elif defined(_XBOX360) || defined(_XBOX) || defined(HAVE_XINPUT2) || defined(HAVE_XINPUT_XBOX1) #elif defined(_XBOX360) || defined(_XBOX) || defined(HAVE_XINPUT2) || defined(HAVE_XINPUT_XBOX1)
@ -1005,6 +1018,26 @@ const char *config_get_default_menu(void)
return "null"; return "null";
} }
const char *config_get_default_midi(void)
{
enum midi_driver_enum default_driver = MIDI_DEFAULT_DRIVER;
switch (default_driver)
{
case MIDI_WINMM:
return "winmm";
case MIDI_NULL:
break;
}
return "null";
}
const char *config_get_midi_driver_options(void)
{
return char_list_new_special(STRING_LIST_MIDI_DRIVERS, NULL);
}
bool config_overlay_enable_default(void) bool config_overlay_enable_default(void)
{ {
if (g_defaults.overlay.set) if (g_defaults.overlay.set)
@ -1046,6 +1079,9 @@ static struct config_array_setting *populate_settings_array(settings_t *settings
SETTING_ARRAY("bundle_assets_dst_path_subdir", settings->arrays.bundle_assets_dst_subdir, false, NULL, true); SETTING_ARRAY("bundle_assets_dst_path_subdir", settings->arrays.bundle_assets_dst_subdir, false, NULL, true);
SETTING_ARRAY("led_driver", settings->arrays.led_driver, false, NULL, true); SETTING_ARRAY("led_driver", settings->arrays.led_driver, false, NULL, true);
SETTING_ARRAY("netplay_mitm_server", settings->arrays.netplay_mitm_server, false, NULL, true); SETTING_ARRAY("netplay_mitm_server", settings->arrays.netplay_mitm_server, false, NULL, true);
SETTING_ARRAY("midi_driver", settings->arrays.midi_driver, false, NULL, true);
SETTING_ARRAY("midi_input", settings->arrays.midi_input, true, midi_input, true);
SETTING_ARRAY("midi_output", settings->arrays.midi_output, true, midi_output, true);
*size = count; *size = count;
return tmp; return tmp;
@ -1532,6 +1568,8 @@ static struct config_uint_setting *populate_settings_uint(settings_t *settings,
SETTING_UINT("run_ahead_frames", &settings->uints.run_ahead_frames, true, 1, false); SETTING_UINT("run_ahead_frames", &settings->uints.run_ahead_frames, true, 1, false);
SETTING_UINT("midi_volume", &settings->uints.midi_volume, true, midi_volume, false);
*size = count; *size = count;
return tmp; return tmp;
@ -1585,6 +1623,7 @@ static void config_set_defaults(void)
const char *def_led = config_get_default_led(); const char *def_led = config_get_default_led();
const char *def_location = config_get_default_location(); const char *def_location = config_get_default_location();
const char *def_record = config_get_default_record(); const char *def_record = config_get_default_record();
const char *def_midi = config_get_default_midi();
const char *def_mitm = netplay_mitm_server; const char *def_mitm = netplay_mitm_server;
struct config_float_setting *float_settings = populate_settings_float (settings, &float_settings_size); struct config_float_setting *float_settings = populate_settings_float (settings, &float_settings_size);
struct config_bool_setting *bool_settings = populate_settings_bool (settings, &bool_settings_size); struct config_bool_setting *bool_settings = populate_settings_bool (settings, &bool_settings_size);
@ -1665,6 +1704,9 @@ static void config_set_defaults(void)
if (def_record) if (def_record)
strlcpy(settings->arrays.record_driver, strlcpy(settings->arrays.record_driver,
def_record, sizeof(settings->arrays.record_driver)); def_record, sizeof(settings->arrays.record_driver));
if (def_midi)
strlcpy(settings->arrays.midi_driver,
def_midi, sizeof(settings->arrays.midi_driver));
if (def_mitm) if (def_mitm)
strlcpy(settings->arrays.netplay_mitm_server, strlcpy(settings->arrays.netplay_mitm_server,
def_mitm, sizeof(settings->arrays.netplay_mitm_server)); def_mitm, sizeof(settings->arrays.netplay_mitm_server));
@ -1982,6 +2024,13 @@ static void config_set_defaults(void)
free(temp_str); free(temp_str);
} }
if (midi_input)
strlcpy(settings->arrays.midi_input,
midi_input, sizeof(settings->arrays.midi_input));
if (midi_output)
strlcpy(settings->arrays.midi_output,
midi_output, sizeof(settings->arrays.midi_output));
/* Avoid reloading config on every content load */ /* Avoid reloading config on every content load */
if (default_block_config_read) if (default_block_config_read)
rarch_ctl(RARCH_CTL_SET_BLOCK_CONFIG_READ, NULL); rarch_ctl(RARCH_CTL_SET_BLOCK_CONFIG_READ, NULL);

View File

@ -403,6 +403,8 @@ typedef struct settings
unsigned led_map[MAX_LEDS]; unsigned led_map[MAX_LEDS];
unsigned run_ahead_frames; unsigned run_ahead_frames;
unsigned midi_volume;
} uints; } uints;
struct struct
@ -424,6 +426,7 @@ typedef struct settings
char audio_resampler[32]; char audio_resampler[32];
char input_driver[32]; char input_driver[32];
char input_joypad_driver[32]; char input_joypad_driver[32];
char midi_driver[32];
char input_keyboard_layout[64]; char input_keyboard_layout[64];
@ -437,6 +440,9 @@ typedef struct settings
char bundle_assets_dst_subdir[PATH_MAX_LENGTH]; char bundle_assets_dst_subdir[PATH_MAX_LENGTH];
char netplay_mitm_server[255]; char netplay_mitm_server[255];
char midi_input[32];
char midi_output[32];
} arrays; } arrays;
struct struct
@ -583,6 +589,9 @@ const char *config_get_default_joypad(void);
**/ **/
const char *config_get_default_menu(void); const char *config_get_default_menu(void);
const char *config_get_default_midi(void);
const char *config_get_midi_driver_options(void);
const char *config_get_default_record(void); const char *config_get_default_record(void);
/** /**

View File

@ -38,6 +38,7 @@
#include "location/location_driver.h" #include "location/location_driver.h"
#include "wifi/wifi_driver.h" #include "wifi/wifi_driver.h"
#include "led/led_driver.h" #include "led/led_driver.h"
#include "midi/midi_driver.h"
#include "configuration.h" #include "configuration.h"
#include "core.h" #include "core.h"
#include "core_info.h" #include "core_info.h"
@ -113,6 +114,12 @@ static const void *find_driver_nonempty(const char *label, int i,
if (drv) if (drv)
strlcpy(s, record_driver_find_ident(i), len); strlcpy(s, record_driver_find_ident(i), len);
} }
else if (string_is_equal(label, "midi_driver"))
{
drv = midi_driver_find_handle(i);
if (drv)
strlcpy(s, midi_driver_find_ident(i), len);
}
else if (string_is_equal(label, "audio_resampler_driver")) else if (string_is_equal(label, "audio_resampler_driver"))
{ {
drv = audio_resampler_driver_find_handle(i); drv = audio_resampler_driver_find_handle(i);
@ -396,6 +403,9 @@ void drivers_init(int flags)
{ {
led_driver_init(); led_driver_init();
} }
if (flags & DRIVER_MIDI_MASK)
midi_driver_init();
} }
@ -459,6 +469,9 @@ void driver_uninit(int flags)
if ((flags & DRIVER_AUDIO_MASK) && !audio_driver_owns_driver()) if ((flags & DRIVER_AUDIO_MASK) && !audio_driver_owns_driver())
audio_driver_destroy_data(); audio_driver_destroy_data();
if (flags & DRIVER_MIDI_MASK)
midi_driver_free();
} }
bool driver_ctl(enum driver_ctl_state state, void *data) bool driver_ctl(enum driver_ctl_state state, void *data)

View File

@ -35,7 +35,8 @@ RETRO_BEGIN_DECLS
| DRIVER_MENU_MASK \ | DRIVER_MENU_MASK \
| DRIVERS_VIDEO_INPUT_MASK \ | DRIVERS_VIDEO_INPUT_MASK \
| DRIVER_WIFI_MASK \ | DRIVER_WIFI_MASK \
| DRIVER_LED_MASK ) | DRIVER_LED_MASK \
| DRIVER_MIDI_MASK )
#define DRIVERS_CMD_ALL_BUT_MENU \ #define DRIVERS_CMD_ALL_BUT_MENU \
( DRIVER_AUDIO_MASK \ ( DRIVER_AUDIO_MASK \
@ -45,7 +46,8 @@ RETRO_BEGIN_DECLS
| DRIVER_LOCATION_MASK \ | DRIVER_LOCATION_MASK \
| DRIVERS_VIDEO_INPUT_MASK \ | DRIVERS_VIDEO_INPUT_MASK \
| DRIVER_WIFI_MASK \ | DRIVER_WIFI_MASK \
| DRIVER_LED_MASK ) | DRIVER_LED_MASK \
| DRIVER_MIDI_MASK )
enum enum
{ {
@ -57,7 +59,8 @@ enum
DRIVER_MENU, DRIVER_MENU,
DRIVERS_VIDEO_INPUT, DRIVERS_VIDEO_INPUT,
DRIVER_WIFI, DRIVER_WIFI,
DRIVER_LED DRIVER_LED,
DRIVER_MIDI
}; };
enum enum
@ -70,7 +73,8 @@ enum
DRIVER_MENU_MASK = 1 << DRIVER_MENU, DRIVER_MENU_MASK = 1 << DRIVER_MENU,
DRIVERS_VIDEO_INPUT_MASK = 1 << DRIVERS_VIDEO_INPUT, DRIVERS_VIDEO_INPUT_MASK = 1 << DRIVERS_VIDEO_INPUT,
DRIVER_WIFI_MASK = 1 << DRIVER_WIFI, DRIVER_WIFI_MASK = 1 << DRIVER_WIFI,
DRIVER_LED_MASK = 1 << DRIVER_LED DRIVER_LED_MASK = 1 << DRIVER_LED,
DRIVER_MIDI_MASK = 1 << DRIVER_MIDI
}; };
enum driver_ctl_state enum driver_ctl_state

View File

@ -55,6 +55,7 @@
#include "performance_counters.h" #include "performance_counters.h"
#include "gfx/video_driver.h" #include "gfx/video_driver.h"
#include "led/led_driver.h" #include "led/led_driver.h"
#include "midi/midi_driver.h"
#include "cores/internal_cores.h" #include "cores/internal_cores.h"
#include "frontend/frontend_driver.h" #include "frontend/frontend_driver.h"
@ -1778,6 +1779,22 @@ bool rarch_environment_cb(unsigned cmd, void *data)
} }
} }
break; break;
case RETRO_ENVIRONMENT_GET_MIDI_INTERFACE:
{
struct retro_midi_interface *midi_interface =
(struct retro_midi_interface *)data;
if (midi_interface)
{
midi_interface->input_enabled = midi_driver_input_enabled;
midi_interface->output_enabled = midi_driver_output_enabled;
midi_interface->read = midi_driver_read;
midi_interface->write = midi_driver_write;
midi_interface->flush = midi_driver_flush;
}
}
break;
default: default:
RARCH_LOG("Environ UNSUPPORTED (#%u).\n", cmd); RARCH_LOG("Environ UNSUPPORTED (#%u).\n", cmd);

View File

@ -333,6 +333,8 @@ MSG_HASH(MENU_ENUM_LABEL_DEFERRED_PLAYLIST_SETTINGS_LIST,
"deferred_playlist_settings") "deferred_playlist_settings")
MSG_HASH(MENU_ENUM_LABEL_DEFERRED_PRIVACY_SETTINGS_LIST, MSG_HASH(MENU_ENUM_LABEL_DEFERRED_PRIVACY_SETTINGS_LIST,
"deferred_privacy_settings_list") "deferred_privacy_settings_list")
MSG_HASH(MENU_ENUM_LABEL_DEFERRED_MIDI_SETTINGS_LIST,
"deferred_midi_settings_list")
MSG_HASH(MENU_ENUM_LABEL_DEFERRED_RDB_ENTRY_DETAIL, MSG_HASH(MENU_ENUM_LABEL_DEFERRED_RDB_ENTRY_DETAIL,
"deferred_rdb_entry_detail") "deferred_rdb_entry_detail")
MSG_HASH(MENU_ENUM_LABEL_DEFERRED_RECORDING_SETTINGS_LIST, MSG_HASH(MENU_ENUM_LABEL_DEFERRED_RECORDING_SETTINGS_LIST,
@ -789,6 +791,8 @@ MSG_HASH(MENU_ENUM_LABEL_POINTER_ENABLE,
"menu_pointer_enable") "menu_pointer_enable")
MSG_HASH(MENU_ENUM_LABEL_PRIVACY_SETTINGS, MSG_HASH(MENU_ENUM_LABEL_PRIVACY_SETTINGS,
"privacy_settings") "privacy_settings")
MSG_HASH(MENU_ENUM_LABEL_MIDI_SETTINGS,
"midi_settings")
MSG_HASH(MENU_ENUM_LABEL_QUIT_RETROARCH, MSG_HASH(MENU_ENUM_LABEL_QUIT_RETROARCH,
"quit_retroarch") "quit_retroarch")
MSG_HASH(MENU_ENUM_LABEL_RDB_ENTRY, MSG_HASH(MENU_ENUM_LABEL_RDB_ENTRY,
@ -889,6 +893,8 @@ MSG_HASH(MENU_ENUM_LABEL_RECORD_CONFIG,
"record_config") "record_config")
MSG_HASH(MENU_ENUM_LABEL_RECORD_DRIVER, MSG_HASH(MENU_ENUM_LABEL_RECORD_DRIVER,
"record_driver") "record_driver")
MSG_HASH(MENU_ENUM_LABEL_MIDI_DRIVER,
"midi_driver")
MSG_HASH(MENU_ENUM_LABEL_RECORD_ENABLE, MSG_HASH(MENU_ENUM_LABEL_RECORD_ENABLE,
"record_enable") "record_enable")
MSG_HASH(MENU_ENUM_LABEL_RECORD_PATH, MSG_HASH(MENU_ENUM_LABEL_RECORD_PATH,
@ -1517,3 +1523,9 @@ MSG_HASH(MENU_ENUM_LABEL_DEFERRED_QUICK_MENU_OVERRIDE_OPTIONS,
"deferred_quick_menu_override_options") "deferred_quick_menu_override_options")
MSG_HASH(MENU_ENUM_LABEL_DISCORD_IN_MENU, MSG_HASH(MENU_ENUM_LABEL_DISCORD_IN_MENU,
"discord_in_menu") "discord_in_menu")
MSG_HASH(MENU_ENUM_LABEL_MIDI_INPUT,
"midi_input")
MSG_HASH(MENU_ENUM_LABEL_MIDI_OUTPUT,
"midi_output")
MSG_HASH(MENU_ENUM_LABEL_MIDI_VOLUME,
"midi_volume")

View File

@ -2037,6 +2037,30 @@ int menu_hash_get_help_us_enum(enum msg_hash_enums msg, char *s, size_t len)
snprintf(s, len, snprintf(s, len,
"Sets the blue value of the OSD text color. Valid values are between 0 and 255."); "Sets the blue value of the OSD text color. Valid values are between 0 and 255.");
break; break;
case MENU_ENUM_LABEL_MIDI_DRIVER:
snprintf(s, len,
"MIDI driver to use.");
break;
case MENU_ENUM_LABEL_MIDI_INPUT:
snprintf(s, len,
"Sets the input device (driver specific).\n"
"When set to \"Off\", MIDI input will be disabled.\n"
"Device name can also be typed in.");
break;
case MENU_ENUM_LABEL_MIDI_OUTPUT:
snprintf(s, len,
"Sets the output device (driver specific).\n"
"When set to \"Off\", MIDI output will be disabled.\n"
"Device name can also be typed in.\n"
" \n"
"When MIDI output is enabled and core and game/app support MIDI output,\n"
"some or all sounds (depends on game/app) will be generated by MIDI device.\n"
"In case of \"null\" MIDI driver this means that those sounds won't be audible.");
break;
case MENU_ENUM_LABEL_MIDI_VOLUME:
snprintf(s, len,
"Sets the master volume of the output device.");
break;
default: default:
if (string_is_empty(s)) if (string_is_empty(s))
strlcpy(s, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_INFORMATION_AVAILABLE), len); strlcpy(s, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_INFORMATION_AVAILABLE), len);

View File

@ -1261,6 +1261,8 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_PRESENT,
"Present") "Present")
MSG_HASH(MENU_ENUM_LABEL_VALUE_PRIVACY_SETTINGS, MSG_HASH(MENU_ENUM_LABEL_VALUE_PRIVACY_SETTINGS,
"Privacy") "Privacy")
MSG_HASH(MENU_ENUM_LABEL_VALUE_MIDI_SETTINGS,
"MIDI")
MSG_HASH(MENU_ENUM_LABEL_VALUE_QUIT_RETROARCH, MSG_HASH(MENU_ENUM_LABEL_VALUE_QUIT_RETROARCH,
"Quit RetroArch") "Quit RetroArch")
MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_ANALOG, MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_ANALOG,
@ -1331,6 +1333,8 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_RECORD_CONFIG,
"Load Recording Config...") "Load Recording Config...")
MSG_HASH(MENU_ENUM_LABEL_VALUE_RECORD_DRIVER, MSG_HASH(MENU_ENUM_LABEL_VALUE_RECORD_DRIVER,
"Record Driver") "Record Driver")
MSG_HASH(MENU_ENUM_LABEL_VALUE_MIDI_DRIVER,
"MIDI Driver")
MSG_HASH(MENU_ENUM_LABEL_VALUE_RECORD_ENABLE, MSG_HASH(MENU_ENUM_LABEL_VALUE_RECORD_ENABLE,
"Enable Recording") "Enable Recording")
MSG_HASH(MENU_ENUM_LABEL_VALUE_RECORD_PATH, MSG_HASH(MENU_ENUM_LABEL_VALUE_RECORD_PATH,
@ -1977,6 +1981,8 @@ MSG_HASH(MENU_ENUM_SUBLABEL_USER_SETTINGS,
"Change account, username, and language settings.") "Change account, username, and language settings.")
MSG_HASH(MENU_ENUM_SUBLABEL_PRIVACY_SETTINGS, MSG_HASH(MENU_ENUM_SUBLABEL_PRIVACY_SETTINGS,
"Change your privacy settings.") "Change your privacy settings.")
MSG_HASH(MENU_ENUM_SUBLABEL_MIDI_SETTINGS,
"Change MIDI settings.")
MSG_HASH(MENU_ENUM_SUBLABEL_DIRECTORY_SETTINGS, MSG_HASH(MENU_ENUM_SUBLABEL_DIRECTORY_SETTINGS,
"Change default directories where files are located.") "Change default directories where files are located.")
MSG_HASH(MENU_ENUM_SUBLABEL_PLAYLIST_SETTINGS, MSG_HASH(MENU_ENUM_SUBLABEL_PLAYLIST_SETTINGS,
@ -2864,6 +2870,10 @@ MSG_HASH(
MENU_ENUM_SUBLABEL_RECORD_DRIVER, MENU_ENUM_SUBLABEL_RECORD_DRIVER,
"Record driver to use." "Record driver to use."
) )
MSG_HASH(
MENU_ENUM_SUBLABEL_MIDI_DRIVER,
"MIDI driver to use."
)
MSG_HASH( MSG_HASH(
MENU_ENUM_SUBLABEL_WIFI_DRIVER, MENU_ENUM_SUBLABEL_WIFI_DRIVER,
"WiFi driver to use." "WiFi driver to use."
@ -3726,3 +3736,15 @@ MSG_HASH(
MENU_ENUM_SUBLABEL_DISCORD_ALLOW, MENU_ENUM_SUBLABEL_DISCORD_ALLOW,
"Enable or disable Discord support. Will not work with the browser version, only native desktop client." "Enable or disable Discord support. Will not work with the browser version, only native desktop client."
) )
MSG_HASH(MENU_ENUM_LABEL_VALUE_MIDI_INPUT,
"Input")
MSG_HASH(MENU_ENUM_SUBLABEL_MIDI_INPUT,
"Select input device.")
MSG_HASH(MENU_ENUM_LABEL_VALUE_MIDI_OUTPUT,
"Output")
MSG_HASH(MENU_ENUM_SUBLABEL_MIDI_OUTPUT,
"Select output device.")
MSG_HASH(MENU_ENUM_LABEL_VALUE_MIDI_VOLUME,
"Volume")
MSG_HASH(MENU_ENUM_SUBLABEL_MIDI_VOLUME,
"Set output volume (%).")

View File

@ -1163,6 +1163,23 @@ struct retro_led_interface
* * State will never be saved when using Hard Disable Audio. * * State will never be saved when using Hard Disable Audio.
*/ */
#define RETRO_ENVIRONMENT_GET_MIDI_INTERFACE (48 | RETRO_ENVIRONMENT_EXPERIMENTAL)
typedef bool (RETRO_CALLCONV *retro_midi_input_enabled_t)(void);
typedef bool (RETRO_CALLCONV *retro_midi_output_enabled_t)(void);
typedef bool (RETRO_CALLCONV *retro_midi_read_t)(uint8_t *byte);
typedef bool (RETRO_CALLCONV *retro_midi_write_t)(uint8_t byte, uint32_t delta_time);
typedef bool (RETRO_CALLCONV *retro_midi_flush_t)(void);
struct retro_midi_interface
{
retro_midi_input_enabled_t input_enabled;
retro_midi_output_enabled_t output_enabled;
retro_midi_read_t read;
retro_midi_write_t write;
retro_midi_flush_t flush;
};
#define RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE (41 | RETRO_ENVIRONMENT_EXPERIMENTAL) #define RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE (41 | RETRO_ENVIRONMENT_EXPERIMENTAL)
/* const struct retro_hw_render_interface ** -- /* const struct retro_hw_render_interface ** --
* Returns an API specific rendering interface for accessing API specific data. * Returns an API specific rendering interface for accessing API specific data.

View File

@ -50,6 +50,7 @@
#include "input/input_driver.h" #include "input/input_driver.h"
#include "audio/audio_driver.h" #include "audio/audio_driver.h"
#include "record/record_driver.h" #include "record/record_driver.h"
#include "midi/midi_driver.h"
#include "configuration.h" #include "configuration.h"
struct string_list *dir_list_new_special(const char *input_dir, struct string_list *dir_list_new_special(const char *input_dir,
@ -274,6 +275,15 @@ struct string_list *string_list_new_special(enum string_list_type type,
string_list_append(s, opt, attr); string_list_append(s, opt, attr);
} }
break; break;
case STRING_LIST_MIDI_DRIVERS:
for (i = 0; midi_driver_find_handle(i); i++)
{
const char *opt = midi_driver_find_ident(i);
*len += strlen(opt) + 1;
string_list_append(s, opt, attr);
}
break;
case STRING_LIST_SUPPORTED_CORES_PATHS: case STRING_LIST_SUPPORTED_CORES_PATHS:
core_info_get_list(&core_info_list); core_info_get_list(&core_info_list);

View File

@ -53,6 +53,7 @@ enum string_list_type
STRING_LIST_INPUT_JOYPAD_DRIVERS, STRING_LIST_INPUT_JOYPAD_DRIVERS,
STRING_LIST_INPUT_HID_DRIVERS, STRING_LIST_INPUT_HID_DRIVERS,
STRING_LIST_RECORD_DRIVERS, STRING_LIST_RECORD_DRIVERS,
STRING_LIST_MIDI_DRIVERS,
STRING_LIST_SUPPORTED_CORES_PATHS, STRING_LIST_SUPPORTED_CORES_PATHS,
STRING_LIST_SUPPORTED_CORES_NAMES STRING_LIST_SUPPORTED_CORES_NAMES
}; };

View File

@ -155,6 +155,7 @@ generic_deferred_push(deferred_push_lakka_services_list, DISPLAYLIST_
generic_deferred_push(deferred_push_user_settings_list, DISPLAYLIST_USER_SETTINGS_LIST) generic_deferred_push(deferred_push_user_settings_list, DISPLAYLIST_USER_SETTINGS_LIST)
generic_deferred_push(deferred_push_directory_settings_list, DISPLAYLIST_DIRECTORY_SETTINGS_LIST) generic_deferred_push(deferred_push_directory_settings_list, DISPLAYLIST_DIRECTORY_SETTINGS_LIST)
generic_deferred_push(deferred_push_privacy_settings_list, DISPLAYLIST_PRIVACY_SETTINGS_LIST) generic_deferred_push(deferred_push_privacy_settings_list, DISPLAYLIST_PRIVACY_SETTINGS_LIST)
generic_deferred_push(deferred_push_midi_settings_list, DISPLAYLIST_MIDI_SETTINGS_LIST)
generic_deferred_push(deferred_push_audio_settings_list, DISPLAYLIST_AUDIO_SETTINGS_LIST) generic_deferred_push(deferred_push_audio_settings_list, DISPLAYLIST_AUDIO_SETTINGS_LIST)
generic_deferred_push(deferred_push_audio_mixer_settings_list, DISPLAYLIST_AUDIO_MIXER_SETTINGS_LIST) generic_deferred_push(deferred_push_audio_mixer_settings_list, DISPLAYLIST_AUDIO_MIXER_SETTINGS_LIST)
generic_deferred_push(deferred_push_input_settings_list, DISPLAYLIST_INPUT_SETTINGS_LIST) generic_deferred_push(deferred_push_input_settings_list, DISPLAYLIST_INPUT_SETTINGS_LIST)
@ -731,6 +732,12 @@ static int menu_cbs_init_bind_deferred_push_compare_label(
return 0; return 0;
} }
else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_MIDI_SETTINGS_LIST)))
{
BIND_ACTION_DEFERRED_PUSH(cbs, deferred_push_midi_settings_list);
return 0;
}
else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_CORE_CONTENT_DIRS_LIST))) else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_CORE_CONTENT_DIRS_LIST)))
{ {
#ifdef HAVE_NETWORKING #ifdef HAVE_NETWORKING

View File

@ -1971,6 +1971,7 @@ static int menu_cbs_init_bind_get_string_representation_compare_label(
case MENU_ENUM_LABEL_JOYPAD_DRIVER: case MENU_ENUM_LABEL_JOYPAD_DRIVER:
case MENU_ENUM_LABEL_AUDIO_RESAMPLER_DRIVER: case MENU_ENUM_LABEL_AUDIO_RESAMPLER_DRIVER:
case MENU_ENUM_LABEL_RECORD_DRIVER: case MENU_ENUM_LABEL_RECORD_DRIVER:
case MENU_ENUM_LABEL_MIDI_DRIVER:
case MENU_ENUM_LABEL_LOCATION_DRIVER: case MENU_ENUM_LABEL_LOCATION_DRIVER:
case MENU_ENUM_LABEL_CAMERA_DRIVER: case MENU_ENUM_LABEL_CAMERA_DRIVER:
case MENU_ENUM_LABEL_WIFI_DRIVER: case MENU_ENUM_LABEL_WIFI_DRIVER:

View File

@ -316,6 +316,8 @@ static enum msg_hash_enums action_ok_dl_to_enum(unsigned lbl)
return MENU_ENUM_LABEL_DEFERRED_DIRECTORY_SETTINGS_LIST; return MENU_ENUM_LABEL_DEFERRED_DIRECTORY_SETTINGS_LIST;
case ACTION_OK_DL_PRIVACY_SETTINGS_LIST: case ACTION_OK_DL_PRIVACY_SETTINGS_LIST:
return MENU_ENUM_LABEL_DEFERRED_PRIVACY_SETTINGS_LIST; return MENU_ENUM_LABEL_DEFERRED_PRIVACY_SETTINGS_LIST;
case ACTION_OK_DL_MIDI_SETTINGS_LIST:
return MENU_ENUM_LABEL_DEFERRED_MIDI_SETTINGS_LIST;
case ACTION_OK_DL_AUDIO_SETTINGS_LIST: case ACTION_OK_DL_AUDIO_SETTINGS_LIST:
return MENU_ENUM_LABEL_DEFERRED_AUDIO_SETTINGS_LIST; return MENU_ENUM_LABEL_DEFERRED_AUDIO_SETTINGS_LIST;
case ACTION_OK_DL_AUDIO_MIXER_SETTINGS_LIST: case ACTION_OK_DL_AUDIO_MIXER_SETTINGS_LIST:
@ -842,6 +844,7 @@ int generic_action_ok_displaylist_push(const char *path,
case ACTION_OK_DL_USER_SETTINGS_LIST: case ACTION_OK_DL_USER_SETTINGS_LIST:
case ACTION_OK_DL_DIRECTORY_SETTINGS_LIST: case ACTION_OK_DL_DIRECTORY_SETTINGS_LIST:
case ACTION_OK_DL_PRIVACY_SETTINGS_LIST: case ACTION_OK_DL_PRIVACY_SETTINGS_LIST:
case ACTION_OK_DL_MIDI_SETTINGS_LIST:
case ACTION_OK_DL_AUDIO_SETTINGS_LIST: case ACTION_OK_DL_AUDIO_SETTINGS_LIST:
case ACTION_OK_DL_AUDIO_MIXER_SETTINGS_LIST: case ACTION_OK_DL_AUDIO_MIXER_SETTINGS_LIST:
case ACTION_OK_DL_INPUT_HOTKEY_BINDS_LIST: case ACTION_OK_DL_INPUT_HOTKEY_BINDS_LIST:
@ -3420,6 +3423,7 @@ default_action_ok_func(action_ok_user_list, ACTION_OK_DL_USER_SETTINGS_LIST)
default_action_ok_func(action_ok_netplay_sublist, ACTION_OK_DL_NETPLAY) default_action_ok_func(action_ok_netplay_sublist, ACTION_OK_DL_NETPLAY)
default_action_ok_func(action_ok_directory_list, ACTION_OK_DL_DIRECTORY_SETTINGS_LIST) default_action_ok_func(action_ok_directory_list, ACTION_OK_DL_DIRECTORY_SETTINGS_LIST)
default_action_ok_func(action_ok_privacy_list, ACTION_OK_DL_PRIVACY_SETTINGS_LIST) default_action_ok_func(action_ok_privacy_list, ACTION_OK_DL_PRIVACY_SETTINGS_LIST)
default_action_ok_func(action_ok_midi_list, ACTION_OK_DL_MIDI_SETTINGS_LIST)
default_action_ok_func(action_ok_rdb_entry, ACTION_OK_DL_RDB_ENTRY) default_action_ok_func(action_ok_rdb_entry, ACTION_OK_DL_RDB_ENTRY)
default_action_ok_func(action_ok_mixer_stream_actions, ACTION_OK_DL_MIXER_STREAM_SETTINGS_LIST) default_action_ok_func(action_ok_mixer_stream_actions, ACTION_OK_DL_MIXER_STREAM_SETTINGS_LIST)
default_action_ok_func(action_ok_browse_url_list, ACTION_OK_DL_BROWSE_URL_LIST) default_action_ok_func(action_ok_browse_url_list, ACTION_OK_DL_BROWSE_URL_LIST)
@ -4662,6 +4666,9 @@ static int menu_cbs_init_bind_ok_compare_label(menu_file_list_cbs_t *cbs,
case MENU_ENUM_LABEL_PRIVACY_SETTINGS: case MENU_ENUM_LABEL_PRIVACY_SETTINGS:
BIND_ACTION_OK(cbs, action_ok_privacy_list); BIND_ACTION_OK(cbs, action_ok_privacy_list);
break; break;
case MENU_ENUM_LABEL_MIDI_SETTINGS:
BIND_ACTION_OK(cbs, action_ok_midi_list);
break;
case MENU_ENUM_LABEL_SCREEN_RESOLUTION: case MENU_ENUM_LABEL_SCREEN_RESOLUTION:
BIND_ACTION_OK(cbs, action_ok_video_resolution); BIND_ACTION_OK(cbs, action_ok_video_resolution);
break; break;

View File

@ -75,6 +75,7 @@ default_sublabel_macro(action_bind_sublabel_saving_settings_list, MENU_
default_sublabel_macro(action_bind_sublabel_logging_settings_list, MENU_ENUM_SUBLABEL_LOGGING_SETTINGS) default_sublabel_macro(action_bind_sublabel_logging_settings_list, MENU_ENUM_SUBLABEL_LOGGING_SETTINGS)
default_sublabel_macro(action_bind_sublabel_user_interface_settings_list, MENU_ENUM_SUBLABEL_USER_INTERFACE_SETTINGS) default_sublabel_macro(action_bind_sublabel_user_interface_settings_list, MENU_ENUM_SUBLABEL_USER_INTERFACE_SETTINGS)
default_sublabel_macro(action_bind_sublabel_privacy_settings_list, MENU_ENUM_SUBLABEL_PRIVACY_SETTINGS) default_sublabel_macro(action_bind_sublabel_privacy_settings_list, MENU_ENUM_SUBLABEL_PRIVACY_SETTINGS)
default_sublabel_macro(action_bind_sublabel_midi_settings_list, MENU_ENUM_SUBLABEL_MIDI_SETTINGS)
default_sublabel_macro(action_bind_sublabel_directory_settings_list, MENU_ENUM_SUBLABEL_DIRECTORY_SETTINGS) default_sublabel_macro(action_bind_sublabel_directory_settings_list, MENU_ENUM_SUBLABEL_DIRECTORY_SETTINGS)
default_sublabel_macro(action_bind_sublabel_playlist_settings_list, MENU_ENUM_SUBLABEL_PLAYLIST_SETTINGS) default_sublabel_macro(action_bind_sublabel_playlist_settings_list, MENU_ENUM_SUBLABEL_PLAYLIST_SETTINGS)
default_sublabel_macro(action_bind_sublabel_network_settings_list, MENU_ENUM_SUBLABEL_NETWORK_SETTINGS) default_sublabel_macro(action_bind_sublabel_network_settings_list, MENU_ENUM_SUBLABEL_NETWORK_SETTINGS)
@ -222,6 +223,7 @@ default_sublabel_macro(action_bind_sublabel_camera_driver, MENU_
default_sublabel_macro(action_bind_sublabel_location_driver, MENU_ENUM_SUBLABEL_LOCATION_DRIVER) default_sublabel_macro(action_bind_sublabel_location_driver, MENU_ENUM_SUBLABEL_LOCATION_DRIVER)
default_sublabel_macro(action_bind_sublabel_menu_driver, MENU_ENUM_SUBLABEL_MENU_DRIVER) default_sublabel_macro(action_bind_sublabel_menu_driver, MENU_ENUM_SUBLABEL_MENU_DRIVER)
default_sublabel_macro(action_bind_sublabel_record_driver, MENU_ENUM_SUBLABEL_RECORD_DRIVER) default_sublabel_macro(action_bind_sublabel_record_driver, MENU_ENUM_SUBLABEL_RECORD_DRIVER)
default_sublabel_macro(action_bind_sublabel_midi_driver, MENU_ENUM_SUBLABEL_MIDI_DRIVER)
default_sublabel_macro(action_bind_sublabel_wifi_driver, MENU_ENUM_SUBLABEL_WIFI_DRIVER) default_sublabel_macro(action_bind_sublabel_wifi_driver, MENU_ENUM_SUBLABEL_WIFI_DRIVER)
default_sublabel_macro(action_bind_sublabel_filter_supported_extensions, MENU_ENUM_SUBLABEL_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE) default_sublabel_macro(action_bind_sublabel_filter_supported_extensions, MENU_ENUM_SUBLABEL_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE)
default_sublabel_macro(action_bind_sublabel_wallpaper, MENU_ENUM_SUBLABEL_MENU_WALLPAPER) default_sublabel_macro(action_bind_sublabel_wallpaper, MENU_ENUM_SUBLABEL_MENU_WALLPAPER)
@ -421,6 +423,9 @@ default_sublabel_macro(action_bind_sublabel_netplay_mitm_server,
default_sublabel_macro(action_bind_sublabel_core_delete, MENU_ENUM_SUBLABEL_CORE_DELETE) default_sublabel_macro(action_bind_sublabel_core_delete, MENU_ENUM_SUBLABEL_CORE_DELETE)
default_sublabel_macro(action_bind_sublabel_pause_hardcode_mode, MENU_ENUM_SUBLABEL_ACHIEVEMENT_PAUSE) default_sublabel_macro(action_bind_sublabel_pause_hardcode_mode, MENU_ENUM_SUBLABEL_ACHIEVEMENT_PAUSE)
default_sublabel_macro(action_bind_sublabel_resume_hardcode_mode, MENU_ENUM_SUBLABEL_ACHIEVEMENT_RESUME) default_sublabel_macro(action_bind_sublabel_resume_hardcode_mode, MENU_ENUM_SUBLABEL_ACHIEVEMENT_RESUME)
default_sublabel_macro(action_bind_sublabel_midi_input, MENU_ENUM_SUBLABEL_MIDI_INPUT)
default_sublabel_macro(action_bind_sublabel_midi_output, MENU_ENUM_SUBLABEL_MIDI_OUTPUT)
default_sublabel_macro(action_bind_sublabel_midi_volume, MENU_ENUM_SUBLABEL_MIDI_VOLUME)
static int action_bind_sublabel_cheevos_entry( static int action_bind_sublabel_cheevos_entry(
file_list_t *list, file_list_t *list,
@ -1256,6 +1261,9 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs,
case MENU_ENUM_LABEL_RECORD_DRIVER: case MENU_ENUM_LABEL_RECORD_DRIVER:
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_record_driver); BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_record_driver);
break; break;
case MENU_ENUM_LABEL_MIDI_DRIVER:
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_midi_driver);
break;
case MENU_ENUM_LABEL_MENU_DRIVER: case MENU_ENUM_LABEL_MENU_DRIVER:
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_menu_driver); BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_menu_driver);
break; break;
@ -1680,6 +1688,9 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs,
case MENU_ENUM_LABEL_PRIVACY_SETTINGS: case MENU_ENUM_LABEL_PRIVACY_SETTINGS:
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_privacy_settings_list); BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_privacy_settings_list);
break; break;
case MENU_ENUM_LABEL_MIDI_SETTINGS:
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_midi_settings_list);
break;
case MENU_ENUM_LABEL_DIRECTORY_SETTINGS: case MENU_ENUM_LABEL_DIRECTORY_SETTINGS:
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_directory_settings_list); BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_directory_settings_list);
break; break;
@ -1758,6 +1769,15 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs,
case MENU_ENUM_LABEL_ACHIEVEMENT_RESUME: case MENU_ENUM_LABEL_ACHIEVEMENT_RESUME:
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_resume_hardcode_mode); BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_resume_hardcode_mode);
break; break;
case MENU_ENUM_LABEL_MIDI_INPUT:
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_midi_input);
break;
case MENU_ENUM_LABEL_MIDI_OUTPUT:
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_midi_output);
break;
case MENU_ENUM_LABEL_MIDI_VOLUME:
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_midi_volume);
break;
default: default:
case MSG_UNKNOWN: case MSG_UNKNOWN:
return -1; return -1;

View File

@ -133,6 +133,7 @@ default_title_macro(action_get_lakka_services_list, MENU_ENUM_LABEL_
default_title_macro(action_get_user_settings_list, MENU_ENUM_LABEL_VALUE_USER_SETTINGS) default_title_macro(action_get_user_settings_list, MENU_ENUM_LABEL_VALUE_USER_SETTINGS)
default_title_macro(action_get_directory_settings_list, MENU_ENUM_LABEL_VALUE_DIRECTORY_SETTINGS) default_title_macro(action_get_directory_settings_list, MENU_ENUM_LABEL_VALUE_DIRECTORY_SETTINGS)
default_title_macro(action_get_privacy_settings_list, MENU_ENUM_LABEL_VALUE_PRIVACY_SETTINGS) default_title_macro(action_get_privacy_settings_list, MENU_ENUM_LABEL_VALUE_PRIVACY_SETTINGS)
default_title_macro(action_get_midi_settings_list, MENU_ENUM_LABEL_VALUE_MIDI_SETTINGS)
default_title_macro(action_get_updater_settings_list, MENU_ENUM_LABEL_VALUE_UPDATER_SETTINGS) default_title_macro(action_get_updater_settings_list, MENU_ENUM_LABEL_VALUE_UPDATER_SETTINGS)
default_title_macro(action_get_audio_settings_list, MENU_ENUM_LABEL_VALUE_AUDIO_SETTINGS) default_title_macro(action_get_audio_settings_list, MENU_ENUM_LABEL_VALUE_AUDIO_SETTINGS)
default_title_macro(action_get_audio_mixer_settings_list, MENU_ENUM_LABEL_VALUE_AUDIO_MIXER_SETTINGS) default_title_macro(action_get_audio_mixer_settings_list, MENU_ENUM_LABEL_VALUE_AUDIO_MIXER_SETTINGS)
@ -448,6 +449,11 @@ static int menu_cbs_init_bind_title_compare_label(menu_file_list_cbs_t *cbs,
BIND_ACTION_GET_TITLE(cbs, action_get_privacy_settings_list); BIND_ACTION_GET_TITLE(cbs, action_get_privacy_settings_list);
return 0; return 0;
} }
else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_MIDI_SETTINGS_LIST)))
{
BIND_ACTION_GET_TITLE(cbs, action_get_midi_settings_list);
return 0;
}
else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_CORE_CONTENT_DIRS_LIST))) else if (string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_CORE_CONTENT_DIRS_LIST)))
{ {
BIND_ACTION_GET_TITLE(cbs, action_get_download_core_content_list); BIND_ACTION_GET_TITLE(cbs, action_get_download_core_content_list);

View File

@ -2679,6 +2679,8 @@ static void materialui_list_insert(void *userdata,
|| ||
string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_PRIVACY_SETTINGS)) string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_PRIVACY_SETTINGS))
|| ||
string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_MIDI_SETTINGS))
||
string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_MENU_VIEWS_SETTINGS)) string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_MENU_VIEWS_SETTINGS))
|| ||
string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_QUICK_MENU_VIEWS_SETTINGS)) string_is_equal(label, msg_hash_to_str(MENU_ENUM_LABEL_QUICK_MENU_VIEWS_SETTINGS))

View File

@ -127,6 +127,7 @@ enum
ACTION_OK_DL_USER_SETTINGS_LIST, ACTION_OK_DL_USER_SETTINGS_LIST,
ACTION_OK_DL_DIRECTORY_SETTINGS_LIST, ACTION_OK_DL_DIRECTORY_SETTINGS_LIST,
ACTION_OK_DL_PRIVACY_SETTINGS_LIST, ACTION_OK_DL_PRIVACY_SETTINGS_LIST,
ACTION_OK_DL_MIDI_SETTINGS_LIST,
ACTION_OK_DL_BROWSE_URL_START, ACTION_OK_DL_BROWSE_URL_START,
ACTION_OK_DL_CONTENT_SETTINGS ACTION_OK_DL_CONTENT_SETTINGS
}; };

View File

@ -4966,6 +4966,9 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, void *data)
ret = menu_displaylist_parse_settings_enum(menu, info, ret = menu_displaylist_parse_settings_enum(menu, info,
MENU_ENUM_LABEL_RECORD_DRIVER, MENU_ENUM_LABEL_RECORD_DRIVER,
PARSE_ONLY_STRING_OPTIONS, false); PARSE_ONLY_STRING_OPTIONS, false);
ret = menu_displaylist_parse_settings_enum(menu, info,
MENU_ENUM_LABEL_MIDI_DRIVER,
PARSE_ONLY_STRING_OPTIONS, false);
#ifdef HAVE_LAKKA #ifdef HAVE_LAKKA
ret = menu_displaylist_parse_settings_enum(menu, info, ret = menu_displaylist_parse_settings_enum(menu, info,
MENU_ENUM_LABEL_WIFI_DRIVER, MENU_ENUM_LABEL_WIFI_DRIVER,
@ -5942,6 +5945,22 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, void *data)
MENU_ENUM_LABEL_NO_SETTINGS_FOUND, MENU_ENUM_LABEL_NO_SETTINGS_FOUND,
0, 0, 0); 0, 0, 0);
info->need_refresh = true;
info->need_push = true;
break;
case DISPLAYLIST_MIDI_SETTINGS_LIST:
menu_entries_ctl(MENU_ENTRIES_CTL_CLEAR, info->list);
menu_displaylist_parse_settings_enum(menu, info,
MENU_ENUM_LABEL_MIDI_INPUT,
PARSE_ONLY_STRING, false);
menu_displaylist_parse_settings_enum(menu, info,
MENU_ENUM_LABEL_MIDI_OUTPUT,
PARSE_ONLY_STRING, false);
menu_displaylist_parse_settings_enum(menu, info,
MENU_ENUM_LABEL_MIDI_VOLUME,
PARSE_ONLY_UINT, false);
info->need_refresh = true; info->need_refresh = true;
info->need_push = true; info->need_push = true;
break; break;
@ -6365,6 +6384,8 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, void *data)
MENU_ENUM_LABEL_DIRECTORY_SETTINGS, PARSE_ACTION, false); MENU_ENUM_LABEL_DIRECTORY_SETTINGS, PARSE_ACTION, false);
ret = menu_displaylist_parse_settings_enum(menu, info, ret = menu_displaylist_parse_settings_enum(menu, info,
MENU_ENUM_LABEL_PRIVACY_SETTINGS, PARSE_ACTION, false); MENU_ENUM_LABEL_PRIVACY_SETTINGS, PARSE_ACTION, false);
ret = menu_displaylist_parse_settings_enum(menu, info,
MENU_ENUM_LABEL_MIDI_SETTINGS, PARSE_ACTION, false);
info->need_push = true; info->need_push = true;
break; break;
case DISPLAYLIST_HORIZONTAL: case DISPLAYLIST_HORIZONTAL:

View File

@ -141,6 +141,7 @@ enum menu_displaylist_ctl_state
DISPLAYLIST_USER_SETTINGS_LIST, DISPLAYLIST_USER_SETTINGS_LIST,
DISPLAYLIST_DIRECTORY_SETTINGS_LIST, DISPLAYLIST_DIRECTORY_SETTINGS_LIST,
DISPLAYLIST_PRIVACY_SETTINGS_LIST, DISPLAYLIST_PRIVACY_SETTINGS_LIST,
DISPLAYLIST_MIDI_SETTINGS_LIST,
DISPLAYLIST_RECORDING_SETTINGS_LIST, DISPLAYLIST_RECORDING_SETTINGS_LIST,
DISPLAYLIST_PLAYLIST_SETTINGS_LIST, DISPLAYLIST_PLAYLIST_SETTINGS_LIST,
DISPLAYLIST_ACCOUNTS_CHEEVOS_LIST, DISPLAYLIST_ACCOUNTS_CHEEVOS_LIST,

View File

@ -76,6 +76,7 @@
#include "../record/record_driver.h" #include "../record/record_driver.h"
#include "../audio/audio_driver.h" #include "../audio/audio_driver.h"
#include "../input/input_driver.h" #include "../input/input_driver.h"
#include "../midi/midi_driver.h"
#include "../tasks/tasks_internal.h" #include "../tasks/tasks_internal.h"
#include "../config.def.h" #include "../config.def.h"
#include "../ui/ui_companion_driver.h" #include "../ui/ui_companion_driver.h"
@ -122,7 +123,8 @@ enum settings_list_type
SETTINGS_LIST_USER_ACCOUNTS, SETTINGS_LIST_USER_ACCOUNTS,
SETTINGS_LIST_USER_ACCOUNTS_CHEEVOS, SETTINGS_LIST_USER_ACCOUNTS_CHEEVOS,
SETTINGS_LIST_DIRECTORY, SETTINGS_LIST_DIRECTORY,
SETTINGS_LIST_PRIVACY SETTINGS_LIST_PRIVACY,
SETTINGS_LIST_MIDI
}; };
struct bool_entry struct bool_entry
@ -347,6 +349,90 @@ static int setting_string_action_right_driver(void *data,
return 0; return 0;
} }
int setting_string_action_left_midi_input(void *data, bool wraparound)
{
struct string_list *list = midi_driver_get_avail_inputs();
if (list && list->size > 1)
{
rarch_setting_t *setting = (rarch_setting_t*)data;
int i = string_list_find_elem(list, setting->value.target.string) - 2;
if (wraparound && i == -1)
i = (int)list->size - 1;
if (i >= 0)
{
strlcpy(setting->value.target.string, list->elems[i].data, setting->size);
return 0;
}
}
return -1;
}
int setting_string_action_right_midi_input(void *data, bool wraparound)
{
struct string_list *list = midi_driver_get_avail_inputs();
if (list && list->size > 1)
{
rarch_setting_t *setting = (rarch_setting_t*)data;
int i = string_list_find_elem(list, setting->value.target.string);
if (wraparound && i == (int)list->size)
i = 0;
if (i >= 0 && i < (int)list->size)
{
strlcpy(setting->value.target.string, list->elems[i].data, setting->size);
return 0;
}
}
return -1;
}
int setting_string_action_left_midi_output(void *data, bool wraparound)
{
struct string_list *list = midi_driver_get_avail_outputs();
if (list && list->size > 1)
{
rarch_setting_t *setting = (rarch_setting_t*)data;
int i = string_list_find_elem(list, setting->value.target.string) - 2;
if (wraparound && i == -1)
i = (int)list->size - 1;
if (i >= 0)
{
strlcpy(setting->value.target.string, list->elems[i].data, setting->size);
return 0;
}
}
return -1;
}
int setting_string_action_right_midi_output(void *data, bool wraparound)
{
struct string_list *list = midi_driver_get_avail_outputs();
if (list && list->size > 1)
{
rarch_setting_t *setting = (rarch_setting_t*)data;
int i = string_list_find_elem(list, setting->value.target.string);
if (wraparound && i == (int)list->size)
i = 0;
if (i >= 0 && i < (int)list->size)
{
strlcpy(setting->value.target.string, list->elems[i].data, setting->size);
return 0;
}
}
return -1;
}
static void setting_get_string_representation_uint_video_rotation(void *data, static void setting_get_string_representation_uint_video_rotation(void *data,
char *s, size_t len) char *s, size_t len)
{ {
@ -1537,6 +1623,15 @@ void general_write_handler(void *data)
case MENU_ENUM_LABEL_VIDEO_WINDOW_SHOW_DECORATIONS: case MENU_ENUM_LABEL_VIDEO_WINDOW_SHOW_DECORATIONS:
video_display_server_set_window_decorations(settings->bools.video_window_show_decorations); video_display_server_set_window_decorations(settings->bools.video_window_show_decorations);
break; break;
case MENU_ENUM_LABEL_MIDI_INPUT:
midi_driver_set_input(settings->arrays.midi_input);
break;
case MENU_ENUM_LABEL_MIDI_OUTPUT:
midi_driver_set_output(settings->arrays.midi_output);
break;
case MENU_ENUM_LABEL_MIDI_VOLUME:
midi_driver_set_volume(settings->uints.midi_volume);
break;
default: default:
break; break;
} }
@ -2495,6 +2590,14 @@ static bool setting_append_list(
&subgroup_info, &subgroup_info,
parent_group); parent_group);
CONFIG_ACTION(
list, list_info,
MENU_ENUM_LABEL_MIDI_SETTINGS,
MENU_ENUM_LABEL_VALUE_MIDI_SETTINGS,
&group_info,
&subgroup_info,
parent_group);
for (user = 0; user < MAX_USERS; user++) for (user = 0; user < MAX_USERS; user++)
setting_append_list_input_player_options(list, list_info, parent_group, user); setting_append_list_input_player_options(list, list_info, parent_group, user);
@ -2504,7 +2607,7 @@ static bool setting_append_list(
case SETTINGS_LIST_DRIVERS: case SETTINGS_LIST_DRIVERS:
{ {
unsigned i; unsigned i;
struct string_options_entry string_options_entries[10]; struct string_options_entry string_options_entries[11];
START_GROUP(list, list_info, &group_info, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DRIVER_SETTINGS), parent_group); START_GROUP(list, list_info, &group_info, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DRIVER_SETTINGS), parent_group);
menu_settings_list_current_add_enum_idx(list, list_info, MENU_ENUM_LABEL_DRIVER_SETTINGS); menu_settings_list_current_add_enum_idx(list, list_info, MENU_ENUM_LABEL_DRIVER_SETTINGS);
@ -2584,6 +2687,13 @@ static bool setting_append_list(
string_options_entries[9].default_value = config_get_default_record(); string_options_entries[9].default_value = config_get_default_record();
string_options_entries[9].values = config_get_record_driver_options(); string_options_entries[9].values = config_get_record_driver_options();
string_options_entries[10].target = settings->arrays.midi_driver;
string_options_entries[10].len = sizeof(settings->arrays.midi_driver);
string_options_entries[10].name_enum_idx = MENU_ENUM_LABEL_MIDI_DRIVER;
string_options_entries[10].SHORT_enum_idx = MENU_ENUM_LABEL_VALUE_MIDI_DRIVER;
string_options_entries[10].default_value = config_get_default_midi();
string_options_entries[10].values = config_get_midi_driver_options();
for (i = 0; i < ARRAY_SIZE(string_options_entries); i++) for (i = 0; i < ARRAY_SIZE(string_options_entries); i++)
{ {
CONFIG_STRING_OPTIONS( CONFIG_STRING_OPTIONS(
@ -7907,6 +8017,63 @@ static bool setting_append_list(
SD_FLAG_NONE); SD_FLAG_NONE);
} }
END_SUB_GROUP(list, list_info, parent_group);
END_GROUP(list, list_info, parent_group);
break;
case SETTINGS_LIST_MIDI:
START_GROUP(list, list_info, &group_info,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_MIDI_SETTINGS), parent_group);
parent_group = msg_hash_to_str(MENU_ENUM_LABEL_MIDI_SETTINGS);
START_SUB_GROUP(list, list_info, "State",
&group_info, &subgroup_info, parent_group);
CONFIG_STRING(
list, list_info,
settings->arrays.midi_input,
sizeof(settings->arrays.midi_input),
MENU_ENUM_LABEL_MIDI_INPUT,
MENU_ENUM_LABEL_VALUE_MIDI_INPUT,
midi_input,
&group_info,
&subgroup_info,
parent_group,
general_write_handler,
general_read_handler);
settings_data_list_current_add_flags(list, list_info, SD_FLAG_ALLOW_INPUT);
(*list)[list_info->index - 1].action_left = setting_string_action_left_midi_input;
(*list)[list_info->index - 1].action_right = setting_string_action_right_midi_input;
CONFIG_STRING(
list, list_info,
settings->arrays.midi_output,
sizeof(settings->arrays.midi_output),
MENU_ENUM_LABEL_MIDI_OUTPUT,
MENU_ENUM_LABEL_VALUE_MIDI_OUTPUT,
midi_output,
&group_info,
&subgroup_info,
parent_group,
general_write_handler,
general_read_handler);
settings_data_list_current_add_flags(list, list_info, SD_FLAG_ALLOW_INPUT);
(*list)[list_info->index - 1].action_left = setting_string_action_left_midi_output;
(*list)[list_info->index - 1].action_right = setting_string_action_right_midi_output;
CONFIG_UINT(
list, list_info,
&settings->uints.midi_volume,
MENU_ENUM_LABEL_MIDI_VOLUME,
MENU_ENUM_LABEL_VALUE_MIDI_VOLUME,
midi_volume,
&group_info,
&subgroup_info,
parent_group,
general_write_handler,
general_read_handler);
menu_settings_list_current_add_range(list, list_info, 0.0f, 100.0f, 1.0f, true, true);
END_SUB_GROUP(list, list_info, parent_group); END_SUB_GROUP(list, list_info, parent_group);
END_GROUP(list, list_info, parent_group); END_GROUP(list, list_info, parent_group);
break; break;
@ -8028,7 +8195,8 @@ static rarch_setting_t *menu_setting_new_internal(rarch_setting_info_t *list_inf
SETTINGS_LIST_USER_ACCOUNTS, SETTINGS_LIST_USER_ACCOUNTS,
SETTINGS_LIST_USER_ACCOUNTS_CHEEVOS, SETTINGS_LIST_USER_ACCOUNTS_CHEEVOS,
SETTINGS_LIST_DIRECTORY, SETTINGS_LIST_DIRECTORY,
SETTINGS_LIST_PRIVACY SETTINGS_LIST_PRIVACY,
SETTINGS_LIST_MIDI
}; };
const char *root = msg_hash_to_str(MENU_ENUM_LABEL_MAIN_MENU); const char *root = msg_hash_to_str(MENU_ENUM_LABEL_MAIN_MENU);
rarch_setting_t *list = (rarch_setting_t*)calloc( rarch_setting_t *list = (rarch_setting_t*)calloc(

98
midi/drivers/null_midi.c Normal file
View File

@ -0,0 +1,98 @@
/* RetroArch - A frontend for libretro.
* Copyright (C) 2018 The RetroArch team
*
* RetroArch is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with RetroArch.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include <libretro.h>
#include <lists/string_list.h>
#include "../midi_driver.h"
static bool null_midi_get_avail_inputs(struct string_list *inputs)
{
union string_list_elem_attr attr = {0};
return string_list_append(inputs, "Null", attr);
}
static bool null_midi_get_avail_outputs(struct string_list *outputs)
{
union string_list_elem_attr attr = {0};
return string_list_append(outputs, "Null", attr);
}
static void *null_midi_init(const char *input, const char *output)
{
(void)input;
(void)output;
return (void*)-1;
}
static void null_midi_free(void *p)
{
(void)p;
}
static bool null_midi_set_input(void *p, const char *input)
{
(void)p;
return input == NULL || !strcmp(input, "Null");
}
static bool null_midi_set_output(void *p, const char *output)
{
(void)p;
return output == NULL || !strcmp(output, "Null");
}
static bool null_midi_read(void *p, midi_event_t *event)
{
(void)p;
(void)event;
return false;
}
static bool null_midi_write(void *p, const midi_event_t *event)
{
(void)p;
(void)event;
return true;
}
static bool null_midi_flush(void *p)
{
(void)p;
return true;
}
midi_driver_t midi_null = {
"null",
null_midi_get_avail_inputs,
null_midi_get_avail_outputs,
null_midi_init,
null_midi_free,
null_midi_set_input,
null_midi_set_output,
null_midi_read,
null_midi_write,
null_midi_flush
};

628
midi/drivers/winmm_midi.c Normal file
View File

@ -0,0 +1,628 @@
/* RetroArch - A frontend for libretro.
* Copyright (C) 2018 The RetroArch team
*
* RetroArch is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with RetroArch.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include <windows.h>
#include <libretro.h>
#include <lists/string_list.h>
#include <verbosity.h>
#include "../midi_driver.h"
#define WINMM_MIDI_BUF_CNT 3
#define WINMM_MIDI_BUF_LEN 1024
typedef struct
{
MIDIHDR header;
DWORD data[WINMM_MIDI_BUF_LEN];
} winmm_midi_buffer_t;
typedef struct
{
uint8_t data[WINMM_MIDI_BUF_LEN * 4];
midi_event_t events[WINMM_MIDI_BUF_LEN];
int rd_idx;
int wr_idx;
} winmm_midi_queue_t;
typedef struct
{
HMIDIIN in_dev;
HMIDISTRM out_dev;
winmm_midi_queue_t in_queue;
winmm_midi_buffer_t out_bufs[WINMM_MIDI_BUF_CNT];
int out_buf_idx;
double tick_dur;
} winmm_midi_t;
static void winmm_midi_free(void *p);
static bool winmm_midi_queue_read(winmm_midi_queue_t *q, midi_event_t *ev)
{
int i;
midi_event_t *src_ev;
if (q->rd_idx == q->wr_idx)
return false;
if (ev->data_size < q->events[q->rd_idx].data_size)
{
#ifdef DEBUG
RARCH_ERR("[MIDI]: Input queue read failed (event data too small).\n");
#endif
return false;
}
src_ev = &q->events[q->rd_idx];
for (i = 0; i < src_ev->data_size; ++i)
ev->data[i] = src_ev->data[i];
ev->data_size = src_ev->data_size;
ev->delta_time = src_ev->delta_time;
if (q->rd_idx + 1 == WINMM_MIDI_BUF_LEN)
q->rd_idx = 0;
else
++q->rd_idx;
return true;
}
static bool winmm_midi_queue_write(winmm_midi_queue_t *q, const midi_event_t *ev)
{
int rd_idx = q->rd_idx;
midi_event_t *dest_ev;
int wr_avail;
int i;
if (q->wr_idx >= rd_idx)
wr_avail = WINMM_MIDI_BUF_LEN - q->wr_idx + rd_idx;
else
wr_avail = rd_idx - q->wr_idx - 1;
if (wr_avail < 1)
{
#ifdef DEBUG
RARCH_ERR("[MIDI]: Input queue overflow.\n");
#endif
return false;
}
dest_ev = &q->events[q->wr_idx];
if (ev->data_size > 4)
{
#ifdef DEBUG
RARCH_ERR("[MIDI]: Input queue write failed (event too big).\n");
#endif
return false;
}
for (i = 0; i < ev->data_size; ++i)
dest_ev->data[i] = ev->data[i];
dest_ev->data_size = ev->data_size;
dest_ev->delta_time = ev->delta_time;
if (q->wr_idx + 1 == WINMM_MIDI_BUF_LEN)
q->wr_idx = 0;
else
++q->wr_idx;
return true;
}
static void winmm_midi_queue_init(winmm_midi_queue_t *q)
{
int i, j;
for (i = j = 0; i < WINMM_MIDI_BUF_LEN; ++i, j += 4)
{
q->events[i].data = &q->data[j];
q->events[i].delta_time = 0;
}
q->rd_idx = 0;
q->wr_idx = 0;
}
static void CALLBACK winmm_midi_input_callback(HMIDIIN dev, UINT msg,
DWORD_PTR q, DWORD_PTR par1, DWORD_PTR par2)
{
winmm_midi_queue_t *queue = (winmm_midi_queue_t*)q;
midi_event_t event;
uint8_t data[3];
(void)dev;
if (msg == MIM_OPEN)
winmm_midi_queue_init(queue);
else if (msg == MIM_DATA)
{
data[0] = (uint8_t)(par1 & 0xFF);
data[1] = (uint8_t)((par1 >> 8) & 0xFF);
data[2] = (uint8_t)((par1 >> 16) & 0xFF);
event.data = data;
event.data_size = midi_driver_get_event_size(data[0]);
event.delta_time = 0;
if (!winmm_midi_queue_write(queue, &event))
{
#ifdef DEBUG
RARCH_ERR("[MIDI]: Input event dropped.\n");
#endif
}
}
else if(msg == MIM_LONGDATA)
{
#ifdef DEBUG
RARCH_WARN("[MIDI]: SysEx input not implemented, event dropped.\n");
#endif
}
}
static HMIDIIN winmm_midi_open_input_device(const char *dev_name,
winmm_midi_queue_t *queue)
{
UINT dev_count = midiInGetNumDevs();
HMIDIIN dev = NULL;
MIDIINCAPSA caps;
MMRESULT mmr;
UINT i;
for (i = 0; i < dev_count; ++i)
{
mmr = midiInGetDevCapsA(i, &caps, sizeof(caps));
if (mmr == MMSYSERR_NOERROR)
{
if (!strcmp(caps.szPname, dev_name))
{
mmr = midiInOpen(&dev, i, (DWORD_PTR)winmm_midi_input_callback,
(DWORD_PTR)queue, CALLBACK_FUNCTION);
if (mmr != MMSYSERR_NOERROR)
RARCH_ERR("[MIDI]: midiInOpen failed with error %d.\n", mmr);
break;
}
}
else
RARCH_WARN("[MIDI]: midiInGetDevCapsA failed with error %d.\n", mmr);
}
return dev;
}
static HMIDISTRM winmm_midi_open_output_device(const char *dev_name)
{
UINT dev_count = midiOutGetNumDevs();
HMIDISTRM dev = NULL;
MIDIOUTCAPSA caps;
MMRESULT mmr;
UINT i;
for (i = 0; i < dev_count; ++i)
{
mmr = midiOutGetDevCapsA(i, &caps, sizeof(caps));
if (mmr == MMSYSERR_NOERROR)
{
if (!strcmp(caps.szPname, dev_name))
{
mmr = midiStreamOpen(&dev, &i, 1, 0, 0, CALLBACK_NULL);
if (mmr != MMSYSERR_NOERROR)
RARCH_ERR("[MIDI]: midiStreamOpen failed with error %d.\n", mmr);
break;
}
}
else
RARCH_WARN("[MIDI]: midiOutGetDevCapsA failed with error %d.\n", mmr);
}
return dev;
}
static bool winmm_midi_init_clock(HMIDISTRM out_dev, double *tick_dur)
{
MIDIPROPTIMEDIV division;
MIDIPROPTEMPO tempo;
MMRESULT mmr;
tempo.cbStruct = sizeof(tempo);
mmr = midiStreamProperty(out_dev, (LPBYTE)&tempo,
MIDIPROP_GET | MIDIPROP_TEMPO);
if (mmr != MMSYSERR_NOERROR)
{
RARCH_ERR("[MIDI]: Current tempo unavailable (error %d).\n", mmr);
return false;
}
division.dwTimeDiv = 3;
while (tempo.dwTempo / division.dwTimeDiv > 320)
division.dwTimeDiv *= 2;
division.cbStruct = sizeof(division);
mmr = midiStreamProperty(out_dev, (LPBYTE)&division,
MIDIPROP_SET | MIDIPROP_TIMEDIV);
if (mmr != MMSYSERR_NOERROR)
{
RARCH_ERR("[MIDI]: Time division change failed (error %d).\n", mmr);
return false;
}
*tick_dur = (double)tempo.dwTempo / (double)division.dwTimeDiv;
#ifdef DEBUG
RARCH_LOG("[MIDI]: Tick duration %f us.\n", *tick_dur);
#endif
return true;
}
static bool winmm_midi_init_output_buffers(HMIDISTRM dev, winmm_midi_buffer_t *bufs)
{
MMRESULT mmr;
int i;
for (i = 0; i < WINMM_MIDI_BUF_CNT; ++i)
{
bufs[i].header.dwBufferLength = sizeof(DWORD) * WINMM_MIDI_BUF_LEN;
bufs[i].header.dwBytesRecorded = 0;
bufs[i].header.dwFlags = 0;
bufs[i].header.lpData = (LPSTR)bufs[i].data;
mmr = midiOutPrepareHeader((HMIDIOUT)dev, &bufs[i].header, sizeof(MIDIHDR));
if (mmr != MMSYSERR_NOERROR)
{
RARCH_ERR("[MIDI]: midiOutPrepareHeader failed with error %d.\n", mmr);
while (--i <= 0)
midiOutUnprepareHeader((HMIDIOUT)dev, &bufs[i].header, sizeof(MIDIHDR));
return false;
}
}
return true;
}
static void winmm_midi_free_output_buffers(HMIDISTRM dev, winmm_midi_buffer_t *bufs)
{
MMRESULT mmr;
int i;
for (i = 0; i < WINMM_MIDI_BUF_CNT; ++i)
{
mmr = midiOutUnprepareHeader((HMIDIOUT)dev, &bufs[i].header, sizeof(MIDIHDR));
if (mmr != MMSYSERR_NOERROR)
RARCH_ERR("[MIDI]: midiOutUnprepareHeader failed with error %d.\n", mmr);
}
}
static bool winmm_midi_write_short_event(winmm_midi_buffer_t *buf,
const uint8_t *data, size_t data_size, DWORD delta_time)
{
DWORD i = buf->header.dwBytesRecorded / sizeof(DWORD);
if (buf->header.dwBytesRecorded + sizeof(DWORD) * 3 >
sizeof(DWORD) * WINMM_MIDI_BUF_LEN)
return false;
buf->data[i++] = delta_time;
buf->data[i++] = 0;
buf->data[i] = MEVT_F_SHORT << 24;
if (data_size == 0)
buf->data[i] |= MEVT_NOP;
else
{
buf->data[i] |= MEVT_SHORTMSG << 24 | data[0];
if (data_size > 1)
buf->data[i] |= data[1] << 8;
if (data_size > 2)
buf->data[i] |= data[2] << 16;
}
buf->header.dwBytesRecorded += sizeof(DWORD) * 3;
return true;
}
static bool winmm_midi_write_long_event(winmm_midi_buffer_t *buf,
const uint8_t *data, size_t data_size, DWORD delta_time)
{
DWORD i = buf->header.dwBytesRecorded / sizeof(DWORD);
if (buf->header.dwBytesRecorded + sizeof(DWORD) * 3 + data_size >
sizeof(DWORD) * WINMM_MIDI_BUF_LEN)
return false;
buf->data[i++] = delta_time;
buf->data[i++] = 0;
buf->data[i++] = MEVT_F_LONG << 24 | MEVT_LONGMSG << 24 | data_size;
memcpy(&buf->data[i], data, data_size);
buf->header.dwBytesRecorded += sizeof(DWORD) * 3 + data_size;
return true;
}
static bool winmm_midi_get_avail_inputs(struct string_list *inputs)
{
union string_list_elem_attr attr = {0};
UINT dev_count = midiInGetNumDevs();
MIDIINCAPSA caps;
MMRESULT mmr;
UINT i;
for (i = 0; i < dev_count; ++i)
{
mmr = midiInGetDevCapsA(i, &caps, sizeof(caps));
if (mmr != MMSYSERR_NOERROR)
{
RARCH_ERR("[MIDI]: midiInGetDevCapsA failed with error %d.\n", mmr);
return false;
}
if (!string_list_append(inputs, caps.szPname, attr))
{
RARCH_ERR("[MIDI]: string_list_append failed.\n");
return false;
}
}
return true;
}
static bool winmm_midi_get_avail_outputs(struct string_list *outputs)
{
union string_list_elem_attr attr = {0};
UINT dev_count = midiOutGetNumDevs();
MIDIOUTCAPSA caps;
MMRESULT mmr;
UINT i;
for (i = 0; i < dev_count; ++i)
{
mmr = midiOutGetDevCapsA(i, &caps, sizeof(caps));
if (mmr != MMSYSERR_NOERROR)
{
RARCH_ERR("[MIDI]: midiOutGetDevCapsA failed with error %d.\n", mmr);
return false;
}
if (!string_list_append(outputs, caps.szPname, attr))
{
RARCH_ERR("[MIDI]: string_list_append failed.\n");
return false;
}
}
return true;
}
static void *winmm_midi_init(const char *input, const char *output)
{
winmm_midi_t *d = (winmm_midi_t*)calloc(sizeof(winmm_midi_t), 1);
bool err = false;
MMRESULT mmr;
if (!d)
{
RARCH_ERR("[MIDI]: Out of memory.\n");
return NULL;
}
if (input)
{
d->in_dev = winmm_midi_open_input_device(input, &d->in_queue);
if (!d->in_dev)
err = true;
else
{
mmr = midiInStart(d->in_dev);
if (mmr != MMSYSERR_NOERROR)
{
RARCH_ERR("[MIDI]: midiInStart failed with error %d.\n", mmr);
err = true;
}
}
}
if (output)
{
d->out_dev = winmm_midi_open_output_device(output);
if (!d->out_dev)
err = true;
else if (!winmm_midi_init_clock(d->out_dev, &d->tick_dur))
err = true;
else if (!winmm_midi_init_output_buffers(d->out_dev, d->out_bufs))
err = true;
else
{
mmr = midiStreamRestart(d->out_dev);
if (mmr != MMSYSERR_NOERROR)
{
RARCH_ERR("[MIDI]: midiStreamRestart failed with error %d.\n", mmr);
err = true;
}
}
}
if (err)
{
winmm_midi_free(d);
return NULL;
}
return d;
}
static void winmm_midi_free(void *p)
{
winmm_midi_t *d = (winmm_midi_t*)p;
if (d->in_dev)
{
midiInStop(d->in_dev);
midiInClose(d->in_dev);
}
if (d->out_dev)
{
midiStreamStop(d->out_dev);
winmm_midi_free_output_buffers(d->out_dev, d->out_bufs);
midiStreamClose(d->out_dev);
}
free(d);
}
static bool winmm_midi_set_input(void *p, const char *input)
{
winmm_midi_t *d = (winmm_midi_t*)p;
HMIDIIN new_dev = NULL;
MMRESULT mmr;
if (input)
{
new_dev = winmm_midi_open_input_device(input, &d->in_queue);
if (!new_dev)
return false;
}
if (d->in_dev)
{
midiInStop(d->in_dev);
midiInClose(d->in_dev);
}
d->in_dev = new_dev;
if (d->in_dev)
{
mmr = midiInStart(d->in_dev);
if (mmr != MMSYSERR_NOERROR)
{
RARCH_ERR("[MIDI]: midiInStart failed with error %d.\n", mmr);
return false;
}
}
return true;
}
static bool winmm_midi_set_output(void *p, const char *output)
{
winmm_midi_t *d = (winmm_midi_t*)p;
HMIDISTRM new_dev = NULL;
MMRESULT mmr;
int i;
if (output)
{
new_dev = winmm_midi_open_output_device(output);
if (!new_dev)
return false;
}
if (d->out_dev)
{
midiStreamStop(d->out_dev);
winmm_midi_free_output_buffers(d->out_dev, d->out_bufs);
midiStreamClose(d->out_dev);
}
d->out_dev = new_dev;
if (d->out_dev)
{
if (!winmm_midi_init_output_buffers(d->out_dev, d->out_bufs))
return false;
d->out_buf_idx = 0;
mmr = midiStreamRestart(d->out_dev);
if (mmr != MMSYSERR_NOERROR)
{
RARCH_ERR("[MIDI]: midiStreamRestart failed with error %d.\n", mmr);
return false;
}
}
return true;
}
static bool winmm_midi_read(void *p, midi_event_t *event)
{
winmm_midi_t *d = (winmm_midi_t*)p;
return winmm_midi_queue_read(&d->in_queue, event);
}
static bool winmm_midi_write(void *p, const midi_event_t *event)
{
winmm_midi_t *d = (winmm_midi_t*)p;
winmm_midi_buffer_t *buf = &d->out_bufs[d->out_buf_idx];
DWORD delta_time;
if (buf->header.dwFlags & MHDR_INQUEUE)
return false;
if (buf->header.dwFlags & MHDR_DONE)
{
buf->header.dwBytesRecorded = 0;
buf->header.dwFlags ^= MHDR_DONE;
}
delta_time = (DWORD)((double)event->delta_time / d->tick_dur);
if (event->data_size < 4)
return winmm_midi_write_short_event(buf, event->data,
event->data_size, delta_time);
return winmm_midi_write_long_event(buf, event->data,
event->data_size, delta_time);
}
static bool winmm_midi_flush(void *p)
{
winmm_midi_t *d = (winmm_midi_t*)p;
winmm_midi_buffer_t *buf = &d->out_bufs[d->out_buf_idx];
MMRESULT mmr;
if (buf->header.dwBytesRecorded)
{
mmr = midiStreamOut(d->out_dev, &buf->header, sizeof(buf->header));
if (mmr != MMSYSERR_NOERROR)
{
#ifdef DEBUG
RARCH_ERR("[MIDI]: midiStreamOut failed with error %d.\n", mmr);
#endif
return false;
}
if (++d->out_buf_idx == WINMM_MIDI_BUF_CNT)
d->out_buf_idx = 0;
}
return true;
}
midi_driver_t midi_winmm = {
"winmm",
winmm_midi_get_avail_inputs,
winmm_midi_get_avail_outputs,
winmm_midi_init,
winmm_midi_free,
winmm_midi_set_input,
winmm_midi_set_output,
winmm_midi_read,
winmm_midi_write,
winmm_midi_flush
};

585
midi/midi_driver.c Normal file
View File

@ -0,0 +1,585 @@
/* RetroArch - A frontend for libretro.
* Copyright (C) 2018 The RetroArch team
*
* RetroArch is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with RetroArch.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include <configuration.h>
#include <verbosity.h>
#include <lists/string_list.h>
#include "midi_driver.h"
#define MIDI_DRIVER_BUF_SIZE 4096
#define MIDI_DRIVER_COUNT (int)(sizeof(midi_drivers) / sizeof(midi_driver_t*))
extern midi_driver_t midi_null;
extern midi_driver_t midi_winmm;
static midi_driver_t *midi_drivers[] = {
#ifdef HAVE_WINMM
&midi_winmm,
#endif
&midi_null
};
static midi_driver_t *midi_drv = &midi_null;
static void *midi_drv_data;
static struct string_list *midi_drv_inputs;
static struct string_list *midi_drv_outputs;
static bool midi_drv_input_enabled;
static bool midi_drv_output_enabled;
static uint8_t *midi_drv_input_buffer;
static uint8_t *midi_drv_output_buffer;
static midi_event_t midi_drv_input_event;
static midi_event_t midi_drv_output_event;
static bool midi_drv_output_pending;
static const uint8_t midi_drv_ev_sizes[128] =
{
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
0, 2, 3, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
};
static midi_driver_t *midi_driver_find_driver(const char *ident)
{
int i;
for (i = 0; i < MIDI_DRIVER_COUNT; ++i)
{
if (!strcmp(midi_drivers[i]->ident, ident))
return midi_drivers[i];
}
RARCH_ERR("[MIDI]: Unknown driver \"%s\", falling back to \"null\" driver.\n");
return &midi_null;
}
const void *midi_driver_find_handle(int index)
{
if (index < 0 || index >= MIDI_DRIVER_COUNT)
return NULL;
return midi_drivers[index];
}
const char *midi_driver_find_ident(int index)
{
if (index < 0 || index >= MIDI_DRIVER_COUNT)
return NULL;
return midi_drivers[index]->ident;
}
struct string_list *midi_driver_get_avail_inputs(void)
{
return midi_drv_inputs;
}
struct string_list *midi_driver_get_avail_outputs(void)
{
return midi_drv_outputs;
}
bool midi_driver_set_all_sounds_off(void)
{
uint8_t data[3] = { 0xB0, 120, 0 };
bool result = true;
midi_event_t event;
uint8_t i;
if (!midi_drv_data || !midi_drv_output_enabled)
return false;
event.data = data;
event.data_size = sizeof(data);
event.delta_time = 0;
for (i = 0; i < 16; ++i)
{
data[0] = 0xB0 | i;
if (!midi_drv->write(midi_drv_data, &event))
result = false;
}
if (!midi_drv->flush(midi_drv_data))
result = false;
if (!result)
RARCH_ERR("[MIDI]: All sounds off failed.\n");
return result;
}
bool midi_driver_set_volume(unsigned volume)
{
uint8_t data[8] = { 0xF0, 0x7F, 0x7F, 0x04, 0x01, 0, 0, 0xF7 };
const char *err_str = NULL;
midi_event_t event;
if (!midi_drv_data || !midi_drv_output_enabled)
return false;
volume = (unsigned)(163.83 * volume + 0.5);
if (volume > 16383)
volume = 16383;
data[5] = (uint8_t)(volume & 0x7F);
data[6] = (uint8_t)(volume >> 7);
event.data = data;
event.data_size = sizeof(data);
event.delta_time = 0;
if (!midi_drv->write(midi_drv_data, &event))
{
RARCH_ERR("[MIDI]: Volume change failed.\n");
return false;
}
return true;
}
bool midi_driver_init_io_buffers(void)
{
if (midi_drv_input_enabled)
{
midi_drv_input_buffer = (uint8_t*)malloc(MIDI_DRIVER_BUF_SIZE);
if (!midi_drv_input_buffer)
return false;
midi_drv_input_event.data = midi_drv_input_buffer;
midi_drv_input_event.data_size = 0;
}
if (midi_drv_output_enabled)
{
midi_drv_output_buffer = (uint8_t*)malloc(MIDI_DRIVER_BUF_SIZE);
if (!midi_drv_output_buffer)
return false;
midi_drv_output_event.data = midi_drv_output_buffer;
midi_drv_output_event.data_size = 0;
}
return true;
}
bool midi_driver_init(void)
{
settings_t *sett = config_get_ptr();
midi_drv_inputs = string_list_new();
midi_drv_outputs = string_list_new();
union string_list_elem_attr attr = {0};
const char *err_str = NULL;
RARCH_LOG("[MIDI]: Initializing ...\n");
if (!sett)
err_str = "settings unavailable";
else if (!midi_drv_inputs || !midi_drv_outputs)
err_str = "string_list_new failed";
else if (!string_list_append(midi_drv_inputs, "Off", attr) ||
!string_list_append(midi_drv_outputs, "Off", attr))
err_str = "string_list_append failed";
else
{
char * input = NULL;
char * output = NULL;
midi_drv = midi_driver_find_driver(sett->arrays.midi_driver);
if (strcmp(midi_drv->ident, sett->arrays.midi_driver))
strcpy(sett->arrays.midi_driver, midi_drv->ident);
if (!midi_drv->get_avail_inputs(midi_drv_inputs))
err_str = "list of input devices unavailable";
else if (!midi_drv->get_avail_outputs(midi_drv_outputs))
err_str = "list of output devices unavailable";
else
{
if (strcmp(sett->arrays.midi_input, "Off"))
{
if (string_list_find_elem(midi_drv_inputs, sett->arrays.midi_input))
input = sett->arrays.midi_input;
else
{
RARCH_WARN("[MIDI]: Input device \"%s\" unavailable.\n",
sett->arrays.midi_input);
strcpy(sett->arrays.midi_input, "Off");
}
}
if (strcmp(sett->arrays.midi_output, "Off"))
{
if (string_list_find_elem(midi_drv_outputs, sett->arrays.midi_output))
output = sett->arrays.midi_output;
else
{
RARCH_WARN("[MIDI]: Output device \"%s\" unavailable.\n",
sett->arrays.midi_output);
strcpy(sett->arrays.midi_output, "Off");
}
}
midi_drv_data = midi_drv->init(input, output);
if (!midi_drv_data)
err_str = "driver init failed";
else
{
midi_drv_input_enabled = input != NULL;
midi_drv_output_enabled = output != NULL;
if (!midi_driver_init_io_buffers())
err_str = "out of memory";
else
{
if (input)
RARCH_LOG("[MIDI]: Input device \"%s\".\n", input);
else
RARCH_LOG("[MIDI]: Input disabled.\n");
if (output)
{
RARCH_LOG("[MIDI]: Output device \"%s\".\n", output);
midi_driver_set_volume(sett->uints.midi_volume);
}
else
RARCH_LOG("[MIDI]: Output disabled.\n");
}
}
}
}
if (err_str)
{
midi_driver_free();
RARCH_ERR("[MIDI]: Initialization failed (%s).\n", err_str);
}
else
RARCH_LOG("[MIDI]: Initialized \"%s\" driver.\n", midi_drv->ident);
return err_str == NULL;;
}
void midi_driver_free(void)
{
if (midi_drv_data)
{
midi_drv->free(midi_drv_data);
midi_drv_data = NULL;
}
if (midi_drv_inputs)
{
string_list_free(midi_drv_inputs);
midi_drv_inputs = NULL;
}
if (midi_drv_outputs)
{
string_list_free(midi_drv_outputs);
midi_drv_outputs = NULL;
}
if (midi_drv_input_buffer)
{
free(midi_drv_input_buffer);
midi_drv_input_buffer = NULL;
}
if (midi_drv_output_buffer)
{
free(midi_drv_output_buffer);
midi_drv_output_buffer = NULL;
}
midi_drv_input_enabled = false;
midi_drv_output_enabled = false;
}
bool midi_driver_set_input(const char *input)
{
if (!midi_drv_data)
{
#ifdef DEBUG
RARCH_ERR("[MIDI]: midi_driver_set_input called on uninitialized driver.\n");
#endif
return false;
}
if (!strcmp(input, "Off"))
input = NULL;
if (!midi_drv->set_input(midi_drv_data, input))
{
if (input)
RARCH_ERR("[MIDI]: Failed to change input device to \"%s\".\n", input);
else
RARCH_ERR("[MIDI]: Failed to disable input.\n");
return false;
}
if (input)
RARCH_LOG("[MIDI]: Input device changed to \"%s\".\n", input);
else
RARCH_LOG("[MIDI]: Input disabled.\n");
midi_drv_input_enabled = input != NULL;
return true;
}
bool midi_driver_set_output(const char *output)
{
if (!midi_drv_data)
{
#ifdef DEBUG
RARCH_ERR("[MIDI]: midi_driver_set_output called on uninitialized driver.\n");
#endif
return false;
}
if (!strcmp(output, "Off"))
output = NULL;
if (!midi_drv->set_output(midi_drv_data, output))
{
if (output)
RARCH_ERR("[MIDI]: Failed to change output device to \"%s\".\n", output);
else
RARCH_ERR("[MIDI]: Failed to disable output.\n");
return false;
}
if (output)
{
settings_t *sett = config_get_ptr();
midi_drv_output_enabled = true;
RARCH_LOG("[MIDI]: Output device changed to \"%s\".\n", output);
if (sett)
midi_driver_set_volume(sett->uints.midi_volume);
else
RARCH_ERR("[MIDI]: Volume change failed (settings unavailable).\n");
}
else
{
midi_drv_output_enabled = false;
RARCH_LOG("[MIDI]: Output disabled.\n");
}
return true;
}
bool midi_driver_input_enabled(void)
{
return midi_drv_input_enabled;
}
bool midi_driver_output_enabled(void)
{
return midi_drv_output_enabled;
}
bool midi_driver_read(uint8_t *byte)
{
static int i;
if (!midi_drv_data || !midi_drv_input_enabled || !byte)
{
#ifdef DEBUG
if (!midi_drv_data)
RARCH_ERR("[MIDI]: midi_driver_read called on uninitialized driver.\n");
else if (!midi_drv_input_enabled)
RARCH_ERR("[MIDI]: midi_driver_read called when input is disabled.\n");
else
RARCH_ERR("[MIDI]: midi_driver_read called with null pointer.\n");
#endif
return false;
}
if (i == midi_drv_input_event.data_size)
{
midi_drv_input_event.data_size = MIDI_DRIVER_BUF_SIZE;
if (!midi_drv->read(midi_drv_data, &midi_drv_input_event))
{
midi_drv_input_event.data_size = i;
return false;
}
i = 0;
#ifdef DEBUG
if (midi_drv_input_event.data_size == 1)
RARCH_LOG("[MIDI]: In [0x%02X].\n",
midi_drv_input_event.data[0]);
else if (midi_drv_input_event.data_size == 2)
RARCH_LOG("[MIDI]: In [0x%02X, 0x%02X].\n",
midi_drv_input_event.data[0],
midi_drv_input_event.data[1]);
else if (midi_drv_input_event.data_size == 3)
RARCH_LOG("[MIDI]: In [0x%02X, 0x%02X, 0x%02X].\n",
midi_drv_input_event.data[0],
midi_drv_input_event.data[1],
midi_drv_input_event.data[2]);
else
RARCH_LOG("[MIDI]: In [0x%02X, ...], size %u.\n",
midi_drv_input_event.data[0],
midi_drv_input_event.data_size);
#endif
}
*byte = midi_drv_input_event.data[i++];
return true;
}
bool midi_driver_write(uint8_t byte, uint32_t delta_time)
{
static int event_size;
if (!midi_drv_data || !midi_drv_output_enabled)
{
#ifdef DEBUG
if (!midi_drv_data)
RARCH_ERR("[MIDI]: midi_driver_write called on uninitialized driver.\n");
else
RARCH_ERR("[MIDI]: midi_driver_write called when output is disabled.\n");
#endif
return false;
}
if (byte >= 0x80)
{
if (midi_drv_output_event.data_size &&
midi_drv_output_event.data[0] == 0xF0)
{
if (byte == 0xF7)
event_size = midi_drv_output_event.data_size + 1;
else
{
if (!midi_drv->write(midi_drv_data, &midi_drv_output_event))
return false;
#ifdef DEBUG
if (midi_drv_output_event.data_size == 1)
RARCH_LOG("[MIDI]: Out [0x%02X].\n",
midi_drv_output_event.data[0]);
else if (midi_drv_output_event.data_size == 2)
RARCH_LOG("[MIDI]: Out [0x%02X, 0x%02X].\n",
midi_drv_output_event.data[0],
midi_drv_output_event.data[1]);
else if (midi_drv_output_event.data_size == 3)
RARCH_LOG("[MIDI]: Out [0x%02X, 0x%02X, 0x%02X].\n",
midi_drv_output_event.data[0],
midi_drv_output_event.data[1],
midi_drv_output_event.data[2]);
else
RARCH_LOG("[MIDI]: Out [0x%02X, ...], size %u.\n",
midi_drv_output_event.data[0],
midi_drv_output_event.data_size);
#endif
midi_drv_output_pending = true;
event_size = midi_driver_get_event_size(byte);
midi_drv_output_event.data_size = 0;
midi_drv_output_event.delta_time = 0;
}
}
else
{
event_size = midi_driver_get_event_size(byte);
midi_drv_output_event.data_size = 0;
midi_drv_output_event.delta_time = 0;
}
}
if (midi_drv_output_event.data_size < MIDI_DRIVER_BUF_SIZE)
{
midi_drv_output_event.data[midi_drv_output_event.data_size] = byte;
++midi_drv_output_event.data_size;
midi_drv_output_event.delta_time += delta_time;
}
else
{
#ifdef DEBUG
RARCH_ERR("[MIDI]: Output event dropped.\n");
#endif
return false;
}
if (midi_drv_output_event.data_size == event_size)
{
if (!midi_drv->write(midi_drv_data, &midi_drv_output_event))
return false;
#ifdef DEBUG
if (midi_drv_output_event.data_size == 1)
RARCH_LOG("[MIDI]: Out [0x%02X].\n",
midi_drv_output_event.data[0]);
else if (midi_drv_output_event.data_size == 2)
RARCH_LOG("[MIDI]: Out [0x%02X, 0x%02X].\n",
midi_drv_output_event.data[0],
midi_drv_output_event.data[1]);
else if (midi_drv_output_event.data_size == 3)
RARCH_LOG("[MIDI]: Out [0x%02X, 0x%02X, 0x%02X].\n",
midi_drv_output_event.data[0],
midi_drv_output_event.data[1],
midi_drv_output_event.data[2]);
else
RARCH_LOG("[MIDI]: Out [0x%02X, ...], size %u.\n",
midi_drv_output_event.data[0],
midi_drv_output_event.data_size);
#endif
midi_drv_output_pending = true;
}
return true;
}
bool midi_driver_flush(void)
{
if (!midi_drv_data)
{
#ifdef DEBUG
RARCH_ERR("[MIDI]: midi_driver_flush called on uninitialized driver.\n");
#endif
return false;
}
if (midi_drv_output_pending)
midi_drv_output_pending = !midi_drv->flush(midi_drv_data);
return !midi_drv_output_pending;
}
size_t midi_driver_get_event_size(uint8_t status)
{
if (status < 0x80)
{
#ifdef DEBUG
RARCH_ERR("[MIDI]: midi_driver_get_event_size called with invalid status.\n");
#endif
return 0;
}
return midi_drv_ev_sizes[status - 0x80];
}

77
midi/midi_driver.h Normal file
View File

@ -0,0 +1,77 @@
/* RetroArch - A frontend for libretro.
* Copyright (C) 2018 The RetroArch team
*
* RetroArch is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with RetroArch.
* If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __MIDI_DRIVER__H
#define __MIDI_DRIVER__H
#include <boolean.h>
#include <retro_common_api.h>
RETRO_BEGIN_DECLS
struct string_list;
typedef struct
{
uint8_t *data;
size_t data_size;
uint32_t delta_time;
} midi_event_t;
typedef struct midi_driver
{
const char *ident;
bool (*get_avail_inputs)(struct string_list *inputs);
bool (*get_avail_outputs)(struct string_list *outputs);
void *(*init)(const char *input, const char *output);
void (*free)(void *p);
bool (*set_input)(void *p, const char *input);
bool (*set_output)(void *p, const char *output);
bool (*read)(void *p, midi_event_t *event);
bool (*write)(void *p, const midi_event_t *event);
bool (*flush)(void *p);
} midi_driver_t;
const void *midi_driver_find_handle(int index);
const char *midi_driver_find_ident(int index);
struct string_list *midi_driver_get_avail_inputs(void);
struct string_list *midi_driver_get_avail_outputs(void);
bool midi_driver_set_all_sounds_off(void);
bool midi_driver_set_volume(unsigned volume);
bool midi_driver_init(void);
void midi_driver_free(void);
bool midi_driver_set_input(const char *input);
bool midi_driver_set_output(const char *output);
bool midi_driver_input_enabled(void);
bool midi_driver_output_enabled(void);
bool midi_driver_read(uint8_t *byte);
bool midi_driver_write(uint8_t byte, uint32_t delta_time);
bool midi_driver_flush(void);
size_t midi_driver_get_event_size(uint8_t status);
RETRO_END_DECLS
#endif

View File

@ -903,6 +903,7 @@ enum msg_hash_enums
MENU_LABEL(USER_SETTINGS), MENU_LABEL(USER_SETTINGS),
MENU_LABEL(DIRECTORY_SETTINGS), MENU_LABEL(DIRECTORY_SETTINGS),
MENU_LABEL(PRIVACY_SETTINGS), MENU_LABEL(PRIVACY_SETTINGS),
MENU_LABEL(MIDI_SETTINGS),
MENU_LABEL(NETWORK_SETTINGS), MENU_LABEL(NETWORK_SETTINGS),
MENU_LABEL(NETPLAY_LAN_SCAN_SETTINGS), MENU_LABEL(NETPLAY_LAN_SCAN_SETTINGS),
@ -1030,6 +1031,7 @@ enum msg_hash_enums
MENU_ENUM_LABEL_DEFERRED_USER_SETTINGS_LIST, MENU_ENUM_LABEL_DEFERRED_USER_SETTINGS_LIST,
MENU_ENUM_LABEL_DEFERRED_DIRECTORY_SETTINGS_LIST, MENU_ENUM_LABEL_DEFERRED_DIRECTORY_SETTINGS_LIST,
MENU_ENUM_LABEL_DEFERRED_PRIVACY_SETTINGS_LIST, MENU_ENUM_LABEL_DEFERRED_PRIVACY_SETTINGS_LIST,
MENU_ENUM_LABEL_DEFERRED_MIDI_SETTINGS_LIST,
MENU_ENUM_LABEL_DEFERRED_LOGGING_SETTINGS_LIST, MENU_ENUM_LABEL_DEFERRED_LOGGING_SETTINGS_LIST,
MENU_ENUM_LABEL_DEFERRED_AUDIO_SETTINGS_LIST, MENU_ENUM_LABEL_DEFERRED_AUDIO_SETTINGS_LIST,
MENU_ENUM_LABEL_DEFERRED_AUDIO_MIXER_SETTINGS_LIST, MENU_ENUM_LABEL_DEFERRED_AUDIO_MIXER_SETTINGS_LIST,
@ -1280,6 +1282,7 @@ enum msg_hash_enums
MENU_LABEL(RECORD_DRIVER), MENU_LABEL(RECORD_DRIVER),
MENU_LABEL(VIDEO_DRIVER), MENU_LABEL(VIDEO_DRIVER),
MENU_LABEL(INPUT_DRIVER), MENU_LABEL(INPUT_DRIVER),
MENU_LABEL(MIDI_DRIVER),
MENU_ENUM_LABEL_VIDEO_DRIVER_GL, MENU_ENUM_LABEL_VIDEO_DRIVER_GL,
MENU_ENUM_LABEL_VIDEO_DRIVER_SDL2, MENU_ENUM_LABEL_VIDEO_DRIVER_SDL2,
@ -1861,6 +1864,10 @@ enum msg_hash_enums
MENU_ENUM_LABEL_VALUE_QT_FILE_READ_OPEN_FAILED, MENU_ENUM_LABEL_VALUE_QT_FILE_READ_OPEN_FAILED,
MENU_ENUM_LABEL_VALUE_QT_FILE_DOES_NOT_EXIST, MENU_ENUM_LABEL_VALUE_QT_FILE_DOES_NOT_EXIST,
MENU_LABEL(MIDI_INPUT),
MENU_LABEL(MIDI_OUTPUT),
MENU_LABEL(MIDI_VOLUME),
MSG_LAST MSG_LAST
}; };

View File

@ -322,6 +322,7 @@ if [ "$OS" = 'Win32' ]; then
HAVE_WASAPI=yes HAVE_WASAPI=yes
HAVE_XAUDIO=yes HAVE_XAUDIO=yes
HAVE_WINMM=yes
else else
HAVE_D3D9=no HAVE_D3D9=no
HAVE_D3D10=no HAVE_D3D10=no