diff options
-rw-r--r-- | Mpu401.cpp | 45 | ||||
-rw-r--r-- | midialsa.cpp | 84 | ||||
-rw-r--r-- | midialsa.h | 11 |
3 files changed, 117 insertions, 23 deletions
@@ -62,10 +62,10 @@ #if RT_OPSYS == RT_OPSYS_LINUX #include "midialsa.h" -typedef MIDIOutAlsa MIDIOutBackend; +typedef MIDIAlsa MIDIBackend; #elif RT_OPSYS == RT_OPSYS_WINDOWS #include "midiwin.h" -typedef MIDIOutWin MIDIOutBackend; +typedef MIDIWin MIDIBackend; #endif /********************************************************************************************************************************* @@ -100,16 +100,16 @@ typedef struct { RTIOPORT uPort; /* Current state. */ - /** Whether we have an input byte waiting to be read. */ + /** Whether we have an input/result byte waiting to be read. */ bool fHaveInput; /** Current input byte waiting to be read. */ uint8_t uInput; /** True if UART mode, false if regular/intelligent mode. */ bool fModeUart; - /** MIDI output backend. */ - MIDIOutBackend midiOut; + /** MIDI backend. */ + MIDIBackend midi; - IOMIOPORTHANDLE hIoPorts; + IOMIOPORTHANDLE hIoPorts; } MPUSTATE; /** Pointer to the shared device state. */ typedef MPUSTATE *PMPUSTATE; @@ -142,6 +142,15 @@ static uint8_t mpuReadData(PPDMDEVINS pDevIns) return pThis->uInput; } + if (pThis->fModeUart) { + uint8_t data; + ssize_t read = pThis->midi.read(&data, 1); + Log3Func(("read = %lld\n", read)); + if (read == 1) { + return data; + } + } + LogWarnFunc(("Trying to read, but no data to read\n")); return MPU_RESPONSE_ACK; @@ -152,8 +161,8 @@ static void mpuWriteData(PPDMDEVINS pDevIns, uint8_t data) PMPUSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PMPUSTATE); if (pThis->fModeUart) { - ssize_t written = pThis->midiOut.write(&data, 1); - LogFunc(("written = %lld\n", written)); + ssize_t written = pThis->midi.write(&data, 1); + Log3Func(("written = %lld\n", written)); } else { LogWarnFunc(("Ignoring data, not in UART mode\n")); } @@ -175,12 +184,21 @@ static uint8_t mpuReadStatus(PPDMDEVINS pDevIns) 0 - Data is available for reading 1 - No data is available for reading */ - // In the current design, we are always output ready uint8_t status = 0; - if (!pThis->fHaveInput) { + + bool outputReady = !pThis->fModeUart || pThis->midi.writeAvail() >= 1; + if (!outputReady) { + status |= RT_BIT(6); + } + + bool inputReady = pThis->fHaveInput + || (pThis->fModeUart && pThis->midi.readAvail() >= 1); + if (!inputReady) { status |= RT_BIT(7); } + LogFlow(("mpu status: outputReady=%RTbool inputReady=%RTbool\n", outputReady, inputReady)); + return status; } @@ -206,6 +224,7 @@ static void mpuDoCommand(PPDMDEVINS pDevIns, uint8_t cmd) mpuRespondData(pDevIns, MPU_RESPONSE_ACK); break; case MPU_COMMAND_ENTER_UART: + Log(("Entering UART mode")); pThis->fModeUart = true; mpuRespondData(pDevIns, MPU_RESPONSE_ACK); break; @@ -369,7 +388,7 @@ static DECLCALLBACK(int) mpuR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGM AssertRCReturn(rc, rc); /* Open the MIDI device now. */ - rc = pThis->midiOut.open("default"); + rc = pThis->midi.open("default"); AssertRCReturn(rc, rc); LogRel(("mpu401#%i: Configured on port 0x%x-0x%x\n", iInstance, pThis->uPort, pThis->uPort + MPU_IO_SIZE - 1)); @@ -384,7 +403,7 @@ static DECLCALLBACK(int) mpuR3Destruct(PPDMDEVINS pDevIns) { PMPUSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PMPUSTATE); - int rc = pThis->midiOut.close(); + int rc = pThis->midi.close(); AssertRCReturn(rc, rc); return VINF_SUCCESS; @@ -408,7 +427,7 @@ static DECLCALLBACK(void) mpuR3PowerOff(PPDMDEVINS pDevIns) { PMPUSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PMPUSTATE); - int rc = pThis->midiOut.close(); + int rc = pThis->midi.close(); AssertRC(rc); } diff --git a/midialsa.cpp b/midialsa.cpp index ef07d8a..03d5699 100644 --- a/midialsa.cpp +++ b/midialsa.cpp @@ -25,20 +25,60 @@ #include <alsa/asoundlib.h> #include "midialsa.h" -MIDIOutAlsa::MIDIOutAlsa() : _out(NULL) +#define MAX_POLL_FDS 4 + +static ssize_t rawmidi_avail(snd_rawmidi_t *rmidi) +{ + struct pollfd pfds[MAX_POLL_FDS]; + + int nfds = snd_rawmidi_poll_descriptors(rmidi, pfds, MAX_POLL_FDS); + if (nfds <= 0) { + LogWarn(("ALSA rawmidi avail: no descriptors to poll!")); + return VERR_AUDIO_ENUMERATION_FAILED; + } + + int ready = poll(pfds, nfds, 0); + if (ready < 0) { + if (errno != EAGAIN && errno != EINTR) { + LogWarnFunc(("Cannot poll, errno=%d", errno)); + return VERR_AUDIO_STREAM_NOT_READY; + } + return 0; + } else if (ready == 0) { + return 0; + } else /* ready > 0 */ { + unsigned short revents; + int err = snd_rawmidi_poll_descriptors_revents(rmidi, pfds, nfds, &revents); + if (err != 0) { + LogWarnFunc(("Cannot call revents, err=%d", err)); + return VERR_AUDIO_STREAM_NOT_READY; + } + + if (revents & POLLNVAL) { + LogWarnFunc(("POLLNVAL")); + } + if (revents & POLLERR) { + LogWarnFunc(("POLLERR")); + } + + return revents & (POLLIN | POLLOUT); + } +} + +MIDIAlsa::MIDIAlsa() : _out(NULL) { } -MIDIOutAlsa::~MIDIOutAlsa() +MIDIAlsa::~MIDIAlsa() { } -int MIDIOutAlsa::open(const char *dev) +int MIDIAlsa::open(const char *dev) { int err; - if ((err = snd_rawmidi_open(NULL, &_out, "virtual", SND_RAWMIDI_NONBLOCK))) { + if ((err = snd_rawmidi_open(&_in, &_out, "virtual", SND_RAWMIDI_NONBLOCK))) { LogWarn(("ALSA rawmidi open error: %s\n", snd_strerror(err))); return VERR_AUDIO_STREAM_COULD_NOT_CREATE; } @@ -49,8 +89,12 @@ int MIDIOutAlsa::open(const char *dev) return VINF_SUCCESS; } -int MIDIOutAlsa::close() +int MIDIAlsa::close() { + if (_in) { + snd_rawmidi_close(_in); + _in = NULL; + } if (_out) { snd_rawmidi_close(_out); _out = NULL; @@ -58,7 +102,33 @@ int MIDIOutAlsa::close() return VINF_SUCCESS; } -ssize_t MIDIOutAlsa::write(uint8_t *data, size_t len) +ssize_t MIDIAlsa::writeAvail() { - return snd_rawmidi_write(_out, data, len); + return _out ? rawmidi_avail(_out) : 0; +} + + +ssize_t MIDIAlsa::write(uint8_t *data, size_t len) +{ + ssize_t result = snd_rawmidi_write(_out, data, len); + if (result < 0) { + LogWarn(("ALSA midi write error: %s", snd_strerror(result))); + return VERR_AUDIO_STREAM_NOT_READY; + } + return result; +} + +ssize_t MIDIAlsa::readAvail() +{ + return _in ? rawmidi_avail(_in) : 0; +} + +ssize_t MIDIAlsa::read(uint8_t *buf, size_t len) +{ + ssize_t result = snd_rawmidi_read(_out, buf, len); + if (result < 0) { + LogWarn(("ALSA midi read error: %s", snd_strerror(result))); + return VERR_AUDIO_STREAM_NOT_READY; + } + return result; } @@ -24,18 +24,23 @@ typedef struct _snd_rawmidi snd_rawmidi_t; -class MIDIOutAlsa +class MIDIAlsa { public: - MIDIOutAlsa(); - ~MIDIOutAlsa(); + MIDIAlsa(); + ~MIDIAlsa(); int open(const char *dev); int close(); + ssize_t writeAvail(); ssize_t write(uint8_t *data, size_t len); + ssize_t readAvail(); + ssize_t read(uint8_t *buf, size_t len); + private: + snd_rawmidi_t *_in; snd_rawmidi_t *_out; }; |