void CoreMidiDriver::readProc(const MIDIPacketList *packetList, void *readProcRefCon, void *srcConnRefCon) { Q_UNUSED(srcConnRefCon) CoreMidiSession *data = (CoreMidiSession *)readProcRefCon; if (data->midiSession == NULL) { data->midiSession = driver->createMidiSession(data->sessionID); } QMidiStreamParser &qMidiStreamParser = *data->midiSession->getQMidiStreamParser(); qMidiStreamParser.setTimestamp(MasterClock::getClockNanos()); MIDIPacket const *packet = &packetList->packet[0]; UInt32 numPackets = packetList->numPackets; while (numPackets > 0) { UInt32 packetLen = packet->length; if (packetLen > 0) { qMidiStreamParser.parseStream(packet->data, packetLen); } packet = MIDIPacketNext(packet); numPackets--; } }
void MidiApple::HandleReadCallback( const MIDIPacketList *pktlist, void *srcConnRefCon ) { const char * refName = (const char *) srcConnRefCon; MIDIEndpointRef endPointRef = m_inputDevices.value(refName); if( !m_inputSubs.contains( refName ) ) { // qDebug("HandleReadCallback '%s' not subscribed",refName); // printQStringKeys("m_inputDevices", m_inputDevices); return; } // qDebug("HandleReadCallback '%s' subscribed",refName); bool continueSysEx = false; unsigned int nBytes; const MIDIPacket *packet = &pktlist->packet[0]; unsigned char sysExMessage[SYSEX_LENGTH]; unsigned int sysExLength = 0; for (uint32_t i=0; i<pktlist->numPackets; ++i) { nBytes = packet->length; // Check if this is the end of a continued SysEx message if (continueSysEx) { unsigned int lengthToCopy = qMin(nBytes, SYSEX_LENGTH - sysExLength); // Copy the message into our SysEx message buffer, // making sure not to overrun the buffer memcpy(sysExMessage + sysExLength, packet->data, lengthToCopy); sysExLength += lengthToCopy; // Check if the last byte is SysEx End. continueSysEx = (packet->data[nBytes - 1] == 0xF7); if (!continueSysEx || sysExLength == SYSEX_LENGTH) { // We would process the SysEx message here, as it is we're just ignoring it sysExLength = 0; } } else { UInt16 iByte, size; iByte = 0; while (iByte < nBytes) { size = 0; // First byte should be status unsigned char status = packet->data[iByte]; if (status < 0xC0) { size = 3; } else if (status < 0xE0) { size = 2; } else if (status < 0xF0) { size = 3; } else if (status == 0xF0) { // MIDI SysEx then we copy the rest of the message into the SysEx message buffer unsigned int lengthLeftInMessage = nBytes - iByte; unsigned int lengthToCopy = qMin(lengthLeftInMessage, SYSEX_LENGTH); memcpy(sysExMessage + sysExLength, packet->data, lengthToCopy); sysExLength += lengthToCopy; size = 0; iByte = nBytes; // Check whether the message at the end is the end of the SysEx continueSysEx = (packet->data[nBytes - 1] != 0xF7); } else if (status < 0xF3) { size = 3; } else if (status == 0xF3) { size = 2; } else { size = 1; } unsigned char messageChannel = status & 0xF; const MidiEventTypes cmdtype = static_cast<MidiEventTypes>( status & 0xF0 ); const int par1 = packet->data[iByte + 1]; const int par2 = packet->data[iByte + 2]; switch (cmdtype) { case MidiNoteOff: //0x80: case MidiNoteOn: //0x90: case MidiKeyPressure: //0xA0: notifyMidiPortList(m_inputSubs[refName],MidiEvent( cmdtype, messageChannel, par1 - KeysPerOctave, par2 & 0xff, &endPointRef )); break; case MidiControlChange: //0xB0: case MidiProgramChange: //0xC0: case MidiChannelPressure: //0xD0: notifyMidiPortList(m_inputSubs[refName],MidiEvent( cmdtype, messageChannel, par1, par2 & 0xff, &endPointRef )); break; case MidiPitchBend: //0xE0: notifyMidiPortList(m_inputSubs[refName],MidiEvent( cmdtype, messageChannel, par1 + par2 * 128, 0, &endPointRef )); break; case MidiActiveSensing: //0xF0 case 0xF0: break; default: qDebug("endPointRef name='%s':Some other message %d", refName, cmdtype); break; } iByte += size; } } packet = MIDIPacketNext(packet); } }
static void MidiInProc(const MIDIPacketList* pktList, void* readProcRefCon, void* srcConnRefCon) { Q_UNUSED(readProcRefCon); CoreMidiInputDevice* self = static_cast<CoreMidiInputDevice*>(srcConnRefCon); Q_ASSERT(self != 0); // Go thru all packets in the midi packet list const MIDIPacket* packet = &pktList->packet[0]; for (quint32 p = 0; p < pktList->numPackets && packet != NULL; ++p) { // Go thru all simultaneously-occurring messages in the packet for (quint32 i = 0; i < packet->length && i < 256; ++i) { uchar cmd = 0; uchar data1 = 0; uchar data2 = 0; quint32 channel = 0; uchar value = 0; // MIDI Command cmd = packet->data[0]; if (!MIDI_IS_CMD(cmd)) continue; // Not a MIDI command. Skip to the next byte. if (cmd == MIDI_SYSEX) break; // Sysex reserves the whole packet. Not interested. // 1 or 2 MIDI Data bytes if (packet->length > (i + 1) && !MIDI_IS_CMD(packet->data[i + 1])) { data1 = packet->data[++i]; if (packet->length > (i + 1) && !MIDI_IS_CMD(packet->data[i + 1])) data2 = packet->data[++i]; else // no data2 ? Could be a Program Change, so act like Linux // and give it a value data2 = 127; } if (cmd >= MIDI_BEAT_CLOCK && cmd <= MIDI_BEAT_STOP) { if (self->processMBC(cmd) == false) continue; } // Convert the data to QLC input channel & value if (QLCMIDIProtocol::midiToInput(cmd, data1, data2, self->midiChannel(), &channel, &value) == true) { self->emitValueChanged(channel, value); // for MIDI beat clock signals, // generate a synthetic release event if (cmd >= MIDI_BEAT_CLOCK && cmd <= MIDI_BEAT_STOP) self->emitValueChanged(channel, 0); } } // Get the next packet in the packet list packet = MIDIPacketNext(packet); } }