aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJavier <dev.git@javispedro.com>2022-01-30 21:28:26 +0100
committerJavier <dev.git@javispedro.com>2022-01-30 21:28:26 +0100
commit83dfe12fc1520888e9ea1570b8d7782b718616e6 (patch)
tree68caf963a9f56425d56f074de0293a4aba0bf851
parent7bb77279bf5b76902c167923d57800e1f6f6073e (diff)
downloadvmusic-83dfe12fc1520888e9ea1570b8d7782b718616e6.tar.gz
vmusic-83dfe12fc1520888e9ea1570b8d7782b718616e6.zip
add minimal flowcontrol for rawmidi
-rw-r--r--Mpu401.cpp45
-rw-r--r--midialsa.cpp84
-rw-r--r--midialsa.h11
3 files changed, 117 insertions, 23 deletions
diff --git a/Mpu401.cpp b/Mpu401.cpp
index d4ca931..a84493e 100644
--- a/Mpu401.cpp
+++ b/Mpu401.cpp
@@ -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;
}
diff --git a/midialsa.h b/midialsa.h
index 4b485d5..e10c5f2 100644
--- a/midialsa.h
+++ b/midialsa.h
@@ -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;
};