void qxgeditMidiDevice::sendSysex ( unsigned char *pSysex, unsigned short iSysex ) const { #ifdef CONFIG_DEBUG fprintf(stderr, "qxgeditMidiDevice::sendSysex(%p, %u)", pSysex, iSysex); fprintf(stderr, " sysex {"); for (unsigned short i = 0; i < iSysex; ++i) fprintf(stderr, " %02x", pSysex[i]); fprintf(stderr, " }\n"); #endif // Don't do anything else if engine // has not been activated... if (m_pAlsaSeq == NULL) return; // Initialize sequencer event... snd_seq_event_t ev; snd_seq_ev_clear(&ev); // Addressing... snd_seq_ev_set_source(&ev, m_iAlsaPort); snd_seq_ev_set_subs(&ev); // The event will be direct... snd_seq_ev_set_direct(&ev); // Just set SYSEX stuff and send it out.. ev.type = SND_SEQ_EVENT_SYSEX; snd_seq_ev_set_sysex(&ev, iSysex, pSysex); snd_seq_event_output_direct(m_pAlsaSeq, &ev); }
void ALSAMidiDriver::send_sysex(uint8 status,const uint8 *msg,uint16 length) { unsigned char buf[1024]; if (length > 511) { perr << "ALSAMidiDriver: " << "Cannot send SysEx block - data too large" << std::endl; return; } buf[0] = status; memcpy(buf + 1, msg, length); snd_seq_ev_set_sysex(&ev, length + 1, &buf); send_event(1); }
void MidiDriver_ALSA::sysEx(const byte *msg, uint16 length) { unsigned char buf[266]; assert(length + 2 <= ARRAYSIZE(buf)); // Add SysEx frame buf[0] = 0xF0; memcpy(buf + 1, msg, length); buf[length + 1] = 0xF7; // Send it snd_seq_ev_set_sysex(&ev, length + 2, &buf); send_event(1); }
/* Send sysex buffer (buffer must contain complete sysex msg w/ SYSEX & EOX) */ int midi_send_sysex(int port, void *buf, int buflen) { int err; snd_seq_event_t sendev; if (port >= MAX_PORTS) return -1; snd_seq_ev_clear(&sendev); snd_seq_ev_set_source(&sendev, ports[port]); snd_seq_ev_set_subs(&sendev); snd_seq_ev_set_sysex(&sendev, buflen, buf); snd_seq_ev_set_direct(&sendev); err = snd_seq_event_output_direct(seq, &sendev); if (err < 0) eprintf("Couldn't send MIDI sysex: %s\n", snd_strerror(err)); return err; }
void MidiDriver_ALSA::sysEx(const byte *msg, uint16 length) { if (!_isOpen) { warning("MidiDriver_ALSA: Got SysEx while not open"); return; } unsigned char buf[266]; assert(length + 2 <= ARRAYSIZE(buf)); // Add SysEx frame buf[0] = 0xF0; memcpy(buf + 1, msg, length); buf[length + 1] = 0xF7; // Send it snd_seq_ev_set_sysex(&ev, length + 2, &buf); send_event(1); }
/* takes an native event, encodes to alsa event, puts it in the queue */ void midibus::sysex( event *a_e24 ) { lock(); snd_seq_event_t ev; /* clear event */ snd_seq_ev_clear( &ev ); snd_seq_ev_set_priority( &ev, 1 ); /* set source */ snd_seq_ev_set_source(&ev, m_local_addr_port ); snd_seq_ev_set_subs(&ev); // its immediate snd_seq_ev_set_direct( &ev ); unsigned char *data = a_e24->get_sysex(); long data_size = a_e24->get_size(); for( long offset = 0; offset < data_size; offset += c_midibus_sysex_chunk ){ long data_left = data_size - offset; snd_seq_ev_set_sysex( &ev, min( data_left, c_midibus_sysex_chunk), &data[offset] ); /* pump it into the queue */ snd_seq_event_output_direct(m_seq, &ev); usleep(80000); flush(); } unlock(); }
void AlsaMidiOutputDevice::writeSysEx(QByteArray message) { if(message.isEmpty()) return; if (isOpen() == false) return; snd_seq_event_t ev; snd_seq_ev_clear(&ev); snd_seq_ev_set_dest(&ev, m_receiver_address->client, m_receiver_address->port); //snd_seq_ev_set_subs(&ev); snd_seq_ev_set_direct(&ev); snd_seq_ev_set_sysex (&ev, message.count(), message.data()); if (snd_seq_event_output(m_alsa, &ev) < 0) qDebug() << "snd_seq_event_output ERROR"; // Make sure that all values go to the MIDI endpoint snd_seq_drain_output(m_alsa); }
void midibus::sysex (event * e24) { #ifdef SEQ64_HAVE_LIBASOUND automutex locker(m_mutex); snd_seq_event_t ev; snd_seq_ev_clear(&ev); /* clear event */ snd_seq_ev_set_priority(&ev, 1); snd_seq_ev_set_source(&ev, m_local_addr_port); /* set source */ snd_seq_ev_set_subs(&ev); snd_seq_ev_set_direct(&ev); /* it's immediate */ /* * Replaced by a vector of midibytes: * * midibyte * data = e24->get_sysex(); * * This is a bit tricky, and relies on the standard property of * std::vector where all n elements of the vector are guaranteed to be * stored contiguously (in order to be accessible via random-access * iterators). */ event::SysexContainer & data = e24->get_sysex(); int data_size = e24->get_sysex_size(); for (int offset = 0; offset < data_size; offset += c_midibus_sysex_chunk) { int data_left = data_size - offset; snd_seq_ev_set_sysex ( &ev, min(data_left, c_midibus_sysex_chunk), &data[offset] ); snd_seq_event_output_direct(m_seq, &ev); /* pump into queue */ usleep(SEQ64_USLEEP_US); flush(); } #endif // SEQ64_HAVE_LIBASOUND }
/************************************************************************** * modLongData [internal] */ static DWORD modLongData(WORD wDevID, LPMIDIHDR lpMidiHdr, DWORD dwSize) { int len_add = 0; LPBYTE lpData, lpNewData = NULL; snd_seq_event_t event; TRACE("(%04X, %p, %08lX);\n", wDevID, lpMidiHdr, dwSize); /* Note: MS doc does not say much about the dwBytesRecorded member of the MIDIHDR structure * but it seems to be used only for midi input. * Taking a look at the WAVEHDR structure (which is quite similar) confirms this assumption. */ if (wDevID >= MODM_NumDevs) return MMSYSERR_BADDEVICEID; if (!MidiOutDev[wDevID].bEnabled) return MIDIERR_NODEVICE; if (midiSeq == NULL) { WARN("can't play !\n"); return MIDIERR_NODEVICE; } lpData = (LPBYTE) lpMidiHdr->lpData; if (lpData == NULL) return MIDIERR_UNPREPARED; if (!(lpMidiHdr->dwFlags & MHDR_PREPARED)) return MIDIERR_UNPREPARED; if (lpMidiHdr->dwFlags & MHDR_INQUEUE) return MIDIERR_STILLPLAYING; lpMidiHdr->dwFlags &= ~MHDR_DONE; lpMidiHdr->dwFlags |= MHDR_INQUEUE; /* FIXME: MS doc is not 100% clear. Will lpData only contain system exclusive * data, or can it also contain raw MIDI data, to be split up and sent to * modShortData() ? * If the latest is true, then the following WARNing will fire up */ if (lpData[0] != 0xF0 || lpData[lpMidiHdr->dwBufferLength - 1] != 0xF7) { WARN("Alleged system exclusive buffer is not correct\n\tPlease report with MIDI file\n"); lpNewData = HeapAlloc(GetProcessHeap(), 0, lpMidiHdr->dwBufferLength + 2); } TRACE("dwBufferLength=%lu !\n", lpMidiHdr->dwBufferLength); TRACE(" %02X %02X %02X ... %02X %02X %02X\n", lpData[0], lpData[1], lpData[2], lpData[lpMidiHdr->dwBufferLength-3], lpData[lpMidiHdr->dwBufferLength-2], lpData[lpMidiHdr->dwBufferLength-1]); switch (MidiOutDev[wDevID].caps.wTechnology) { case MOD_FMSYNTH: /* FIXME: I don't think there is much to do here */ break; case MOD_MIDIPORT: if (lpData[0] != 0xF0) { /* Send start of System Exclusive */ len_add = 1; lpData[0] = 0xF0; memcpy(lpNewData, lpData, lpMidiHdr->dwBufferLength); WARN("Adding missing 0xF0 marker at the beginning of " "system exclusive byte stream\n"); } if (lpData[lpMidiHdr->dwBufferLength-1] != 0xF7) { /* Send end of System Exclusive */ memcpy(lpData + len_add, lpData, lpMidiHdr->dwBufferLength); lpNewData[lpMidiHdr->dwBufferLength + len_add - 1] = 0xF0; len_add++; WARN("Adding missing 0xF7 marker at the end of " "system exclusive byte stream\n"); } snd_seq_ev_clear(&event); snd_seq_ev_set_direct(&event); snd_seq_ev_set_source(&event, port_out); snd_seq_ev_set_dest(&event, MidiOutDev[wDevID].addr.client, MidiOutDev[wDevID].addr.port); TRACE("client = %d port = %d\n", MidiOutDev[wDevID].addr.client, MidiOutDev[wDevID].addr.port); snd_seq_ev_set_sysex(&event, lpMidiHdr->dwBufferLength + len_add, lpNewData ? lpNewData : lpData); snd_seq_event_output_direct(midiSeq, &event); if (lpNewData) HeapFree(GetProcessHeap(), 0, lpData); break; default: WARN("Technology not supported (yet) %d !\n", MidiOutDev[wDevID].caps.wTechnology); return MMSYSERR_NOTENABLED; } lpMidiHdr->dwFlags &= ~MHDR_INQUEUE; lpMidiHdr->dwFlags |= MHDR_DONE; if (MIDI_NotifyClient(wDevID, MOM_DONE, (DWORD)lpMidiHdr, 0L) != MMSYSERR_NOERROR) { WARN("can't notify client !\n"); return MMSYSERR_INVALPARAM; } return MMSYSERR_NOERROR; }
/************************************************************************** * modData [internal] */ static DWORD modData(WORD wDevID, DWORD dwParam) { BYTE evt = LOBYTE(LOWORD(dwParam)); BYTE d1 = HIBYTE(LOWORD(dwParam)); BYTE d2 = LOBYTE(HIWORD(dwParam)); TRACE("(%04X, %08lX);\n", wDevID, dwParam); if (wDevID >= MODM_NumDevs) return MMSYSERR_BADDEVICEID; if (!MidiOutDev[wDevID].bEnabled) return MIDIERR_NODEVICE; if (midiSeq == NULL) { WARN("can't play !\n"); return MIDIERR_NODEVICE; } switch (MidiOutDev[wDevID].caps.wTechnology) { case MOD_SYNTH: case MOD_MIDIPORT: { int handled = 1; /* Assume event is handled */ snd_seq_event_t event; snd_seq_ev_clear(&event); snd_seq_ev_set_direct(&event); snd_seq_ev_set_source(&event, port_out); snd_seq_ev_set_dest(&event, MidiOutDev[wDevID].addr.client, MidiOutDev[wDevID].addr.port); switch (evt & 0xF0) { case MIDI_CMD_NOTE_OFF: snd_seq_ev_set_noteoff(&event, evt&0x0F, d1, d2); break; case MIDI_CMD_NOTE_ON: snd_seq_ev_set_noteon(&event, evt&0x0F, d1, d2); break; case MIDI_CMD_NOTE_PRESSURE: snd_seq_ev_set_keypress(&event, evt&0x0F, d1, d2); break; case MIDI_CMD_CONTROL: snd_seq_ev_set_controller(&event, evt&0x0F, d1, d2); break; case MIDI_CMD_BENDER: snd_seq_ev_set_pitchbend(&event, evt&0x0F, ((WORD)d2 << 7 | (WORD)d1) - 0x2000); break; case MIDI_CMD_PGM_CHANGE: snd_seq_ev_set_pgmchange(&event, evt&0x0F, d1); break; case MIDI_CMD_CHANNEL_PRESSURE: snd_seq_ev_set_chanpress(&event, evt&0x0F, d1); break; case MIDI_CMD_COMMON_SYSEX: switch (evt & 0x0F) { case 0x00: /* System Exclusive, don't do it on modData, * should require modLongData*/ case 0x01: /* Undefined */ case 0x04: /* Undefined. */ case 0x05: /* Undefined. */ case 0x07: /* End of Exclusive. */ case 0x09: /* Undefined. */ case 0x0D: /* Undefined. */ handled = 0; break; case 0x06: /* Tune Request */ case 0x08: /* Timing Clock. */ case 0x0A: /* Start. */ case 0x0B: /* Continue */ case 0x0C: /* Stop */ case 0x0E: /* Active Sensing. */ /* FIXME: Is this function suitable for these purposes (and also Song Select and Song Position Pointer) */ snd_seq_ev_set_sysex(&event, 1, &evt); break; case 0x0F: /* Reset */ /* snd_seq_ev_set_sysex(&event, 1, &evt); this other way may be better */ { BYTE reset_sysex_seq[] = {MIDI_CMD_COMMON_SYSEX, 0x7e, 0x7f, 0x09, 0x01, 0xf7}; snd_seq_ev_set_sysex(&event, sizeof(reset_sysex_seq), reset_sysex_seq); } break; case 0x03: /* Song Select. */ { BYTE buf[2]; buf[0] = evt; buf[1] = d1; snd_seq_ev_set_sysex(&event, sizeof(buf), buf); } break; case 0x02: /* Song Position Pointer. */ { BYTE buf[3]; buf[0] = evt; buf[1] = d1; buf[2] = d2; snd_seq_ev_set_sysex(&event, sizeof(buf), buf); } break; } break; } if (handled) snd_seq_event_output_direct(midiSeq, &event); } break; default: WARN("Technology not supported (yet) %d !\n", MidiOutDev[wDevID].caps.wTechnology); return MMSYSERR_NOTENABLED; } return MMSYSERR_NOERROR; }
// MIDI clip freewheeling event enqueue method (needed for export). void qtractorMidiClip::enqueue_export ( qtractorTrack *pTrack, qtractorMidiEvent *pEvent, unsigned long iTime, float fGain ) const { qtractorSession *pSession = pTrack->session(); if (pSession == NULL) return; snd_seq_event_t ev; snd_seq_ev_clear(&ev); snd_seq_ev_schedule_tick(&ev, 0, 0, iTime); switch (pEvent->type()) { case qtractorMidiEvent::NOTEON: ev.type = SND_SEQ_EVENT_NOTE; ev.data.note.channel = pTrack->midiChannel(); ev.data.note.note = pEvent->note(); ev.data.note.velocity = int(fGain * float(pEvent->value())) & 0x7f; ev.data.note.duration = pEvent->duration(); break; case qtractorMidiEvent::KEYPRESS: ev.type = SND_SEQ_EVENT_KEYPRESS; ev.data.note.channel = pTrack->midiChannel(); ev.data.note.note = pEvent->note(); ev.data.note.velocity = pEvent->velocity(); ev.data.note.duration = 0; break; case qtractorMidiEvent::CONTROLLER: ev.type = SND_SEQ_EVENT_CONTROLLER; ev.data.control.channel = pTrack->midiChannel(); ev.data.control.param = pEvent->controller(); ev.data.control.value = pEvent->value(); break; case qtractorMidiEvent::PGMCHANGE: ev.type = SND_SEQ_EVENT_PGMCHANGE; ev.data.control.channel = pTrack->midiChannel(); ev.data.control.value = pEvent->value(); break; case qtractorMidiEvent::CHANPRESS: ev.type = SND_SEQ_EVENT_CHANPRESS; ev.data.control.channel = pTrack->midiChannel(); ev.data.control.value = pEvent->value(); break; case qtractorMidiEvent::PITCHBEND: ev.type = SND_SEQ_EVENT_PITCHBEND; ev.data.control.channel = pTrack->midiChannel(); ev.data.control.value = pEvent->pitchBend(); break; case qtractorMidiEvent::SYSEX: ev.type = SND_SEQ_EVENT_SYSEX; snd_seq_ev_set_sysex(&ev, pEvent->sysex_len(), pEvent->sysex()); break; default: break; } qtractorTimeScale::Cursor& cursor = pSession->timeScale()->cursor(); qtractorTimeScale::Node *pNode = cursor.seekTick(iTime); const unsigned long t1 = pNode->frameFromTick(iTime); unsigned long t2 = t1; if (ev.type == SND_SEQ_EVENT_NOTE && ev.data.note.duration > 0) { iTime += (ev.data.note.duration - 1); pNode = cursor.seekTick(iTime); t2 += (pNode->frameFromTick(iTime) - t1); } // Do it for the MIDI track plugins... qtractorMidiManager *pMidiManager = (pTrack->pluginList())->midiManager(); if (pMidiManager) pMidiManager->queued(&ev, t1, t2); // And for the MIDI output plugins as well... // Target MIDI bus... qtractorMidiBus *pMidiBus = static_cast<qtractorMidiBus *> (pTrack->outputBus()); if (pMidiBus && pMidiBus->pluginList_out()) { pMidiManager = (pMidiBus->pluginList_out())->midiManager(); if (pMidiManager) pMidiManager->queued(&ev, t1, t2); } }