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.
This commit is contained in:
R. Belmont 2013-01-13 03:48:10 +00:00
parent fa807d8a30
commit f6c44c6e9b
8 changed files with 435 additions and 1 deletions

2
.gitattributes vendored
View File

@ -1041,6 +1041,8 @@ src/emu/imagedev/floppy.c svneol=native#text/plain
src/emu/imagedev/floppy.h svneol=native#text/plain
src/emu/imagedev/harddriv.c svneol=native#text/plain
src/emu/imagedev/harddriv.h svneol=native#text/plain
src/emu/imagedev/midiin.c svneol=native#text/plain
src/emu/imagedev/midiin.h svneol=native#text/plain
src/emu/imagedev/printer.c svneol=native#text/plain
src/emu/imagedev/printer.h svneol=native#text/plain
src/emu/imagedev/serial.c svneol=native#text/plain

View File

@ -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 */
};

View File

@ -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

View File

@ -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 \

166
src/emu/imagedev/midiin.c Normal file
View File

@ -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)
{
}

89
src/emu/imagedev/midiin.h Normal file
View File

@ -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__ */

View File

@ -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

View File

@ -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)