diff --git a/Makefile.common b/Makefile.common index 97c1113b76..76f8c4d701 100644 --- a/Makefile.common +++ b/Makefile.common @@ -236,6 +236,7 @@ OBJ += frontend/frontend_driver.o \ retroarch.o \ command.o \ msg_hash.o \ + midi_driver.o \ intl/msg_hash_us.o \ $(LIBRETRO_COMM_DIR)/queues/task_queue.o \ tasks/task_content.o diff --git a/griffin/griffin.c b/griffin/griffin.c index 6b4c86588a..44a0c89581 100644 --- a/griffin/griffin.c +++ b/griffin/griffin.c @@ -1214,6 +1214,7 @@ RETROARCH ============================================================ */ #include "../retroarch.c" #include "../command.c" +#include "../midi_driver.c" #include "../libretro-common/queues/task_queue.c" #include "../msg_hash.c" diff --git a/menu/menu_setting.c b/menu/menu_setting.c index 182b1b5b8c..df6d2011e0 100644 --- a/menu/menu_setting.c +++ b/menu/menu_setting.c @@ -81,7 +81,7 @@ #include "../list_special.h" #include "../bluetooth/bluetooth_driver.h" #include "../wifi/wifi_driver.h" -#include "../midi/midi_driver.h" +#include "../midi_driver.h" #include "../tasks/tasks_internal.h" #include "../config.def.h" #include "../ui/ui_companion_driver.h" @@ -7952,7 +7952,8 @@ static void general_write_handler(rarch_setting_t *setting) case MENU_ENUM_LABEL_MIDI_OUTPUT: { settings_t *settings = config_get_ptr(); - midi_driver_set_output(settings->arrays.midi_output); + midi_driver_set_output(settings, + settings->arrays.midi_output); } break; case MENU_ENUM_LABEL_MIDI_VOLUME: diff --git a/midi_driver.c b/midi_driver.c new file mode 100644 index 0000000000..3a93ac3978 --- /dev/null +++ b/midi_driver.c @@ -0,0 +1,618 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2010-2014 - Hans-Kristian Arntzen + * Copyright (C) 2011-2021 - Daniel De Matteis + * + * 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 . + */ + +#include +#include +#include + +#include "configuration.h" +#include "midi_driver.h" +#include "verbosity.h" + +#define MIDI_DRIVER_BUF_SIZE 4096 + +static void *rarch_midi_drv_data; +static struct string_list *rarch_midi_drv_inputs; +static struct string_list *rarch_midi_drv_outputs; +static uint8_t *rarch_midi_drv_input_buffer; +static uint8_t *rarch_midi_drv_output_buffer; + +static midi_event_t rarch_midi_drv_input_event; /* ptr alignment */ +static midi_event_t rarch_midi_drv_output_event; /* ptr alignment */ + +static bool rarch_midi_drv_input_enabled; +static bool rarch_midi_drv_output_enabled; +static bool rarch_midi_drv_output_pending; + +static void null_midi_free(void *p) { } +static void *null_midi_init(const char *input, const char *output) { return (void*)-1; } +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 bool null_midi_set_input(void *p, const char *input) { return input == NULL || string_is_equal(input, "Null"); } +static bool null_midi_set_output(void *p, const char *output) { return output == NULL || string_is_equal(output, "Null"); } +static bool null_midi_read(void *p, midi_event_t *event) { return false; } +static bool null_midi_write(void *p, const midi_event_t *event) { return true; } +static bool null_midi_flush(void *p) { return true; } + +static 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 +}; + +static midi_driver_t *midi_drv = &midi_null; + +midi_driver_t *midi_drivers[] = { +#if defined(HAVE_ALSA) && !defined(HAVE_HAKCHI) && !defined(HAVE_SEGAM) && !defined(DINGUX) + &midi_alsa, +#endif +#ifdef HAVE_WINMM + &midi_winmm, +#endif + &midi_null +}; + +static midi_driver_t *midi_driver_find_driver(const char *ident) +{ + unsigned i; + + for (i = 0; i < ARRAY_SIZE(midi_drivers); ++i) + { + if (string_is_equal(midi_drivers[i]->ident, ident)) + return midi_drivers[i]; + } + + RARCH_ERR("[MIDI]: Unknown driver \"%s\", falling back to \"null\" driver.\n", ident); + + return &midi_null; +} + +const void *midi_driver_find_handle(int index) +{ + if (index < 0 || index >= ARRAY_SIZE(midi_drivers)) + return NULL; + + return midi_drivers[index]; +} + +struct string_list *midi_driver_get_avail_inputs(void) +{ + return rarch_midi_drv_inputs; +} + +struct string_list *midi_driver_get_avail_outputs(void) +{ + return rarch_midi_drv_outputs; +} + +bool midi_driver_set_all_sounds_off(void) +{ + midi_event_t event; + uint8_t i; + uint8_t data[3] = { 0xB0, 120, 0 }; + bool result = true; + + if (!rarch_midi_drv_data || !rarch_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(rarch_midi_drv_data, &event)) + result = false; + } + + if (!midi_drv->flush(rarch_midi_drv_data)) + result = false; + + if (!result) + RARCH_ERR("[MIDI]: All sounds off failed.\n"); + + return result; +} + +bool midi_driver_set_volume(unsigned volume) +{ + midi_event_t event; + uint8_t data[8] = { + 0xF0, 0x7F, 0x7F, 0x04, 0x01, 0, 0, 0xF7}; + + if (!rarch_midi_drv_data || !rarch_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(rarch_midi_drv_data, &event)) + { + RARCH_ERR("[MIDI]: Volume change failed.\n"); + return false; + } + + return true; +} + +static bool midi_driver_init_io_buffers(void) +{ + uint8_t *midi_drv_input_buffer = (uint8_t*)malloc(MIDI_DRIVER_BUF_SIZE); + uint8_t *midi_drv_output_buffer = (uint8_t*)malloc(MIDI_DRIVER_BUF_SIZE); + + if (!midi_drv_input_buffer || !midi_drv_output_buffer) + { + if (midi_drv_input_buffer) + free(midi_drv_input_buffer); + if (midi_drv_output_buffer) + free(midi_drv_output_buffer); + return false; + } + + rarch_midi_drv_input_buffer = midi_drv_input_buffer; + rarch_midi_drv_output_buffer = midi_drv_output_buffer; + + rarch_midi_drv_input_event.data = midi_drv_input_buffer; + rarch_midi_drv_input_event.data_size = 0; + + rarch_midi_drv_output_event.data = midi_drv_output_buffer; + rarch_midi_drv_output_event.data_size = 0; + + return true; +} + +void midi_driver_free(void) +{ + if (rarch_midi_drv_data) + { + midi_drv->free(rarch_midi_drv_data); + rarch_midi_drv_data = NULL; + } + + if (rarch_midi_drv_inputs) + { + string_list_free(rarch_midi_drv_inputs); + rarch_midi_drv_inputs = NULL; + } + + if (rarch_midi_drv_outputs) + { + string_list_free(rarch_midi_drv_outputs); + rarch_midi_drv_outputs = NULL; + } + + if (rarch_midi_drv_input_buffer) + { + free(rarch_midi_drv_input_buffer); + rarch_midi_drv_input_buffer = NULL; + } + + if (rarch_midi_drv_output_buffer) + { + free(rarch_midi_drv_output_buffer); + rarch_midi_drv_output_buffer = NULL; + } + + rarch_midi_drv_input_enabled = false; + rarch_midi_drv_output_enabled = false; +} + +bool midi_driver_init(void *data) +{ + union string_list_elem_attr + attr = {0}; + bool ret = true; + settings_t *settings = (settings_t*)data; + + rarch_midi_drv_inputs = string_list_new(); + rarch_midi_drv_outputs = string_list_new(); + + if (!rarch_midi_drv_inputs || !rarch_midi_drv_outputs) + ret = false; + else if (!string_list_append(rarch_midi_drv_inputs, "Off", attr) || + !string_list_append(rarch_midi_drv_outputs, "Off", attr)) + ret = false; + else + { + char * input = NULL; + char * output = NULL; + + midi_drv = midi_driver_find_driver( + settings->arrays.midi_driver); + + if (strcmp(midi_drv->ident, settings->arrays.midi_driver)) + { + configuration_set_string(settings, + settings->arrays.midi_driver, midi_drv->ident); + } + + if (!midi_drv->get_avail_inputs(rarch_midi_drv_inputs)) + ret = false; + else if (!midi_drv->get_avail_outputs(rarch_midi_drv_outputs)) + ret = false; + else + { + if (string_is_not_equal(settings->arrays.midi_input, "Off")) + { + if (string_list_find_elem(rarch_midi_drv_inputs, settings->arrays.midi_input)) + input = settings->arrays.midi_input; + else + { + RARCH_WARN("[MIDI]: Input device \"%s\" unavailable.\n", + settings->arrays.midi_input); + configuration_set_string(settings, + settings->arrays.midi_input, "Off"); + } + } + + if (string_is_not_equal(settings->arrays.midi_output, "Off")) + { + if (string_list_find_elem(rarch_midi_drv_outputs, settings->arrays.midi_output)) + output = settings->arrays.midi_output; + else + { + RARCH_WARN("[MIDI]: Output device \"%s\" unavailable.\n", + settings->arrays.midi_output); + configuration_set_string(settings, + settings->arrays.midi_output, "Off"); + } + } + + rarch_midi_drv_data = midi_drv->init(input, output); + if (!rarch_midi_drv_data) + ret = false; + else + { + rarch_midi_drv_input_enabled = (input != NULL); + rarch_midi_drv_output_enabled = (output != NULL); + + if (!midi_driver_init_io_buffers()) + ret = false; + else + { + if (input) + RARCH_LOG("[MIDI]: Input device \"%s\".\n", input); + + if (output) + { + RARCH_LOG("[MIDI]: Output device \"%s\".\n", output); + midi_driver_set_volume(settings->uints.midi_volume); + } + } + } + } + } + + if (!ret) + { + midi_driver_free(); + RARCH_ERR("[MIDI]: Initialization failed.\n"); + return false; + } + return true; +} + +bool midi_driver_set_input(const char *input) +{ + if (!rarch_midi_drv_data) + { +#ifdef DEBUG + RARCH_ERR("[MIDI]: midi_driver_set_input called on uninitialized driver.\n"); +#endif + return false; + } + + if (string_is_equal(input, "Off")) + input = NULL; + + if (!midi_drv->set_input(rarch_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"); + + rarch_midi_drv_input_enabled = input != NULL; + + return true; +} + +bool midi_driver_set_output(void *settings_data, const char *output) +{ + settings_t *settings = (settings_t*)settings_data; + + if (!rarch_midi_drv_data) + { +#ifdef DEBUG + RARCH_ERR("[MIDI]: midi_driver_set_output called on uninitialized driver.\n"); +#endif + return false; + } + + if (string_is_equal(output, "Off")) + output = NULL; + + if (!midi_drv->set_output(rarch_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) + { + rarch_midi_drv_output_enabled = true; + RARCH_LOG("[MIDI]: Output device changed to \"%s\".\n", output); + + midi_driver_set_volume(settings->uints.midi_volume); + } + else + { + rarch_midi_drv_output_enabled = false; + RARCH_LOG("[MIDI]: Output disabled.\n"); + } + + return true; +} + +bool midi_driver_input_enabled(void) +{ + return rarch_midi_drv_input_enabled; +} + +bool midi_driver_output_enabled(void) +{ + return rarch_midi_drv_output_enabled; +} + +bool midi_driver_read(uint8_t *byte) +{ + static int i; + + if (!rarch_midi_drv_data || !rarch_midi_drv_input_enabled || !byte) + { +#ifdef DEBUG + if (!rarch_midi_drv_data) + RARCH_ERR("[MIDI]: midi_driver_read called on uninitialized driver.\n"); + else if (!rarch_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 == rarch_midi_drv_input_event.data_size) + { + rarch_midi_drv_input_event.data_size = MIDI_DRIVER_BUF_SIZE; + if (!midi_drv->read(rarch_midi_drv_data, + &rarch_midi_drv_input_event)) + { + rarch_midi_drv_input_event.data_size = i; + return false; + } + + i = 0; + +#ifdef DEBUG + if (rarch_midi_drv_input_event.data_size == 1) + RARCH_LOG("[MIDI]: In [0x%02X].\n", + rarch_midi_drv_input_event.data[0]); + else if (rarch_midi_drv_input_event.data_size == 2) + RARCH_LOG("[MIDI]: In [0x%02X, 0x%02X].\n", + rarch_midi_drv_input_event.data[0], + rarch_midi_drv_input_event.data[1]); + else if (rarch_midi_drv_input_event.data_size == 3) + RARCH_LOG("[MIDI]: In [0x%02X, 0x%02X, 0x%02X].\n", + rarch_midi_drv_input_event.data[0], + rarch_midi_drv_input_event.data[1], + rarch_midi_drv_input_event.data[2]); + else + RARCH_LOG("[MIDI]: In [0x%02X, ...], size %u.\n", + rarch_midi_drv_input_event.data[0], + rarch_midi_drv_input_event.data_size); +#endif + } + + *byte = rarch_midi_drv_input_event.data[i++]; + + return true; +} + +bool midi_driver_write(uint8_t byte, uint32_t delta_time) +{ + static int event_size; + + if (!rarch_midi_drv_data || !rarch_midi_drv_output_enabled) + { +#ifdef DEBUG + if (!rarch_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 ( rarch_midi_drv_output_event.data_size && + rarch_midi_drv_output_event.data[0] == 0xF0) + { + if (byte == 0xF7) + event_size = (int)rarch_midi_drv_output_event.data_size + 1; + else + { + if (!midi_drv->write(rarch_midi_drv_data, + &rarch_midi_drv_output_event)) + return false; + +#ifdef DEBUG + switch (rarch_midi_drv_output_event.data_size) + { + case 1: + RARCH_LOG("[MIDI]: Out [0x%02X].\n", + rarch_midi_drv_output_event.data[0]); + break; + case 2: + RARCH_LOG("[MIDI]: Out [0x%02X, 0x%02X].\n", + rarch_midi_drv_output_event.data[0], + rarch_midi_drv_output_event.data[1]); + break; + case 3: + RARCH_LOG("[MIDI]: Out [0x%02X, 0x%02X, 0x%02X].\n", + rarch_midi_drv_output_event.data[0], + rarch_midi_drv_output_event.data[1], + rarch_midi_drv_output_event.data[2]); + break; + default: + RARCH_LOG("[MIDI]: Out [0x%02X, ...], size %u.\n", + rarch_midi_drv_output_event.data[0], + rarch_midi_drv_output_event.data_size); + break; + } +#endif + + rarch_midi_drv_output_pending = true; + event_size = (int)midi_driver_get_event_size(byte); + rarch_midi_drv_output_event.data_size = 0; + rarch_midi_drv_output_event.delta_time = 0; + } + } + else + { + event_size = (int)midi_driver_get_event_size(byte); + rarch_midi_drv_output_event.data_size = 0; + rarch_midi_drv_output_event.delta_time = 0; + } + } + + if (rarch_midi_drv_output_event.data_size < MIDI_DRIVER_BUF_SIZE) + { + rarch_midi_drv_output_event.data[rarch_midi_drv_output_event.data_size] = byte; + ++rarch_midi_drv_output_event.data_size; + rarch_midi_drv_output_event.delta_time += delta_time; + } + else + { +#ifdef DEBUG + RARCH_ERR("[MIDI]: Output event dropped.\n"); +#endif + return false; + } + + if (rarch_midi_drv_output_event.data_size == event_size) + { + if (!midi_drv->write(rarch_midi_drv_data, + &rarch_midi_drv_output_event)) + return false; + +#ifdef DEBUG + switch (rarch_midi_drv_output_event.data_size) + { + case 1: + RARCH_LOG("[MIDI]: Out [0x%02X].\n", + rarch_midi_drv_output_event.data[0]); + break; + case 2: + RARCH_LOG("[MIDI]: Out [0x%02X, 0x%02X].\n", + rarch_midi_drv_output_event.data[0], + rarch_midi_drv_output_event.data[1]); + break; + case 3: + RARCH_LOG("[MIDI]: Out [0x%02X, 0x%02X, 0x%02X].\n", + rarch_midi_drv_output_event.data[0], + rarch_midi_drv_output_event.data[1], + rarch_midi_drv_output_event.data[2]); + break; + default: + RARCH_LOG("[MIDI]: Out [0x%02X, ...], size %u.\n", + rarch_midi_drv_output_event.data[0], + rarch_midi_drv_output_event.data_size); + break; + } +#endif + + rarch_midi_drv_output_pending = true; + rarch_midi_drv_output_event.data_size = 0; + rarch_midi_drv_output_event.delta_time = 0; + } + + return true; +} + +bool midi_driver_flush(void) +{ + if (!rarch_midi_drv_data) + return false; + + if (rarch_midi_drv_output_pending) + rarch_midi_drv_output_pending = + !midi_drv->flush(rarch_midi_drv_data); + + return !rarch_midi_drv_output_pending; +} + +size_t midi_driver_get_event_size(uint8_t status) +{ + 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 + }; + + 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]; +} diff --git a/midi/midi_driver.h b/midi_driver.h similarity index 94% rename from midi/midi_driver.h rename to midi_driver.h index 9828b0de65..b2c87894ee 100644 --- a/midi/midi_driver.h +++ b/midi_driver.h @@ -207,7 +207,7 @@ struct string_list *midi_driver_get_avail_outputs(void); bool midi_driver_set_volume(unsigned volume); bool midi_driver_set_input(const char *input); -bool midi_driver_set_output(const char *output); +bool midi_driver_set_output(void *data, const char *output); /** * midi_driver_get_event_size: @@ -222,6 +222,29 @@ bool midi_driver_set_output(const char *output); **/ size_t midi_driver_get_event_size(uint8_t status); +bool midi_driver_input_enabled(void); + +bool midi_driver_output_enabled(void); + +bool midi_driver_flush(void); + +bool midi_driver_read(uint8_t *byte); + +bool midi_driver_write(uint8_t byte, uint32_t delta_time); + +bool midi_driver_init(void *data); + +void midi_driver_free(void); + +bool midi_driver_set_all_sounds_off(void); + +const void *midi_driver_find_handle(int index); + +extern midi_driver_t midi_winmm; +extern midi_driver_t midi_alsa; + +extern midi_driver_t *midi_drivers[]; + RETRO_END_DECLS #endif diff --git a/retroarch.c b/retroarch.c index 0cb5feae8d..bae2a70730 100644 --- a/retroarch.c +++ b/retroarch.c @@ -236,7 +236,7 @@ #include "wifi/wifi_driver.h" #include "misc/cpufreq/cpufreq.h" #include "led/led_driver.h" -#include "midi/midi_driver.h" +#include "midi_driver.h" #include "core.h" #include "configuration.h" #include "list_special.h" @@ -10126,7 +10126,7 @@ bool command_event(enum event_command cmd, void *data) #endif break; case CMD_EVENT_AUDIO_STOP: - midi_driver_set_all_sounds_off(p_rarch); + midi_driver_set_all_sounds_off(); if (!audio_driver_stop(p_rarch)) return false; break; @@ -20466,567 +20466,6 @@ void config_read_keybinds_conf(void *data) } } -/* MIDI */ - -static midi_driver_t *midi_driver_find_driver(const char *ident) -{ - unsigned i; - - for (i = 0; i < ARRAY_SIZE(midi_drivers); ++i) - { - if (string_is_equal(midi_drivers[i]->ident, ident)) - return midi_drivers[i]; - } - - RARCH_ERR("[MIDI]: Unknown driver \"%s\", falling back to \"null\" driver.\n", ident); - - return &midi_null; -} - -static const void *midi_driver_find_handle(int index) -{ - if (index < 0 || index >= ARRAY_SIZE(midi_drivers)) - return NULL; - - return midi_drivers[index]; -} - -struct string_list *midi_driver_get_avail_inputs(void) -{ - struct rarch_state *p_rarch = &rarch_st; - return p_rarch->midi_drv_inputs; -} - -struct string_list *midi_driver_get_avail_outputs(void) -{ - struct rarch_state *p_rarch = &rarch_st; - return p_rarch->midi_drv_outputs; -} - -static bool midi_driver_set_all_sounds_off(struct rarch_state *p_rarch) -{ - midi_event_t event; - uint8_t i; - uint8_t data[3] = { 0xB0, 120, 0 }; - bool result = true; - - if (!p_rarch->midi_drv_data || !p_rarch->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(p_rarch->midi_drv_data, &event)) - result = false; - } - - if (!midi_drv->flush(p_rarch->midi_drv_data)) - result = false; - - if (!result) - RARCH_ERR("[MIDI]: All sounds off failed.\n"); - - return result; -} - -bool midi_driver_set_volume(unsigned volume) -{ - midi_event_t event; - struct rarch_state *p_rarch = &rarch_st; - uint8_t data[8] = { - 0xF0, 0x7F, 0x7F, 0x04, 0x01, 0, 0, 0xF7}; - - if (!p_rarch->midi_drv_data || !p_rarch->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(p_rarch->midi_drv_data, &event)) - { - RARCH_ERR("[MIDI]: Volume change failed.\n"); - return false; - } - - return true; -} - -static bool midi_driver_init_io_buffers(struct rarch_state *p_rarch) -{ - uint8_t *midi_drv_input_buffer = (uint8_t*)malloc(MIDI_DRIVER_BUF_SIZE); - uint8_t *midi_drv_output_buffer = (uint8_t*)malloc(MIDI_DRIVER_BUF_SIZE); - - if (!midi_drv_input_buffer || !midi_drv_output_buffer) - { - if (midi_drv_input_buffer) - free(midi_drv_input_buffer); - if (midi_drv_output_buffer) - free(midi_drv_output_buffer); - return false; - } - - p_rarch->midi_drv_input_buffer = midi_drv_input_buffer; - p_rarch->midi_drv_output_buffer = midi_drv_output_buffer; - - p_rarch->midi_drv_input_event.data = midi_drv_input_buffer; - p_rarch->midi_drv_input_event.data_size = 0; - - p_rarch->midi_drv_output_event.data = midi_drv_output_buffer; - p_rarch->midi_drv_output_event.data_size = 0; - - return true; -} - -static void midi_driver_free(struct rarch_state *p_rarch) -{ - if (p_rarch->midi_drv_data) - { - midi_drv->free(p_rarch->midi_drv_data); - p_rarch->midi_drv_data = NULL; - } - - if (p_rarch->midi_drv_inputs) - { - string_list_free(p_rarch->midi_drv_inputs); - p_rarch->midi_drv_inputs = NULL; - } - - if (p_rarch->midi_drv_outputs) - { - string_list_free(p_rarch->midi_drv_outputs); - p_rarch->midi_drv_outputs = NULL; - } - - if (p_rarch->midi_drv_input_buffer) - { - free(p_rarch->midi_drv_input_buffer); - p_rarch->midi_drv_input_buffer = NULL; - } - - if (p_rarch->midi_drv_output_buffer) - { - free(p_rarch->midi_drv_output_buffer); - p_rarch->midi_drv_output_buffer = NULL; - } - - p_rarch->midi_drv_input_enabled = false; - p_rarch->midi_drv_output_enabled = false; -} - -static bool midi_driver_init(struct rarch_state *p_rarch, - settings_t *settings) -{ - union string_list_elem_attr attr = {0}; - bool ret = true; - - p_rarch->midi_drv_inputs = string_list_new(); - p_rarch->midi_drv_outputs = string_list_new(); - - if (!p_rarch->midi_drv_inputs || !p_rarch->midi_drv_outputs) - ret = false; - else if (!string_list_append(p_rarch->midi_drv_inputs, "Off", attr) || - !string_list_append(p_rarch->midi_drv_outputs, "Off", attr)) - ret = false; - else - { - char * input = NULL; - char * output = NULL; - - midi_drv = midi_driver_find_driver( - settings->arrays.midi_driver); - - if (strcmp(midi_drv->ident, settings->arrays.midi_driver)) - { - configuration_set_string(settings, - settings->arrays.midi_driver, midi_drv->ident); - } - - if (!midi_drv->get_avail_inputs(p_rarch->midi_drv_inputs)) - ret = false; - else if (!midi_drv->get_avail_outputs(p_rarch->midi_drv_outputs)) - ret = false; - else - { - if (string_is_not_equal(settings->arrays.midi_input, "Off")) - { - if (string_list_find_elem(p_rarch->midi_drv_inputs, settings->arrays.midi_input)) - input = settings->arrays.midi_input; - else - { - RARCH_WARN("[MIDI]: Input device \"%s\" unavailable.\n", - settings->arrays.midi_input); - configuration_set_string(settings, - settings->arrays.midi_input, "Off"); - } - } - - if (string_is_not_equal(settings->arrays.midi_output, "Off")) - { - if (string_list_find_elem(p_rarch->midi_drv_outputs, settings->arrays.midi_output)) - output = settings->arrays.midi_output; - else - { - RARCH_WARN("[MIDI]: Output device \"%s\" unavailable.\n", - settings->arrays.midi_output); - configuration_set_string(settings, - settings->arrays.midi_output, "Off"); - } - } - - p_rarch->midi_drv_data = midi_drv->init(input, output); - if (!p_rarch->midi_drv_data) - ret = false; - else - { - p_rarch->midi_drv_input_enabled = (input != NULL); - p_rarch->midi_drv_output_enabled = (output != NULL); - - if (!midi_driver_init_io_buffers(p_rarch)) - ret = false; - else - { - if (input) - RARCH_LOG("[MIDI]: Input device \"%s\".\n", input); - - if (output) - { - RARCH_LOG("[MIDI]: Output device \"%s\".\n", output); - midi_driver_set_volume(settings->uints.midi_volume); - } - } - } - } - } - - if (!ret) - { - midi_driver_free(p_rarch); - RARCH_ERR("[MIDI]: Initialization failed.\n"); - return false; - } - return true; -} - -bool midi_driver_set_input(const char *input) -{ - struct rarch_state *p_rarch = &rarch_st; - - if (!p_rarch->midi_drv_data) - { -#ifdef DEBUG - RARCH_ERR("[MIDI]: midi_driver_set_input called on uninitialized driver.\n"); -#endif - return false; - } - - if (string_is_equal(input, "Off")) - input = NULL; - - if (!midi_drv->set_input(p_rarch->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"); - - p_rarch->midi_drv_input_enabled = input != NULL; - - return true; -} - -bool midi_driver_set_output(const char *output) -{ - struct rarch_state *p_rarch = &rarch_st; - - if (!p_rarch->midi_drv_data) - { -#ifdef DEBUG - RARCH_ERR("[MIDI]: midi_driver_set_output called on uninitialized driver.\n"); -#endif - return false; - } - - if (string_is_equal(output, "Off")) - output = NULL; - - if (!midi_drv->set_output(p_rarch->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 *settings = p_rarch->configuration_settings; - - p_rarch->midi_drv_output_enabled = true; - RARCH_LOG("[MIDI]: Output device changed to \"%s\".\n", output); - - if (settings) - midi_driver_set_volume(settings->uints.midi_volume); - else - RARCH_ERR("[MIDI]: Volume change failed (settings unavailable).\n"); - } - else - { - p_rarch->midi_drv_output_enabled = false; - RARCH_LOG("[MIDI]: Output disabled.\n"); - } - - return true; -} - -static bool midi_driver_input_enabled(void) -{ - struct rarch_state *p_rarch = &rarch_st; - return p_rarch->midi_drv_input_enabled; -} - -static bool midi_driver_output_enabled(void) -{ - struct rarch_state *p_rarch = &rarch_st; - return p_rarch->midi_drv_output_enabled; -} - -static bool midi_driver_read(uint8_t *byte) -{ - static int i; - struct rarch_state *p_rarch = &rarch_st; - - if (!p_rarch->midi_drv_data || !p_rarch->midi_drv_input_enabled || !byte) - { -#ifdef DEBUG - if (!p_rarch->midi_drv_data) - RARCH_ERR("[MIDI]: midi_driver_read called on uninitialized driver.\n"); - else if (!p_rarch->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 == p_rarch->midi_drv_input_event.data_size) - { - p_rarch->midi_drv_input_event.data_size = MIDI_DRIVER_BUF_SIZE; - if (!midi_drv->read(p_rarch->midi_drv_data, - &p_rarch->midi_drv_input_event)) - { - p_rarch->midi_drv_input_event.data_size = i; - return false; - } - - i = 0; - -#ifdef DEBUG - if (p_rarch->midi_drv_input_event.data_size == 1) - RARCH_LOG("[MIDI]: In [0x%02X].\n", - p_rarch->midi_drv_input_event.data[0]); - else if (p_rarch->midi_drv_input_event.data_size == 2) - RARCH_LOG("[MIDI]: In [0x%02X, 0x%02X].\n", - p_rarch->midi_drv_input_event.data[0], - p_rarch->midi_drv_input_event.data[1]); - else if (p_rarch->midi_drv_input_event.data_size == 3) - RARCH_LOG("[MIDI]: In [0x%02X, 0x%02X, 0x%02X].\n", - p_rarch->midi_drv_input_event.data[0], - p_rarch->midi_drv_input_event.data[1], - p_rarch->midi_drv_input_event.data[2]); - else - RARCH_LOG("[MIDI]: In [0x%02X, ...], size %u.\n", - p_rarch->midi_drv_input_event.data[0], - p_rarch->midi_drv_input_event.data_size); -#endif - } - - *byte = p_rarch->midi_drv_input_event.data[i++]; - - return true; -} - -static bool midi_driver_write(uint8_t byte, uint32_t delta_time) -{ - static int event_size; - struct rarch_state *p_rarch = &rarch_st; - - if (!p_rarch->midi_drv_data || !p_rarch->midi_drv_output_enabled) - { -#ifdef DEBUG - if (!p_rarch->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 (p_rarch->midi_drv_output_event.data_size && - p_rarch->midi_drv_output_event.data[0] == 0xF0) - { - if (byte == 0xF7) - event_size = (int)p_rarch->midi_drv_output_event.data_size + 1; - else - { - if (!midi_drv->write(p_rarch->midi_drv_data, - &p_rarch->midi_drv_output_event)) - return false; - -#ifdef DEBUG - switch (p_rarch->midi_drv_output_event.data_size) - { - case 1: - RARCH_LOG("[MIDI]: Out [0x%02X].\n", - p_rarch->midi_drv_output_event.data[0]); - break; - case 2: - RARCH_LOG("[MIDI]: Out [0x%02X, 0x%02X].\n", - p_rarch->midi_drv_output_event.data[0], - p_rarch->midi_drv_output_event.data[1]); - break; - case 3: - RARCH_LOG("[MIDI]: Out [0x%02X, 0x%02X, 0x%02X].\n", - p_rarch->midi_drv_output_event.data[0], - p_rarch->midi_drv_output_event.data[1], - p_rarch->midi_drv_output_event.data[2]); - break; - default: - RARCH_LOG("[MIDI]: Out [0x%02X, ...], size %u.\n", - p_rarch->midi_drv_output_event.data[0], - p_rarch->midi_drv_output_event.data_size); - break; - } -#endif - - p_rarch->midi_drv_output_pending = true; - event_size = (int)midi_driver_get_event_size(byte); - p_rarch->midi_drv_output_event.data_size = 0; - p_rarch->midi_drv_output_event.delta_time = 0; - } - } - else - { - event_size = (int)midi_driver_get_event_size(byte); - p_rarch->midi_drv_output_event.data_size = 0; - p_rarch->midi_drv_output_event.delta_time = 0; - } - } - - if (p_rarch->midi_drv_output_event.data_size < MIDI_DRIVER_BUF_SIZE) - { - p_rarch->midi_drv_output_event.data[p_rarch->midi_drv_output_event.data_size] = byte; - ++p_rarch->midi_drv_output_event.data_size; - p_rarch->midi_drv_output_event.delta_time += delta_time; - } - else - { -#ifdef DEBUG - RARCH_ERR("[MIDI]: Output event dropped.\n"); -#endif - return false; - } - - if (p_rarch->midi_drv_output_event.data_size == event_size) - { - if (!midi_drv->write(p_rarch->midi_drv_data, - &p_rarch->midi_drv_output_event)) - return false; - -#ifdef DEBUG - switch (p_rarch->midi_drv_output_event.data_size) - { - case 1: - RARCH_LOG("[MIDI]: Out [0x%02X].\n", - p_rarch->midi_drv_output_event.data[0]); - break; - case 2: - RARCH_LOG("[MIDI]: Out [0x%02X, 0x%02X].\n", - p_rarch->midi_drv_output_event.data[0], - p_rarch->midi_drv_output_event.data[1]); - break; - case 3: - RARCH_LOG("[MIDI]: Out [0x%02X, 0x%02X, 0x%02X].\n", - p_rarch->midi_drv_output_event.data[0], - p_rarch->midi_drv_output_event.data[1], - p_rarch->midi_drv_output_event.data[2]); - break; - default: - RARCH_LOG("[MIDI]: Out [0x%02X, ...], size %u.\n", - p_rarch->midi_drv_output_event.data[0], - p_rarch->midi_drv_output_event.data_size); - break; - } -#endif - - p_rarch->midi_drv_output_pending = true; - p_rarch->midi_drv_output_event.data_size = 0; - p_rarch->midi_drv_output_event.delta_time = 0; - } - - return true; -} - -static bool midi_driver_flush(void) -{ - struct rarch_state *p_rarch = &rarch_st; - if (!p_rarch->midi_drv_data) - return false; - - if (p_rarch->midi_drv_output_pending) - p_rarch->midi_drv_output_pending = - !midi_drv->flush(p_rarch->midi_drv_data); - - return !p_rarch->midi_drv_output_pending; -} - -size_t midi_driver_get_event_size(uint8_t status) -{ - 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 - }; - - 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]; -} - /* AUDIO */ static enum resampler_quality audio_driver_get_resampler_quality( @@ -26854,7 +26293,7 @@ static void drivers_init(struct rarch_state *p_rarch, /* Initialize MIDI driver */ if (flags & DRIVER_MIDI_MASK) - midi_driver_init(p_rarch, settings); + midi_driver_init(settings); #ifdef HAVE_LAKKA cpu_scaling_driver_init(); @@ -26950,7 +26389,7 @@ static void driver_uninit(struct rarch_state *p_rarch, int flags) p_rarch->audio_driver_context_audio_data = NULL; if (flags & DRIVER_MIDI_MASK) - midi_driver_free(p_rarch); + midi_driver_free(); #ifdef HAVE_LAKKA cpu_scaling_driver_free(); diff --git a/retroarch_data.h b/retroarch_data.h index 7e8d7e6394..e7e0a62ba8 100644 --- a/retroarch_data.h +++ b/retroarch_data.h @@ -81,8 +81,6 @@ #define MENU_SOUND_FORMATS "ogg|mod|xm|s3m|mp3|flac|wav" -#define MIDI_DRIVER_BUF_SIZE 4096 - /** * db_to_gain: * @db : Decibels. @@ -880,42 +878,6 @@ static const record_driver_t *record_drivers[] = { NULL, }; -extern midi_driver_t midi_winmm; -extern midi_driver_t midi_alsa; - -static void null_midi_free(void *p) { } -static void *null_midi_init(const char *input, const char *output) { return (void*)-1; } -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 bool null_midi_set_input(void *p, const char *input) { return input == NULL || string_is_equal(input, "Null"); } -static bool null_midi_set_output(void *p, const char *output) { return output == NULL || string_is_equal(output, "Null"); } -static bool null_midi_read(void *p, midi_event_t *event) { return false; } -static bool null_midi_write(void *p, const midi_event_t *event) { return true; } -static bool null_midi_flush(void *p) { return true; } - -static 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 -}; - -static midi_driver_t *midi_drivers[] = { -#if defined(HAVE_ALSA) && !defined(HAVE_HAKCHI) && !defined(HAVE_SEGAM) && !defined(DINGUX) - &midi_alsa, -#endif -#ifdef HAVE_WINMM - &midi_winmm, -#endif - &midi_null -}; - static void *nullcamera_init(const char *device, uint64_t caps, unsigned width, unsigned height) { return (void*)-1; } static void nullcamera_free(void *data) { } @@ -1246,13 +1208,9 @@ struct rarch_state #endif struct string_list *subsystem_fullpaths; - struct string_list *midi_drv_inputs; - struct string_list *midi_drv_outputs; struct string_list *audio_driver_devices_list; uint8_t *video_driver_record_gpu_buffer; - uint8_t *midi_drv_input_buffer; - uint8_t *midi_drv_output_buffer; bool *load_no_content_hook; float *audio_driver_output_samples_buf; char *osk_grid[45]; @@ -1277,8 +1235,6 @@ struct rarch_state const camera_driver_t *camera_driver; void *camera_data; - void *midi_drv_data; - const ui_companion_driver_t *ui_companion; void *ui_companion_data; @@ -1385,8 +1341,6 @@ struct rarch_state gfx_ctx_driver_t current_video_context; /* ptr alignment */ content_state_t content_st; /* ptr alignment */ - midi_event_t midi_drv_input_event; /* ptr alignment */ - midi_event_t midi_drv_output_event; /* ptr alignment */ core_info_state_t core_info_st; /* ptr alignment */ struct retro_hw_render_callback hw_render; /* ptr alignment */ #ifdef HAVE_BSV_MOVIE @@ -1774,10 +1728,6 @@ struct rarch_state bool recording_enable; bool streaming_enable; - bool midi_drv_input_enabled; - bool midi_drv_output_enabled; - - bool midi_drv_output_pending; bool main_ui_companion_is_on_foreground; bool keyboard_mapping_blocked; @@ -1818,7 +1768,6 @@ static runloop_core_status_msg_t runloop_core_status_msg = extern u32 __nx_applet_type; #endif -static midi_driver_t *midi_drv = &midi_null; static const video_display_server_t *current_display_server = &dispserv_null; struct aspect_ratio_elem aspectratio_lut[ASPECT_RATIO_END] = { diff --git a/retroarch_fwd_decls.h b/retroarch_fwd_decls.h index 23fa9133d7..ce67bcee78 100644 --- a/retroarch_fwd_decls.h +++ b/retroarch_fwd_decls.h @@ -36,14 +36,6 @@ static void deinit_netplay(struct rarch_state *p_rarch); static void retroarch_deinit_drivers(struct rarch_state *p_rarch, struct retro_callbacks *cbs); -static bool midi_driver_read(uint8_t *byte); -static bool midi_driver_write(uint8_t byte, uint32_t delta_time); -static bool midi_driver_output_enabled(void); -static bool midi_driver_input_enabled(void); -static bool midi_driver_set_all_sounds_off(struct rarch_state *p_rarch); -static const void *midi_driver_find_handle(int index); -static bool midi_driver_flush(void); - static void retroarch_deinit_core_options( bool game_options_active, const char *path_core_options,