diff options
| author | Javier <dev.git@javispedro.com> | 2022-01-30 21:28:26 +0100 | 
|---|---|---|
| committer | Javier <dev.git@javispedro.com> | 2022-01-30 21:28:26 +0100 | 
| commit | 83dfe12fc1520888e9ea1570b8d7782b718616e6 (patch) | |
| tree | 68caf963a9f56425d56f074de0293a4aba0bf851 | |
| parent | 7bb77279bf5b76902c167923d57800e1f6f6073e (diff) | |
| download | vmusic-83dfe12fc1520888e9ea1570b8d7782b718616e6.tar.gz vmusic-83dfe12fc1520888e9ea1570b8d7782b718616e6.zip  | |
add minimal flowcontrol for rawmidi
| -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;  };  | 
