diff --git a/src/SOUND/midi.c b/src/SOUND/midi.c index d8b1a8d8f..6f3de8fba 100644 --- a/src/SOUND/midi.c +++ b/src/SOUND/midi.c @@ -26,6 +26,7 @@ static MIDI_DEVICE devices[] = {"None", "none", NULL}, {SYSTEM_MIDI_NAME, SYSTEM_MIDI_INTERNAL_NAME, &system_midi_device}, {"Roland MT-32 Emulation", "mt32", &mt32_device}, + {"Roland CM-32L Emulation", "cm32l", &cm32l_device}, {"", "", NULL} }; diff --git a/src/SOUND/midi.h b/src/SOUND/midi.h index 371c79eb4..bba31233a 100644 --- a/src/SOUND/midi.h +++ b/src/SOUND/midi.h @@ -10,10 +10,11 @@ void midi_device_init(); typedef struct midi_device_t { - void (*play_sysex)(uint8_t *sysex, unsigned int len); - void (*play_msg)(uint8_t *msg); - void (*poll)(); - int (*write)(uint8_t val); + void (*play_sysex)(struct midi_device_t* p, uint8_t *sysex, unsigned int len); + void (*play_msg)(struct midi_device_t* p, uint8_t *msg); + void (*poll)(struct midi_device_t* p); + int (*write)(struct midi_device_t* p, uint8_t val); + void* data; } midi_device_t; void midi_init(midi_device_t* device); diff --git a/src/SOUND/midi_mt32.c b/src/SOUND/midi_mt32.c index 6233f9ae4..047c58484 100644 --- a/src/SOUND/midi_mt32.c +++ b/src/SOUND/midi_mt32.c @@ -3,6 +3,7 @@ #include #include "munt/c_interface/c_interface.h" #include "../WIN/plat_thread.h" +#include "../WIN/plat_ticks.h" #include "../ibm.h" #include "../device.h" #include "../mem.h" @@ -11,9 +12,40 @@ #include "midi.h" #include "sound.h" +#define RENDER_RATE 30 +#define MESSAGE_HIDE 10000 + extern void givealbuffer_midi(void *buf, uint32_t size); extern void pclog(const char *format, ...); extern void al_set_midi(int freq, int buf_size); +extern int soundon; + +typedef struct mt32_t +{ + mt32emu_context context; + char message[MT32EMU_SYSEX_BUFFER_SIZE]; + unsigned int message_shown; + thread_t* thread_h; + event_t* event; + + uint32_t samplerate; + int buf_size; + float* buffer; + int16_t* buffer_int16; + int midi_pos; + + int status_show_instruments; + + char model_name[50]; +} mt32_t; + +void showLCDMessage(void *instance_data, const char *message) +{ + mt32_t* data = (mt32_t*)instance_data; + strncpy(data->message, message, 999); + data->message[999] = 0; + data->message_shown = get_ticks(); +} static const mt32emu_report_handler_i_v0 handler_v0 = { /** Returns the actual interface version ID */ @@ -25,7 +57,7 @@ static const mt32emu_report_handler_i_v0 handler_v0 = { NULL, //void (*onErrorControlROM)(void *instance_data); NULL, //void (*onErrorPCMROM)(void *instance_data); /** Callback for reporting about displaying a new custom message on LCD */ - NULL, //void (*showLCDMessage)(void *instance_data, const char *message); + showLCDMessage, //void (*showLCDMessage)(void *instance_data, const char *message); /** Callback for reporting actual processing of a MIDI message */ NULL, //void (*onMIDIMessagePlayed)(void *instance_data); /** @@ -53,8 +85,7 @@ static const mt32emu_report_handler_i_v0 handler_v0 = { static const mt32emu_report_handler_i handler = { &handler_v0 }; -static mt32emu_context context = NULL; -static int roms_present = -1; +static int roms_present[] = { -1, -1 }; mt32emu_return_code mt32_check(const char* func, mt32emu_return_code ret, mt32emu_return_code expected) { @@ -68,104 +99,118 @@ mt32emu_return_code mt32_check(const char* func, mt32emu_return_code ret, mt32em int mt32_available() { - if (roms_present < 0) - roms_present = (rom_present(L"roms/mt32/mt32_control.rom") && rom_present(L"roms/mt32/mt32_pcm.rom")); - return roms_present; + if (roms_present[0] < 0) + roms_present[0] = (rom_present(L"roms/mt32/mt32_control.rom") && rom_present(L"roms/mt32/mt32_pcm.rom")); + return roms_present[0]; } -static thread_t *thread_h = NULL; -static event_t *event = NULL; +int cm32l_available() +{ + if (roms_present[1] < 0) + roms_present[1] = (rom_present(L"roms/cm32l/cm32l_control.rom") && rom_present(L"roms/cm32l/cm32l_pcm.rom")); + return roms_present[1]; +} -#define RENDER_RATE 30 - -static uint32_t samplerate = 44100; -static int buf_size = 0; -static float* buffer = NULL; -static int16_t* buffer_int16 = NULL; -static int midi_pos = 0; - -void mt32_stream(float* stream, int len) +void mt32_stream(mt32emu_context context, float* stream, int len) { if (context) mt32emu_render_float(context, stream, len); } -void mt32_stream_int16(int16_t* stream, int len) +void mt32_stream_int16(mt32emu_context context, int16_t* stream, int len) { if (context) mt32emu_render_bit16s(context, stream, len); } -void mt32_poll() +void mt32_poll(midi_device_t *device) { - midi_pos++; - if (midi_pos == 48000/RENDER_RATE) + mt32_t *data = (mt32_t *) device->data; + data->midi_pos++; + if (data->midi_pos == 48000/RENDER_RATE) { - midi_pos = 0; - thread_set_event(event); + data->midi_pos = 0; + thread_set_event(data->event); } + if (get_ticks() > data->message_shown+MESSAGE_HIDE) + data->message[0] = 0; } -extern int soundon; - static void mt32_thread(void *param) { + mt32_t *data = (mt32_t *) param; while (1) { - thread_wait_event(event, -1); + thread_wait_event(data->event, -1); if (sound_is_float) { - memset(buffer, 0, buf_size * sizeof(float)); - mt32_stream(buffer, (samplerate/RENDER_RATE)); + memset(data->buffer, 0, data->buf_size * sizeof(float)); + mt32_stream(data->context, data->buffer, data->buf_size / (sizeof(float) << 1)); if (soundon) - givealbuffer_midi(buffer, buf_size); + givealbuffer_midi(data->buffer, data->buf_size); } else { - memset(buffer_int16, 0, buf_size * sizeof(int16_t)); - mt32_stream_int16(buffer_int16, (samplerate/RENDER_RATE)); + memset(data->buffer_int16, 0, data->buf_size * sizeof(int16_t)); + mt32_stream_int16(data->context, data->buffer_int16, data->buf_size / (sizeof(int16_t) << 1)); if (soundon) - givealbuffer_midi(buffer_int16, buf_size); + givealbuffer_midi(data->buffer_int16, data->buf_size); } } } -void mt32_msg(uint8_t* val) +void mt32_msg(midi_device_t *device, uint8_t* val) { + mt32emu_context context = ((mt32_t *)device->data)->context; if (context) mt32_check("mt32emu_play_msg", mt32emu_play_msg(context, *(uint32_t*)val), MT32EMU_RC_OK); } -void mt32_sysex(uint8_t* data, unsigned int len) +void mt32_sysex(midi_device_t *device, uint8_t* data, unsigned int len) { + mt32emu_context context = ((mt32_t *)device->data)->context; if (context) mt32_check("mt32emu_play_sysex", mt32emu_play_sysex(context, data, len), MT32EMU_RC_OK); } -void* mt32_init() +static mt32emu_return_code mt32emu_add_rom_file_ex(mt32emu_context context, wchar_t *s) +{ + char fn[512]; + wcstombs(fn, s, (wcslen(s) << 1) + 2); + return mt32emu_add_rom_file(context, fn); +} + +static void* mt32emu_init(wchar_t* control_rom, wchar_t* pcm_rom) { wchar_t s[512]; - char fn[512]; - context = mt32emu_create_context(handler, NULL); - if (!rom_getfile(L"roms/mt32/mt32_control.rom", s, 512)) return 0; - wcstombs(fn, s, (wcslen(s) << 1) + 2); - if (!mt32_check("mt32emu_add_rom_file", mt32emu_add_rom_file(context, fn), MT32EMU_RC_ADDED_CONTROL_ROM)) return 0; - if (!rom_getfile(L"roms/mt32/mt32_pcm.rom", s, 512)) return 0; - wcstombs(fn, s, (wcslen(s) << 1) + 2); - if (!mt32_check("mt32emu_add_rom_file", mt32emu_add_rom_file(context, fn), MT32EMU_RC_ADDED_PCM_ROM)) return 0; - if (!mt32_check("mt32emu_open_synth", mt32emu_open_synth(context), MT32EMU_RC_OK)) return 0; + mt32_t* data = malloc(sizeof(mt32_t)); + memset(data, 0, sizeof(mt32_t)); + mt32emu_context context = mt32emu_create_context(handler, data); - event = thread_create_event(); - thread_h = thread_create(mt32_thread, 0); - samplerate = mt32emu_get_actual_stereo_output_samplerate(context); - buf_size = samplerate/RENDER_RATE*2; + if ( + !rom_getfile(control_rom, s, 512) || + !mt32_check("mt32emu_add_rom_file", mt32emu_add_rom_file_ex(context, s), MT32EMU_RC_ADDED_CONTROL_ROM) || + !rom_getfile(pcm_rom, s, 512) || + !mt32_check("mt32emu_add_rom_file", mt32emu_add_rom_file_ex(context, s), MT32EMU_RC_ADDED_PCM_ROM) || + !mt32_check("mt32emu_open_synth", mt32emu_open_synth(context), MT32EMU_RC_OK)) + { + free(data); + return 0; + } + + data->samplerate = mt32emu_get_actual_stereo_output_samplerate(context); if (sound_is_float) { - buffer = malloc(buf_size * sizeof(float)); - buffer_int16 = NULL; + data->buf_size = data->samplerate/RENDER_RATE*(sizeof(float) << 1); + data->buffer = malloc(data->buf_size); + data->buffer_int16 = NULL; } else { - buffer = NULL; - buffer_int16 = malloc(buf_size * sizeof(int16_t)); + data->buf_size = data->samplerate/RENDER_RATE*(sizeof(int16_t) << 1); + data->buffer = NULL; + data->buffer_int16 = malloc(data->buf_size); } + data->event = thread_create_event(); + data->thread_h = thread_create(mt32_thread, 0); + data->status_show_instruments = device_get_config_int("status_show_instruments"); mt32emu_set_output_gain(context, device_get_config_int("output_gain")/100.0f); mt32emu_set_reverb_enabled(context, device_get_config_int("reverb")); @@ -177,9 +222,12 @@ void* mt32_init() pclog("mt32 reverb: %d\n", mt32emu_is_reverb_enabled(context)); pclog("mt32 reversed stereo: %d\n", mt32emu_is_reversed_stereo_enabled(context)); - al_set_midi(samplerate, buf_size); + al_set_midi(data->samplerate, data->buf_size); - pclog("mt32 (Munt %s) initialized, samplerate %d, buf_size %d\n", mt32emu_get_library_version_string(), samplerate, buf_size); + pclog("mt32 (Munt %s) initialized, samplerate %d, buf_size %d\n", mt32emu_get_library_version_string(), data->samplerate, data->buf_size); + + data->context = context; + data->message[0] = 0; midi_device_t* dev = malloc(sizeof(midi_device_t)); memset(dev, 0, sizeof(midi_device_t)); @@ -187,45 +235,96 @@ void* mt32_init() dev->play_msg = mt32_msg; dev->play_sysex = mt32_sysex; dev->poll = mt32_poll; + dev->data = data; midi_init(dev); return dev; } +void* mt32_init() +{ + midi_device_t* dev = mt32emu_init(L"roms/mt32/mt32_control.rom", L"roms/mt32/mt32_pcm.rom"); + if (dev) + strcpy(((mt32_t*)dev->data)->model_name, "MT-32"); + return dev; +} + +void* cm32l_init() +{ + midi_device_t* dev = mt32emu_init(L"roms/cm32l/cm32l_control.rom", L"roms/cm32l/cm32l_pcm.rom"); + if (dev) + strcpy(((mt32_t*)dev->data)->model_name, "CM-32L"); + return dev; +} + void mt32_close(void* p) { if (!p) return; - if (thread_h) - thread_kill(thread_h); - if (event) - thread_destroy_event(event); - event = NULL; - thread_h = NULL; + midi_device_t* device = (midi_device_t*)p; - if (context) + mt32_t* data = (mt32_t*)device->data; + + if (data->thread_h) + thread_kill(data->thread_h); + if (data->event) + thread_destroy_event(data->event); + + if (data->context) { - mt32emu_close_synth(context); - mt32emu_free_context(context); + mt32emu_close_synth(data->context); + mt32emu_free_context(data->context); } - context = NULL; - if (buffer) - free(buffer); - buffer = NULL; + if (data->buffer) + free(data->buffer); - if (buffer_int16) - free(buffer_int16); - buffer_int16 = NULL; + if (data->buffer_int16) + free(data->buffer_int16); midi_close(); + free(data); free((midi_device_t*)p); pclog("mt32 closed\n"); } +void mt32_add_status_info(char *s, int max_len, void *p) +{ + int i; + char temps[MT32EMU_SYSEX_BUFFER_SIZE]; + midi_device_t* dev = (midi_device_t*)p; + mt32_t* data = (mt32_t*)dev->data; + mt32emu_context context = data->context; + if (strlen(data->message)) + { + sprintf(temps, "%s message: %s\n", data->model_name, data->message); + strncat(s, temps, max_len); + } + if (mt32emu_is_active(context)) + { + sprintf(temps, "%s playback frequency: %iHz\n", data->model_name, data->samplerate); + strncat(s, temps, max_len); + if (data->status_show_instruments) + { + for (i = 0; i < 8; ++i) + { + const char* patch_name = mt32emu_get_patch_name(context, i); + sprintf(temps, "%s inst. %d: %s\n", data->model_name, i+1, patch_name); + strncat(s, temps, max_len); + } + } + strncat(s, "\n", max_len); + } + else + { + strncat(s, data->model_name, max_len); + strncat(s, " playback stopped\n\n", max_len); + } +} + static device_config_t mt32_config[] = { { @@ -304,6 +403,12 @@ static device_config_t mt32_config[] = .type = CONFIG_BINARY, .default_int = 0 }, + { + .name = "status_show_instruments", + .description = "(Status) Show instruments", + .type = CONFIG_BINARY, + .default_int = 0 + }, { .type = -1 } @@ -318,6 +423,19 @@ device_t mt32_device = mt32_available, NULL, NULL, - NULL, + mt32_add_status_info, + mt32_config +}; + +device_t cm32l_device = +{ + "Roland CM-32L Emulation", + 0, + cm32l_init, + mt32_close, + cm32l_available, + NULL, + NULL, + mt32_add_status_info, mt32_config }; diff --git a/src/SOUND/midi_mt32.h b/src/SOUND/midi_mt32.h index 9a80989a6..b881ea4cc 100644 --- a/src/SOUND/midi_mt32.h +++ b/src/SOUND/midi_mt32.h @@ -1 +1,2 @@ extern device_t mt32_device; +extern device_t cm32l_device; diff --git a/src/SOUND/midi_system.c b/src/SOUND/midi_system.c index d69fc3a4b..13583867c 100644 --- a/src/SOUND/midi_system.c +++ b/src/SOUND/midi_system.c @@ -3,9 +3,9 @@ #include #include #include "../device.h" -#include "../WIN/plat_midi.h" #include "midi_system.h" #include "midi.h" +#include "../WIN/plat_midi.h" void* system_midi_init() { @@ -15,8 +15,7 @@ void* system_midi_init() dev->play_msg = plat_midi_play_msg; dev->play_sysex = plat_midi_play_sysex; dev->write = plat_midi_write; - - plat_midi_init(); + dev->data = plat_midi_init(); midi_init(dev); @@ -25,7 +24,9 @@ void* system_midi_init() void system_midi_close(void* p) { - plat_midi_close(); + midi_device_t *dev = (midi_device_t *)p; + plat_midi_close(dev->data); + free(dev); midi_close(); } @@ -35,6 +36,11 @@ int system_midi_available() return plat_midi_get_num_devs(); } +void system_midi_add_status_info(char *s, int max_len, void *p) +{ + plat_midi_add_status_info(s, max_len, (midi_device_t*)p); +} + static device_config_t system_midi_config[] = { { @@ -57,6 +63,6 @@ device_t system_midi_device = system_midi_available, NULL, NULL, - NULL, + system_midi_add_status_info, system_midi_config }; diff --git a/src/WIN/plat_midi.h b/src/WIN/plat_midi.h index b1b93b5e2..485f04d32 100644 --- a/src/WIN/plat_midi.h +++ b/src/WIN/plat_midi.h @@ -1,7 +1,8 @@ -void plat_midi_init(); -void plat_midi_close(); -void plat_midi_play_msg(uint8_t* val); -void plat_midi_play_sysex(uint8_t* data, unsigned int len); -int plat_midi_write(uint8_t val); +void* plat_midi_init(); +void plat_midi_close(void* p); +void plat_midi_play_msg(struct midi_device_t* device, uint8_t* val); +void plat_midi_play_sysex(struct midi_device_t* device, uint8_t* data, unsigned int len); +int plat_midi_write(struct midi_device_t* device, uint8_t val); int plat_midi_get_num_devs(); void plat_midi_get_dev_name(int num, char *s); +void plat_midi_add_status_info(char *s, int max_len, struct midi_device_t* device); diff --git a/src/WIN/win_midi.c b/src/WIN/win_midi.c index 4572c0b32..6c5bc8696 100644 --- a/src/WIN/win_midi.c +++ b/src/WIN/win_midi.c @@ -5,70 +5,68 @@ #include "../SOUND/midi.h" #include "plat_midi.h" -int midi_id = 0; -static HMIDIOUT midi_out_device = NULL; - -HANDLE m_event; - -static uint8_t midi_rt_buf[1024]; -static uint8_t midi_cmd_buf[1024]; -static int midi_cmd_pos = 0; -static int midi_cmd_len = 0; -static uint8_t midi_status = 0; -static unsigned int midi_sysex_start = 0; -static unsigned int midi_sysex_delay = 0; - -void plat_midi_init() +typedef struct plat_midi_t { + int id; + char name[512]; + HMIDIOUT midi_out_device; + HANDLE event; + MIDIHDR hdr; +} plat_midi_t; + +void* plat_midi_init() +{ + plat_midi_t* data = malloc(sizeof(plat_midi_t)); + memset(data, 0, sizeof(plat_midi_t)); + /* This is for compatibility with old configuration files. */ - midi_id = config_get_int("Sound", "midi_host_device", -1); - if (midi_id == -1) + data->id = config_get_int("Sound", "midi_host_device", -1); + if (data->id == -1) { - midi_id = config_get_int(SYSTEM_MIDI_NAME, "midi", 0); + data->id = config_get_int(SYSTEM_MIDI_NAME, "midi", 0); } else { config_delete_var("Sound", "midi_host_device"); - config_set_int(SYSTEM_MIDI_NAME, "midi", midi_id); + config_set_int(SYSTEM_MIDI_NAME, "midi", data->id); } MMRESULT hr = MMSYSERR_NOERROR; - memset(midi_rt_buf, 0, sizeof(midi_rt_buf)); - memset(midi_cmd_buf, 0, sizeof(midi_cmd_buf)); + data->event = CreateEvent(NULL, TRUE, TRUE, NULL); - midi_cmd_pos = midi_cmd_len = 0; - midi_status = 0; - - midi_sysex_start = midi_sysex_delay = 0; - - m_event = CreateEvent(NULL, TRUE, TRUE, NULL); - - hr = midiOutOpen(&midi_out_device, midi_id, (DWORD) m_event, + hr = midiOutOpen(&data->midi_out_device, data->id, (DWORD) data->event, 0, CALLBACK_EVENT); if (hr != MMSYSERR_NOERROR) { printf("midiOutOpen error - %08X\n",hr); - midi_id = 0; - hr = midiOutOpen(&midi_out_device, midi_id, (DWORD) m_event, + data->id = 0; + hr = midiOutOpen(&data->midi_out_device, data->id, (DWORD) data->event, 0, CALLBACK_EVENT); if (hr != MMSYSERR_NOERROR) { printf("midiOutOpen error - %08X\n",hr); - return; + free(data); + return 0; } } - midiOutReset(midi_out_device); + plat_midi_get_dev_name(data->id, data->name); + + midiOutReset(data->midi_out_device); + + return data; } -void plat_midi_close() +void plat_midi_close(void* p) { - if (midi_out_device != NULL) + plat_midi_t* data = (plat_midi_t*)p; + if (data->midi_out_device != NULL) { - midiOutReset(midi_out_device); - midiOutClose(midi_out_device); + midiOutReset(data->midi_out_device); + midiOutClose(data->midi_out_device); /* midi_out_device = NULL; */ - CloseHandle(m_event); + CloseHandle(data->event); } + free(data); } int plat_midi_get_num_devs() @@ -83,43 +81,50 @@ void plat_midi_get_dev_name(int num, char *s) strcpy(s, caps.szPname); } -void plat_midi_play_msg(uint8_t *msg) +void plat_midi_play_msg(midi_device_t* device, uint8_t *msg) { - midiOutShortMsg(midi_out_device, *(uint32_t *) msg); + plat_midi_t* data = (plat_midi_t*)device->data; + midiOutShortMsg(data->midi_out_device, *(uint32_t *) msg); } -MIDIHDR m_hdr; - -void plat_midi_play_sysex(uint8_t *sysex, unsigned int len) +void plat_midi_play_sysex(midi_device_t* device, uint8_t *sysex, unsigned int len) { + plat_midi_t* data = (plat_midi_t*)device->data; MMRESULT result; - if (WaitForSingleObject(m_event, 2000) == WAIT_TIMEOUT) + if (WaitForSingleObject(data->event, 2000) == WAIT_TIMEOUT) { pclog("Can't send MIDI message\n"); return; } - midiOutUnprepareHeader(midi_out_device, &m_hdr, sizeof(m_hdr)); + midiOutUnprepareHeader(data->midi_out_device, &data->hdr, sizeof(data->hdr)); - m_hdr.lpData = (char *) sysex; - m_hdr.dwBufferLength = len; - m_hdr.dwBytesRecorded = len; - m_hdr.dwUser = 0; + data->hdr.lpData = (char *) sysex; + data->hdr.dwBufferLength = len; + data->hdr.dwBytesRecorded = len; + data->hdr.dwUser = 0; - result = midiOutPrepareHeader(midi_out_device, &m_hdr, sizeof(m_hdr)); + result = midiOutPrepareHeader(data->midi_out_device, &data->hdr, sizeof(data->hdr)); if (result != MMSYSERR_NOERROR) return; - ResetEvent(m_event); - result = midiOutLongMsg(midi_out_device, &m_hdr, sizeof(m_hdr)); + ResetEvent(data->event); + result = midiOutLongMsg(data->midi_out_device, &data->hdr, sizeof(data->hdr)); if (result != MMSYSERR_NOERROR) { - SetEvent(m_event); + SetEvent(data->event); return; } } -int plat_midi_write(uint8_t val) +int plat_midi_write(midi_device_t* device, uint8_t val) { return 0; } + +void plat_midi_add_status_info(char *s, int max_len, struct midi_device_t* device) +{ + char temps[512]; + sprintf(temps, "MIDI out device: %s\n\n", ((plat_midi_t*)device->data)->name); + strncat(s, temps, max_len); +}