diff options
author | 2013-01-13 03:48:10 +0000 | |
---|---|---|
committer | 2013-01-13 03:48:10 +0000 | |
commit | f6c44c6e9bbf1720d481707cbee73aadbae21572 (patch) | |
tree | 93d48913f4afee3080c2aca425119f0840b74276 /src | |
parent | fa807d8a30cd94a3f4f283db378f47312271d61f (diff) |
MIDI core updates: [R. Belmont]
- Add MIDI in and out ports as image device types
- Add OSD calls to check for and read MIDI input
- Add MIDI in image device which reads input and converts it to a serial bitstream
nw section:
Note that the MIDI In device uses the new image device override to prevent the core from attempting to fopen() the "file" name and instead it handles open/close itself in call_load/call_unload. This allows greater flexibilty than the hack used for sockets/ptys/named pipes where the OSD file layer has to know about them.
Diffstat (limited to 'src')
-rw-r--r-- | src/emu/diimage.c | 2 | ||||
-rw-r--r-- | src/emu/diimage.h | 4 | ||||
-rw-r--r-- | src/emu/emu.mak | 1 | ||||
-rw-r--r-- | src/emu/imagedev/midiin.c | 166 | ||||
-rw-r--r-- | src/emu/imagedev/midiin.h | 89 | ||||
-rw-r--r-- | src/osd/osdcore.h | 2 | ||||
-rw-r--r-- | src/osd/portmedia/pmmidi.c | 170 |
7 files changed, 433 insertions, 1 deletions
diff --git a/src/emu/diimage.c b/src/emu/diimage.c index a8c921d6e4a..64022a68313 100644 --- a/src/emu/diimage.c +++ b/src/emu/diimage.c @@ -67,6 +67,8 @@ const image_device_type_info device_image_interface::m_device_info_array[] = { IO_CDROM, "cdrom", "cdrm" }, /* 13 */ { IO_MAGTAPE, "magtape", "magt" }, /* 14 */ { IO_ROM, "romimage", "rom" }, /* 15 */ + { IO_MIDIIN, "midiin", "min" }, /* 16 */ + { IO_MIDIOUT, "midiout", "mout" } /* 17 */ }; diff --git a/src/emu/diimage.h b/src/emu/diimage.h index 8b17f4f6587..7781be91dcd 100644 --- a/src/emu/diimage.h +++ b/src/emu/diimage.h @@ -70,7 +70,9 @@ enum iodevice_t IO_CDROM, /* 14 - optical CD-ROM disc */ IO_MAGTAPE, /* 15 - Magentic tape */ IO_ROM, /* 16 - Individual ROM image - the Amstrad CPC has a few applications that were sold on 16kB ROMs */ - IO_COUNT /* 17 - Total Number of IO_devices for searching */ + IO_MIDIIN, /* 17 - MIDI In port */ + IO_MIDIOUT, /* 18 - MIDI Out port */ + IO_COUNT /* 19 - Total Number of IO_devices for searching */ }; enum image_error_t diff --git a/src/emu/emu.mak b/src/emu/emu.mak index 408bd3d8ea5..52459e696fd 100644 --- a/src/emu/emu.mak +++ b/src/emu/emu.mak @@ -345,6 +345,7 @@ EMUIMAGEDEVOBJS = \ $(EMUIMAGEDEV)/flopdrv.o \ $(EMUIMAGEDEV)/floppy.o \ $(EMUIMAGEDEV)/harddriv.o \ + $(EMUIMAGEDEV)/midiin.o \ $(EMUIMAGEDEV)/printer.o \ $(EMUIMAGEDEV)/serial.o \ $(EMUIMAGEDEV)/snapquik.o \ diff --git a/src/emu/imagedev/midiin.c b/src/emu/imagedev/midiin.c new file mode 100644 index 00000000000..1ec7ba774fa --- /dev/null +++ b/src/emu/imagedev/midiin.c @@ -0,0 +1,166 @@ +/********************************************************************* + + midiin.c + + MIDI In image device and serial transmitter + +*********************************************************************/ + +#include "emu.h" +#include "midiin.h" + +/*************************************************************************** + IMPLEMENTATION +***************************************************************************/ + +const device_type MIDIIN = &device_creator<midiin_device>; + +/*------------------------------------------------- + ctor +-------------------------------------------------*/ + +midiin_device::midiin_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MIDIIN, "MIDI In image device", tag, owner, clock), + device_image_interface(mconfig, *this), + device_serial_interface(mconfig, *this) +{ +} + +/*------------------------------------------------- + device_start +-------------------------------------------------*/ + +void midiin_device::device_start() +{ + m_input_func.resolve(m_input_callback, *this); + m_timer = timer_alloc(0); +} + +void midiin_device::device_reset() +{ + m_tx_busy = false; + m_xmit_read = m_xmit_write = 0; + m_timer->adjust(attotime::from_hz(1500), 0, attotime::from_hz(1500)); + + // we don't Rx, we Tx at 31250 8-N-1 + set_rcv_rate(0); + set_tra_rate(31250); + set_data_frame(8, 1, SERIAL_PARITY_NONE); +} + +/*------------------------------------------------- + device_config_complete +-------------------------------------------------*/ + +void midiin_device::device_config_complete(void) +{ + const midiin_config *intf = reinterpret_cast<const midiin_config *>(static_config()); + if(intf != NULL) + { + *static_cast<midiin_config *>(this) = *intf; + } + else + { + memset(&m_input_callback, 0, sizeof(m_input_callback)); + } + update_names(); +} + +/*------------------------------------------------- + device_timer +-------------------------------------------------*/ + +void midiin_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + UINT8 buf[256]; + int bytesRead; + + if (osd_poll_midi_channel(m_midi)) + { + bytesRead = osd_read_midi_channel(m_midi, buf); + + if (bytesRead > 0) + { + for (int i = 0; i < bytesRead; i++) + { + xmit_char(buf[i]); + } + } + } +} + +/*------------------------------------------------- + call_load +-------------------------------------------------*/ + +bool midiin_device::call_load(void) +{ + m_midi = osd_open_midi_input(filename()); + + if (m_midi == NULL) + { + return IMAGE_INIT_FAIL; + } + + return IMAGE_INIT_PASS; +} + +/*------------------------------------------------- + call_unload +-------------------------------------------------*/ + +void midiin_device::call_unload(void) +{ + osd_close_midi_channel(m_midi); +} + +void midiin_device::tra_complete() +{ + // is there more waiting to send? + if (m_xmit_read != m_xmit_write) + { +// printf("tx1 %02x\n", m_xmitring[m_xmit_read]); + transmit_register_setup(m_xmitring[m_xmit_read++]); + if (m_xmit_read >= XMIT_RING_SIZE) + { + m_xmit_read = 0; + } + } + else + { + m_tx_busy = false; + } +} + +void midiin_device::tra_callback() +{ + int bit = transmit_register_get_data_bit(); + m_input_func(bit); +} + +void midiin_device::xmit_char(UINT8 data) +{ +// printf("MIDI in: xmit %02x\n", data); + + // if tx is busy it'll pick this up automatically when it completes + if (!m_tx_busy) + { + m_tx_busy = true; +// printf("tx0 %02x\n", data); + transmit_register_setup(data); + } + else + { + // tx is busy, it'll pick this up next time + m_xmitring[m_xmit_write++] = data; + if (m_xmit_write >= XMIT_RING_SIZE) + { + m_xmit_write = 0; + } + } +} + +void midiin_device::input_callback(UINT8 state) +{ +} + diff --git a/src/emu/imagedev/midiin.h b/src/emu/imagedev/midiin.h new file mode 100644 index 00000000000..ac6bbc49a54 --- /dev/null +++ b/src/emu/imagedev/midiin.h @@ -0,0 +1,89 @@ +/********************************************************************* + + midiin.h + + MIDI In image device + +*********************************************************************/ + +#ifndef __MIDIIN_H__ +#define __MIDIIN_H__ + +#include "image.h" + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +struct midiin_config +{ + /* callback to driver */ + devcb_write_line m_input_callback; +}; + +#define MCFG_MIDIIN_ADD(_tag, _config) \ + MCFG_DEVICE_ADD(_tag, MIDIIN, 0) \ + MCFG_DEVICE_CONFIG(_config) + + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +class midiin_device : public device_t, + public device_image_interface, + public device_serial_interface, + public midiin_config +{ +public: + // construction/destruction + midiin_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // image-level overrides + virtual bool call_load(); + virtual void call_unload(); + + // image device + virtual iodevice_t image_type() const { return IO_MIDIIN; } + virtual bool is_readable() const { return 1; } + virtual bool is_writeable() const { return 0; } + virtual bool is_creatable() const { return 0; } + virtual bool must_be_loaded() const { return 1; } + virtual bool is_reset_on_load() const { return 0; } + virtual const char *file_extensions() const { return "mid"; } + virtual bool core_opens_image_file() const { return FALSE; } + virtual const option_guide *create_option_guide() const { return NULL; } + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + virtual void device_config_complete(); + + // serial overrides + virtual void tra_complete(); // Tx completed sending byte + virtual void tra_callback(); // Tx send bit + void input_callback(UINT8 state); + +private: + static const int XMIT_RING_SIZE = 64; + + void xmit_char(UINT8 data); + + osd_midi_device *m_midi; + emu_timer *m_timer; + devcb_resolved_write_line m_input_func; + UINT8 m_xmitring[XMIT_RING_SIZE]; + int m_xmit_read, m_xmit_write; + bool m_tx_busy; +}; + +// device type definition +extern const device_type MIDIIN; + +// device iterator +typedef device_type_iterator<&device_creator<midiin_device>, midiin_device> midiin_device_iterator; + +#endif /* __MIDIIN_H__ */ diff --git a/src/osd/osdcore.h b/src/osd/osdcore.h index c2f8ffb2e6c..bc078888669 100644 --- a/src/osd/osdcore.h +++ b/src/osd/osdcore.h @@ -895,6 +895,8 @@ void osd_list_midi_devices(void); osd_midi_device *osd_open_midi_input(const char *devname); osd_midi_device *osd_open_midi_output(const char *devname); void osd_close_midi_channel(osd_midi_device *dev); +bool osd_poll_midi_channel(osd_midi_device *dev); +int osd_read_midi_channel(osd_midi_device *dev, UINT8 *pOut); /*************************************************************************** UNCATEGORIZED INTERFACES diff --git a/src/osd/portmedia/pmmidi.c b/src/osd/portmedia/pmmidi.c index 40c2b3d4fd7..9669d761ba4 100644 --- a/src/osd/portmedia/pmmidi.c +++ b/src/osd/portmedia/pmmidi.c @@ -10,6 +10,15 @@ #include "portmidi/portmidi.h" #include "osdcore.h" +struct osd_midi_device +{ + #ifndef DISABLE_MIDI + PortMidiStream *pmStream; + PmEvent rx_evBuf[20]; // up to 20 events + #endif + UINT8 xmit_in[3]; // Pm_Messages mean we can at most have 3 residue bytes +}; + void osd_list_midi_devices(void) { #ifndef DISABLE_MIDI @@ -52,16 +61,177 @@ void osd_list_midi_devices(void) osd_midi_device *osd_open_midi_input(const char *devname) { + #ifndef DISABLE_MIDI + int num_devs = Pm_CountDevices(); + int found_dev = -1; + const PmDeviceInfo *pmInfo; + PortMidiStream *stm; + osd_midi_device *ret; + + for (int i = 0; i < num_devs; i++) + { + pmInfo = Pm_GetDeviceInfo(i); + + if (pmInfo->input) + { + if (!strcmp(devname, pmInfo->name)) + { + found_dev = i; + break; + } + } + } + + if (found_dev >= 0) + { + if (Pm_OpenInput(&stm, found_dev, NULL, 20, NULL, NULL) == pmNoError) + { + ret = (osd_midi_device *)osd_malloc(sizeof(osd_midi_device)); + memset(ret, 0, sizeof(osd_midi_device)); + ret->pmStream = stm; + return ret; + } + else + { + printf("Couldn't open PM device\n"); + return NULL; + } + } + else + { + return NULL; + } + #else return NULL; + #endif } osd_midi_device *osd_open_midi_output(const char *devname) { + #ifndef DISABLE_MIDI + int num_devs = Pm_CountDevices(); + int found_dev = -1; + const PmDeviceInfo *pmInfo; + PortMidiStream *stm; + osd_midi_device *ret; + + for (int i = 0; i < num_devs; i++) + { + pmInfo = Pm_GetDeviceInfo(i); + + if (pmInfo->output) + { + if (!strcmp(devname, pmInfo->name)) + { + found_dev = i; + break; + } + } + } + + if (found_dev >= 0) + { + if (Pm_OpenOutput(&stm, found_dev, NULL, 20, NULL, NULL, 0) == pmNoError) + { + ret = (osd_midi_device *)osd_malloc(sizeof(osd_midi_device)); + memset(ret, 0, sizeof(osd_midi_device)); + ret->pmStream = stm; + return ret; + } + else + { + printf("Couldn't open PM device\n"); + return NULL; + } + } + else + { + return NULL; + } + #endif return NULL; } void osd_close_midi_channel(osd_midi_device *dev) { + #ifndef DISABLE_MIDI + Pm_Close(dev->pmStream); + osd_free(dev); + #endif +} + +bool osd_poll_midi_channel(osd_midi_device *dev) +{ + #ifndef DISABLE_MIDI + PmError chk = Pm_Poll(dev->pmStream); + + return (chk == pmGotData) ? true : false; + #else + return false; + #endif +} + +int osd_read_midi_channel(osd_midi_device *dev, UINT8 *pOut) +{ + #ifndef DISABLE_MIDI + int msgsRead = Pm_Read(dev->pmStream, dev->rx_evBuf, 20); + int bytesOut = 0; + + if (msgsRead <= 0) + { + return 0; + } + + for (int msg = 0; msg < msgsRead; msg++) + { + UINT8 status = Pm_MessageStatus(dev->rx_evBuf[msg].message); + switch ((status>>4) & 0xf) + { + case 0xc: // 2-byte messages + case 0xd: + *pOut++ = status; + *pOut++ = Pm_MessageData1(dev->rx_evBuf[msg].message); + bytesOut += 2; + break; + + case 0xf: // system common + switch (status & 0xf) + { + case 0: // System Exclusive + printf("No SEx please!\n"); + break; + + case 7: // End of System Exclusive + *pOut++ = status; + bytesOut += 1; + break; + + case 2: // song pos + case 3: // song select + *pOut++ = status; + *pOut++ = Pm_MessageData1(dev->rx_evBuf[msg].message); + *pOut++ = Pm_MessageData2(dev->rx_evBuf[msg].message); + bytesOut += 3; + break; + + default: // all other defined Fx messages are 1 byte + break; + } + break; + + default: + *pOut++ = status; + *pOut++ = Pm_MessageData1(dev->rx_evBuf[msg].message); + *pOut++ = Pm_MessageData2(dev->rx_evBuf[msg].message); + bytesOut += 3; + break; + } + } + + return bytesOut; + #else + return 0; + #endif } void osd_init_midi(void) |