diff options
Diffstat (limited to 'src/osd/modules/midi')
-rw-r--r-- | src/osd/modules/midi/midi_module.h | 26 | ||||
-rw-r--r-- | src/osd/modules/midi/none.cpp | 87 | ||||
-rw-r--r-- | src/osd/modules/midi/portmidi.cpp | 374 |
3 files changed, 221 insertions, 266 deletions
diff --git a/src/osd/modules/midi/midi_module.h b/src/osd/modules/midi/midi_module.h index 6c50cdd3edc..61eef311aa6 100644 --- a/src/osd/modules/midi/midi_module.h +++ b/src/osd/modules/midi/midi_module.h @@ -4,12 +4,18 @@ * midi_module.h * */ +#ifndef MAME_OSD_MODULES_MIDI_MIDI_MODULE_H +#define MAME_OSD_MODULES_MIDI_MIDI_MODULE_H -#ifndef MIDI_MODULE_H_ -#define MIDI_MODULE_H_ +#pragma once + +#include "interface/midiport.h" + +#include <memory> +#include <string> +#include <string_view> +#include <vector> -#include "osdepend.h" -#include "modules/osdmodule.h" //============================================================ // CONSTANTS @@ -20,13 +26,13 @@ class midi_module { public: - virtual ~midi_module() { } + virtual ~midi_module() = default; + // specific routines - virtual osd_midi_device *create_midi_device() = 0; - // FIXME: should return a list of strings ... - virtual void list_midi_devices(void) = 0; + virtual std::unique_ptr<osd::midi_input_port> create_input(std::string_view name) = 0; + virtual std::unique_ptr<osd::midi_output_port> create_output(std::string_view name) = 0; + virtual std::vector<osd::midi_port_info> list_midi_ports() = 0; }; - -#endif /* MIDI_MODULE_H_ */ +#endif // MAME_OSD_MODULES_MIDI_MIDI_MODULE_H diff --git a/src/osd/modules/midi/none.cpp b/src/osd/modules/midi/none.cpp index adacee7d634..2a50bf71a84 100644 --- a/src/osd/modules/midi/none.cpp +++ b/src/osd/modules/midi/none.cpp @@ -6,89 +6,36 @@ Empty shim for systems not supporting midi / portmidi -*******************************************************************c********/ +***************************************************************************/ -#include "osdcore.h" -#include "corealloc.h" -#include "modules/osdmodule.h" #include "midi_module.h" -class none_module : public osd_module, public midi_module -{ -public: +#include "modules/osdmodule.h" +#include "osdcore.h" - none_module() - : osd_module(OSD_MIDI_PROVIDER, "pm"), midi_module() - { - } - virtual ~none_module() { } +#include <memory> - virtual int init(const osd_options &options) override; - virtual void exit() override; - virtual osd_midi_device *create_midi_device() override; - virtual void list_midi_devices(void) override; -}; +namespace osd { +namespace { -class osd_midi_device_none : public osd_midi_device +class none_module : public osd_module, public midi_module { public: - virtual ~osd_midi_device_none() { } - virtual bool open_input(const char *devname) override; - virtual bool open_output(const char *devname) override; - virtual void close() override; - virtual bool poll() override; - virtual int read(uint8_t *pOut) override; - virtual void write(uint8_t data) override; -}; + none_module() : osd_module(OSD_MIDI_PROVIDER, "none"), midi_module() { } -osd_midi_device *none_module::create_midi_device() -{ - return global_alloc(osd_midi_device_none()); -} - - -int none_module::init(const osd_options &options) -{ - return 0; -} + virtual int init(osd_interface &osd, const osd_options &options) override { return 0; } + virtual void exit() override { } -void none_module::exit() -{ -} - -void none_module::list_midi_devices(void) -{ - osd_printf_warning("\nMIDI is not supported in this build\n"); -} - -bool osd_midi_device_none::open_input(const char *devname) -{ - return false; -} - -bool osd_midi_device_none::open_output(const char *devname) -{ - return false; -} - -void osd_midi_device_none::close() -{ -} + virtual std::unique_ptr<midi_input_port> create_input(std::string_view name) override { return nullptr; } + virtual std::unique_ptr<midi_output_port> create_output(std::string_view name) override { return nullptr; } + virtual std::vector<osd::midi_port_info> list_midi_ports() override { return std::vector<osd::midi_port_info>(); } +}; -bool osd_midi_device_none::poll() -{ - return false; -} +} // anonymous namespace -int osd_midi_device_none::read(uint8_t *pOut) -{ - return 0; -} +} // namespace osd -void osd_midi_device_none::write(uint8_t data) -{ -} -MODULE_DEFINITION(MIDI_NONE, none_module) +MODULE_DEFINITION(MIDI_NONE, osd::none_module) diff --git a/src/osd/modules/midi/portmidi.cpp b/src/osd/modules/midi/portmidi.cpp index 418295a7a5c..07372af1469 100644 --- a/src/osd/modules/midi/portmidi.cpp +++ b/src/osd/modules/midi/portmidi.cpp @@ -2,72 +2,88 @@ // copyright-holders:R. Belmont /*************************************************************************** - portmap.c + portmidi.cpp Midi implementation based on portmidi library *******************************************************************c********/ +#include "midi_module.h" + +#include "modules/osdmodule.h" + #ifndef NO_USE_MIDI +#include "interface/midiport.h" +#include "osdcore.h" // osd_printf_* + #include <portmidi.h> -#include "osdcore.h" -#include "corealloc.h" -#include "modules/osdmodule.h" -#include "midi_module.h" + +#include <cstdio> +#include <cstring> + + +namespace osd { + +namespace { class pm_module : public osd_module, public midi_module { public: - pm_module() - : osd_module(OSD_MIDI_PROVIDER, "pm"), midi_module() + pm_module() : osd_module(OSD_MIDI_PROVIDER, "pm"), midi_module() { } virtual ~pm_module() { } - virtual int init(const osd_options &options)override; - virtual void exit()override; + virtual int init(osd_interface &osd, const osd_options &options) override; + virtual void exit() override; - virtual osd_midi_device *create_midi_device() override; - virtual void list_midi_devices(void) override; + virtual std::unique_ptr<midi_input_port> create_input(std::string_view name) override; + virtual std::unique_ptr<midi_output_port> create_output(std::string_view name) override; + virtual std::vector<osd::midi_port_info> list_midi_ports() override; }; -static const int RX_EVENT_BUF_SIZE = 512; +static constexpr unsigned RX_EVENT_BUF_SIZE = 512; -#define MIDI_SYSEX 0xf0 -#define MIDI_EOX 0xf7 +static constexpr uint8_t MIDI_SYSEX = 0xf0; +static constexpr uint8_t MIDI_EOX = 0xf7; -class osd_midi_device_pm : public osd_midi_device +class midi_input_pm : public midi_input_port { public: - osd_midi_device_pm(): pmStream(nullptr), xmit_cnt(0), last_status(0), rx_sysex(false) { } - virtual ~osd_midi_device_pm() { } - virtual bool open_input(const char *devname) override; - virtual bool open_output(const char *devname) override; - virtual void close() override; + midi_input_pm(PortMidiStream *stream) : m_stream(stream), m_rx_sysex(false) { } + virtual ~midi_input_pm(); + virtual bool poll() override; virtual int read(uint8_t *pOut) override; - virtual void write(uint8_t data) override; private: - PortMidiStream *pmStream; - PmEvent rx_evBuf[RX_EVENT_BUF_SIZE]; - uint8_t xmit_in[4]; // Pm_Messages mean we can at most have 3 residue bytes - int xmit_cnt; - uint8_t last_status; - bool rx_sysex; + PortMidiStream *const m_stream; + PmEvent m_evbuf[RX_EVENT_BUF_SIZE]; + bool m_rx_sysex; }; -osd_midi_device *pm_module::create_midi_device() +class midi_output_pm : public midi_output_port { - return global_alloc(osd_midi_device_pm()); -} +public: + midi_output_pm(PortMidiStream *stream) : m_stream(stream), m_xmit_cnt(0), m_last_status(0) { } + virtual ~midi_output_pm(); + + virtual void write(uint8_t data) override; +private: + PortMidiStream *const m_stream; + uint8_t m_xmit_in[4]; // Pm_Messages mean we can at most have 3 residue bytes + int m_xmit_cnt; + uint8_t m_last_status; +}; -int pm_module::init(const osd_options &options) + +int pm_module::init(osd_interface &osd, const osd_options &options) { + // FIXME: check error return code Pm_Initialize(); return 0; } @@ -77,151 +93,126 @@ void pm_module::exit() Pm_Terminate(); } -void pm_module::list_midi_devices(void) +std::unique_ptr<midi_input_port> pm_module::create_input(std::string_view name) { - int num_devs = Pm_CountDevices(); - const PmDeviceInfo *pmInfo; - - printf("\n"); - - if (num_devs == 0) + int found_dev = -1; + if (name == "default") { - printf("No MIDI ports were found\n"); - return; + found_dev = Pm_GetDefaultInputDeviceID(); } - - printf("MIDI input ports:\n"); - for (int i = 0; i < num_devs; i++) + else { - pmInfo = Pm_GetDeviceInfo(i); - - if (pmInfo->input) + int const num_devs = Pm_CountDevices(); + for (found_dev = 0; num_devs > found_dev; ++found_dev) { - printf("%s %s\n", pmInfo->name, (i == Pm_GetDefaultInputDeviceID()) ? "(default)" : ""); + auto const info = Pm_GetDeviceInfo(found_dev); + if (info->input && (name == info->name)) + break; } + if (num_devs <= found_dev) + found_dev = -1; } - printf("\nMIDI output ports:\n"); - for (int i = 0; i < num_devs; i++) + if (0 > found_dev) { - pmInfo = Pm_GetDeviceInfo(i); - - if (pmInfo->output) - { - printf("%s %s\n", pmInfo->name, (i == Pm_GetDefaultOutputDeviceID()) ? "(default)" : ""); - } + osd_printf_warning("No MIDI input device named '%s' was found.\n", name); + return nullptr; } -} -bool osd_midi_device_pm::open_input(const char *devname) -{ - int num_devs = Pm_CountDevices(); - int found_dev = -1; - const PmDeviceInfo *pmInfo; - PortMidiStream *stm; - - if (!strcmp("default", devname)) - { - found_dev = Pm_GetDefaultInputDeviceID(); - } - else + PortMidiStream *stream = nullptr; + PmError const err = Pm_OpenInput(&stream, found_dev, nullptr, RX_EVENT_BUF_SIZE, nullptr, nullptr); + if (pmNoError != err) { - for (int i = 0; i < num_devs; i++) - { - pmInfo = Pm_GetDeviceInfo(i); - - if (pmInfo->input) - { - if (!strcmp(devname, pmInfo->name)) - { - found_dev = i; - break; - } - } - } + osd_printf_error("Error opening PortMidi device '%s' for input.\n", name); + return nullptr; } - if (found_dev >= 0) + try { - if (Pm_OpenInput(&stm, found_dev, nullptr, RX_EVENT_BUF_SIZE, nullptr, nullptr) == pmNoError) - { - pmStream = stm; - return true; - } - else - { - printf("Couldn't open PM device\n"); - return false; - } + return std::make_unique<midi_input_pm>(stream); } - else + catch (...) { - return false; + Pm_Close(stream); + return nullptr; } } -bool osd_midi_device_pm::open_output(const char *devname) +std::unique_ptr<midi_output_port> pm_module::create_output(std::string_view name) { - int num_devs = Pm_CountDevices(); int found_dev = -1; - const PmDeviceInfo *pmInfo; - PortMidiStream *stm; - - if (!strcmp("default", devname)) + if (name == "default") { found_dev = Pm_GetDefaultOutputDeviceID(); } else { - for (int i = 0; i < num_devs; i++) + int const num_devs = Pm_CountDevices(); + for (found_dev = 0; num_devs > found_dev; ++found_dev) { - pmInfo = Pm_GetDeviceInfo(i); - - if (pmInfo->output) - { - if (!strcmp(devname, pmInfo->name)) - { - found_dev = i; - break; - } - } + auto const info = Pm_GetDeviceInfo(found_dev); + if (info->output && (name == info->name)) + break; } + if (num_devs <= found_dev) + found_dev = -1; } - if (found_dev >= 0) + PortMidiStream *stream = nullptr; + PmError const err = Pm_OpenOutput(&stream, found_dev, nullptr, 100, nullptr, nullptr, 0); + if (pmNoError != err) { - if (Pm_OpenOutput(&stm, found_dev, nullptr, 100, nullptr, nullptr, 0) == pmNoError) - { - pmStream = stm; - return true; - } - else - { - printf("Couldn't open PM device\n"); - return false; - } + osd_printf_error("Error opening PortMidi device '%s' for output.\n", name); + return nullptr; } - else + + try { - return false; + return std::make_unique<midi_output_pm>(stream); + } + catch (...) + { + Pm_Close(stream); + return nullptr; } } -void osd_midi_device_pm::close() +std::vector<osd::midi_port_info> pm_module::list_midi_ports() { - Pm_Close(pmStream); + int const num_devs = Pm_CountDevices(); + int const def_input = Pm_GetDefaultInputDeviceID(); + int const def_output = Pm_GetDefaultOutputDeviceID(); + std::vector<osd::midi_port_info> result; + result.reserve(num_devs); + for (int i = 0; num_devs > i; ++i) + { + auto const pm_info = Pm_GetDeviceInfo(i); + result.emplace_back(osd::midi_port_info{ + pm_info->name, + 0 != pm_info->input, + 0 != pm_info->output, + def_input == i, + def_output == i }); + } + return result; } -bool osd_midi_device_pm::poll() + +midi_input_pm::~midi_input_pm() { - PmError chk = Pm_Poll(pmStream); + if (m_stream) + Pm_Close(m_stream); +} +bool midi_input_pm::poll() +{ + PmError const chk = Pm_Poll(m_stream); return (chk == pmGotData) ? true : false; } -int osd_midi_device_pm::read(uint8_t *pOut) +int midi_input_pm::read(uint8_t *pOut) { - int msgsRead = Pm_Read(pmStream, rx_evBuf, RX_EVENT_BUF_SIZE); + int msgsRead = Pm_Read(m_stream, m_evbuf, RX_EVENT_BUF_SIZE); int bytesOut = 0; if (msgsRead <= 0) @@ -231,23 +222,23 @@ int osd_midi_device_pm::read(uint8_t *pOut) for (int msg = 0; msg < msgsRead; msg++) { - uint8_t status = Pm_MessageStatus(rx_evBuf[msg].message); + uint8_t status = Pm_MessageStatus(m_evbuf[msg].message); - if (rx_sysex) + if (m_rx_sysex) { if (status & 0x80) // sys real-time imposing on us? { if (status == 0xf2) { *pOut++ = status; - *pOut++ = Pm_MessageData1(rx_evBuf[msg].message); - *pOut++ = Pm_MessageData2(rx_evBuf[msg].message); + *pOut++ = Pm_MessageData1(m_evbuf[msg].message); + *pOut++ = Pm_MessageData2(m_evbuf[msg].message); bytesOut += 3; } else if (status == 0xf3) { *pOut++ = status; - *pOut++ = Pm_MessageData1(rx_evBuf[msg].message); + *pOut++ = Pm_MessageData1(m_evbuf[msg].message); bytesOut += 2; } else @@ -256,7 +247,7 @@ int osd_midi_device_pm::read(uint8_t *pOut) bytesOut++; if (status == MIDI_EOX) { - rx_sysex = false; + m_rx_sysex = false; } } } @@ -264,15 +255,15 @@ int osd_midi_device_pm::read(uint8_t *pOut) { for (int i = 0; i < 4; i++) { - uint8_t byte = rx_evBuf[msg].message & 0xff; + uint8_t byte = m_evbuf[msg].message & 0xff; *pOut++ = byte; bytesOut++; if (byte == MIDI_EOX) { - rx_sysex = false; + m_rx_sysex = false; break; } - rx_evBuf[msg].message >>= 8; + m_evbuf[msg].message >>= 8; } } } @@ -283,7 +274,7 @@ int osd_midi_device_pm::read(uint8_t *pOut) case 0xc: // 2-byte messages case 0xd: *pOut++ = status; - *pOut++ = Pm_MessageData1(rx_evBuf[msg].message); + *pOut++ = Pm_MessageData1(m_evbuf[msg].message); bytesOut += 2; break; @@ -293,30 +284,30 @@ int osd_midi_device_pm::read(uint8_t *pOut) case 0: // System Exclusive { *pOut++ = status; // this should be OK: the shortest legal sysex is F0 tt dd F7, I believe - *pOut++ = (rx_evBuf[msg].message>>8) & 0xff; - *pOut++ = (rx_evBuf[msg].message>>16) & 0xff; - uint8_t last = *pOut++ = (rx_evBuf[msg].message>>24) & 0xff; + *pOut++ = (m_evbuf[msg].message>>8) & 0xff; + *pOut++ = (m_evbuf[msg].message>>16) & 0xff; + uint8_t last = *pOut++ = (m_evbuf[msg].message>>24) & 0xff; bytesOut += 4; - rx_sysex = (last != MIDI_EOX); + m_rx_sysex = (last != MIDI_EOX); break; } case 7: // End of System Exclusive *pOut++ = status; bytesOut += 1; - rx_sysex = false; + m_rx_sysex = false; break; case 2: // song pos *pOut++ = status; - *pOut++ = Pm_MessageData1(rx_evBuf[msg].message); - *pOut++ = Pm_MessageData2(rx_evBuf[msg].message); + *pOut++ = Pm_MessageData1(m_evbuf[msg].message); + *pOut++ = Pm_MessageData2(m_evbuf[msg].message); bytesOut += 3; break; case 3: // song select *pOut++ = status; - *pOut++ = Pm_MessageData1(rx_evBuf[msg].message); + *pOut++ = Pm_MessageData1(m_evbuf[msg].message); bytesOut += 2; break; @@ -329,8 +320,8 @@ int osd_midi_device_pm::read(uint8_t *pOut) default: *pOut++ = status; - *pOut++ = Pm_MessageData1(rx_evBuf[msg].message); - *pOut++ = Pm_MessageData2(rx_evBuf[msg].message); + *pOut++ = Pm_MessageData1(m_evbuf[msg].message); + *pOut++ = Pm_MessageData2(m_evbuf[msg].message); bytesOut += 3; break; } @@ -340,57 +331,64 @@ int osd_midi_device_pm::read(uint8_t *pOut) return bytesOut; } -void osd_midi_device_pm::write(uint8_t data) + +midi_output_pm::~midi_output_pm() +{ + if (m_stream) + Pm_Close(m_stream); +} + +void midi_output_pm::write(uint8_t data) { int bytes_needed = 0; PmEvent ev; ev.timestamp = 0; // use the current time -// printf("write: %02x (%d)\n", data, xmit_cnt); +// printf("write: %02x (%d)\n", data, m_xmit_cnt); // reject data bytes when no valid status exists - if ((last_status == 0) && !(data & 0x80)) + if ((m_last_status == 0) && !(data & 0x80)) { - xmit_cnt = 0; + m_xmit_cnt = 0; return; } - if (xmit_cnt >= 4) + if (m_xmit_cnt >= 4) { printf("MIDI out: packet assembly overflow, contact MAMEdev!\n"); return; } // handle sysex - if (last_status == MIDI_SYSEX) + if (m_last_status == MIDI_SYSEX) { -// printf("sysex: %02x (%d)\n", data, xmit_cnt); +// printf("sysex: %02x (%d)\n", data, m_xmit_cnt); // if we get a status that isn't sysex, assume it's system common if ((data & 0x80) && (data != MIDI_EOX)) { // printf("common during sysex!\n"); ev.message = Pm_Message(data, 0, 0); - Pm_Write(pmStream, &ev, 1); + Pm_Write(m_stream, &ev, 1); return; } - xmit_in[xmit_cnt++] = data; + m_xmit_in[m_xmit_cnt++] = data; // if EOX or 4 bytes filled, transmit 4 bytes - if ((xmit_cnt == 4) || (data == MIDI_EOX)) + if ((m_xmit_cnt == 4) || (data == MIDI_EOX)) { - ev.message = xmit_in[0] | (xmit_in[1]<<8) | (xmit_in[2]<<16) | (xmit_in[3]<<24); - Pm_Write(pmStream, &ev, 1); - xmit_in[0] = xmit_in[1] = xmit_in[2] = xmit_in[3] = 0; - xmit_cnt = 0; + ev.message = m_xmit_in[0] | (m_xmit_in[1]<<8) | (m_xmit_in[2]<<16) | (m_xmit_in[3]<<24); + Pm_Write(m_stream, &ev, 1); + m_xmit_in[0] = m_xmit_in[1] = m_xmit_in[2] = m_xmit_in[3] = 0; + m_xmit_cnt = 0; // printf("SysEx packet: %08x\n", ev.message); // if this is EOX, kill the running status if (data == MIDI_EOX) { - last_status = 0; + m_last_status = 0; } } @@ -398,33 +396,33 @@ void osd_midi_device_pm::write(uint8_t data) } // handle running status. don't allow system real-time messages to be considered as running status. - if ((xmit_cnt == 0) && (data & 0x80) && (data < 0xf8)) + if ((m_xmit_cnt == 0) && (data & 0x80) && (data < 0xf8)) { - last_status = data; + m_last_status = data; } - if ((xmit_cnt == 0) && !(data & 0x80)) + if ((m_xmit_cnt == 0) && !(data & 0x80)) { - xmit_in[xmit_cnt++] = last_status; - xmit_in[xmit_cnt++] = data; -// printf("\trunning status: [%d] = %02x, [%d] = %02x, last_status = %02x\n", xmit_cnt-2, last_status, xmit_cnt-1, data, last_status); + m_xmit_in[m_xmit_cnt++] = m_last_status; + m_xmit_in[m_xmit_cnt++] = data; +// printf("\trunning status: [%d] = %02x, [%d] = %02x, m_last_status = %02x\n", m_xmit_cnt-2, m_last_status, m_xmit_cnt-1, data, m_last_status); } else { - xmit_in[xmit_cnt++] = data; -// printf("\tNRS: [%d] = %02x\n", xmit_cnt-1, data); + m_xmit_in[m_xmit_cnt++] = data; +// printf("\tNRS: [%d] = %02x\n", m_xmit_cnt-1, data); } - if ((xmit_cnt == 1) && (xmit_in[0] == MIDI_SYSEX)) + if ((m_xmit_cnt == 1) && (m_xmit_in[0] == MIDI_SYSEX)) { // printf("Start SysEx!\n"); - last_status = MIDI_SYSEX; + m_last_status = MIDI_SYSEX; return; } // are we there yet? -// printf("status check: %02x\n", xmit_in[0]); - switch ((xmit_in[0]>>4) & 0xf) +// printf("status check: %02x\n", m_xmit_in[0]); + switch ((m_xmit_in[0]>>4) & 0xf) { case 0xc: // 2-byte messages case 0xd: @@ -432,7 +430,7 @@ void osd_midi_device_pm::write(uint8_t data) break; case 0xf: // system common - switch (xmit_in[0] & 0xf) + switch (m_xmit_in[0] & 0xf) { case 0: // System Exclusive is handled above break; @@ -457,20 +455,24 @@ void osd_midi_device_pm::write(uint8_t data) break; } - if (xmit_cnt == bytes_needed) + if (m_xmit_cnt == bytes_needed) { - ev.message = Pm_Message(xmit_in[0], xmit_in[1], xmit_in[2]); - Pm_Write(pmStream, &ev, 1); - xmit_cnt = 0; + ev.message = Pm_Message(m_xmit_in[0], m_xmit_in[1], m_xmit_in[2]); + Pm_Write(m_stream, &ev, 1); + m_xmit_cnt = 0; } } + +} // anonymous namespace + +} // namespace osd + #else - #include "modules/osdmodule.h" - #include "midi_module.h" - MODULE_NOT_SUPPORTED(pm_module, OSD_MIDI_PROVIDER, "pm") +namespace osd { namespace { MODULE_NOT_SUPPORTED(pm_module, OSD_MIDI_PROVIDER, "pm") } } + #endif -MODULE_DEFINITION(MIDI_PM, pm_module) +MODULE_DEFINITION(MIDI_PM, osd::pm_module) |