static void Func_ProgramChange( int channel, int program ) { snd_seq_event_t ev; snd_seq_ev_clear(&ev); snd_seq_ev_set_pgmchange(&ev, channel, program); sequence_event(&ev); }
bool MidiAlsaDevice::putMidiEvent(const MidiPlayEvent& e) { if (midiOutputTrace) { printf("MidiOut: midiAlsa: "); e.dump(); } int chn = e.channel(); int a = e.dataA(); int b = e.dataB(); snd_seq_event_t event; memset(&event, 0, sizeof (event)); event.queue = SND_SEQ_QUEUE_DIRECT; event.source = losPort; event.dest = adr; switch (e.type()) { case ME_NOTEON: snd_seq_ev_set_noteon(&event, chn, a, b); break; case ME_NOTEOFF: snd_seq_ev_set_noteoff(&event, chn, a, 0); break; case ME_PROGRAM: snd_seq_ev_set_pgmchange(&event, chn, a); break; case ME_CONTROLLER: #if 1 snd_seq_ev_set_controller(&event, chn, a, b); #else { int a = e.dataA(); int b = e.dataB(); int chn = e.channel(); if (a < CTRL_14_OFFSET) { // 7 Bit Controller snd_seq_ev_set_controller(&event, chn, a, b); } else if (a < CTRL_RPN_OFFSET) { // 14 bit high resolution controller int ctrlH = (a >> 8) & 0x7f; int ctrlL = a & 0x7f; a = (ctrlH << 7) + ctrlL; snd_seq_ev_set_controller(&event, chn, a, b); event.type = SND_SEQ_EVENT_CONTROL14; } else if (a < CTRL_NRPN_OFFSET) { // RPN 7-Bit Controller int ctrlH = (a >> 8) & 0x7f; int ctrlL = a & 0x7f; a = (ctrlH << 7) + ctrlL; b <<= 7; snd_seq_ev_set_controller(&event, chn, a, b); event.type = SND_SEQ_EVENT_REGPARAM; }
void MidiDriver_ALSA::send(uint32 b) { unsigned int midiCmd[4]; ev.type = SND_SEQ_EVENT_OSS; midiCmd[3] = (b & 0xFF000000) >> 24; midiCmd[2] = (b & 0x00FF0000) >> 16; midiCmd[1] = (b & 0x0000FF00) >> 8; midiCmd[0] = (b & 0x000000FF); ev.data.raw32.d[0] = midiCmd[0]; ev.data.raw32.d[1] = midiCmd[1]; ev.data.raw32.d[2] = midiCmd[2]; unsigned char chanID = midiCmd[0] & 0x0F; switch (midiCmd[0] & 0xF0) { case 0x80: snd_seq_ev_set_noteoff(&ev, chanID, midiCmd[1], midiCmd[2]); send_event(1); break; case 0x90: snd_seq_ev_set_noteon(&ev, chanID, midiCmd[1], midiCmd[2]); send_event(1); break; case 0xA0: snd_seq_ev_set_keypress(&ev, chanID, midiCmd[1], midiCmd[2]); send_event(1); break; case 0xB0: /* is it this simple ? Wow... */ snd_seq_ev_set_controller(&ev, chanID, midiCmd[1], midiCmd[2]); send_event(1); break; case 0xC0: snd_seq_ev_set_pgmchange(&ev, chanID, midiCmd[1]); send_event(0); break; case 0xD0: snd_seq_ev_set_chanpress(&ev, chanID, midiCmd[1]); send_event(1); break; case 0xE0:{ // long theBend = ((((long)midiCmd[1] + (long)(midiCmd[2] << 7))) - 0x2000) / 4; // snd_seq_ev_set_pitchbend(&ev, chanID, theBend); long theBend = ((long)midiCmd[1] + (long)(midiCmd[2] << 7)) - 0x2000; snd_seq_ev_set_pitchbend(&ev, chanID, theBend); send_event(1); } break; default: warning("Unknown MIDI Command: %08x", (int)b); /* I don't know if this works but, well... */ send_event(1); break; } }
void ALSAMidiDriver::send(uint32 b) { unsigned int midiCmd[4]; ev.type = SND_SEQ_EVENT_OSS; midiCmd[3] = (b & 0xFF000000) >> 24; midiCmd[2] = (b & 0x00FF0000) >> 16; midiCmd[1] = (b & 0x0000FF00) >> 8; midiCmd[0] = (b & 0x000000FF); ev.data.raw32.d[0] = midiCmd[0]; ev.data.raw32.d[1] = midiCmd[1]; ev.data.raw32.d[2] = midiCmd[2]; unsigned char chanID = midiCmd[0] & 0x0F; switch (midiCmd[0] & 0xF0) { case 0x80: snd_seq_ev_set_noteoff(&ev, chanID, midiCmd[1], midiCmd[2]); send_event(1); break; case 0x90: snd_seq_ev_set_noteon(&ev, chanID, midiCmd[1], midiCmd[2]); send_event(1); break; case 0xB0: /* is it this simple ? Wow... */ snd_seq_ev_set_controller(&ev, chanID, midiCmd[1], midiCmd[2]); send_event(1); break; case 0xC0: snd_seq_ev_set_pgmchange(&ev, chanID, midiCmd[1]); send_event(0); break; case 0xD0: snd_seq_ev_set_chanpress(&ev, chanID, midiCmd[1]); send_event(0); break; case 0xE0:{ // long theBend = ((((long)midiCmd[1] + (long)(midiCmd[2] << 7))) - 0x2000) / 4; // snd_seq_ev_set_pitchbend(&ev, chanID, theBend); long theBend = (static_cast<long>(midiCmd[1]) + static_cast<long>(midiCmd[2] << 7)) - 0x2000; snd_seq_ev_set_pitchbend(&ev, chanID, theBend); send_event(1); } break; default: perr << "ALSAMidiDriver: Unknown Command: " << std::hex << static_cast<int>(b) << std::dec << std::endl; /* I don't know if this works but, well... */ send_event(1); break; } }
void prog_alsa(void* seqq, unsigned char chan, unsigned char indx) { ALSA_SEQ* seq = (ALSA_SEQ*)seqq; snd_seq_event_t ev; snd_seq_ev_clear(&ev); snd_seq_ev_set_source(&ev, seq->g_port); snd_seq_ev_set_subs(&ev); snd_seq_ev_set_direct(&ev); //... // set event type, data, so on.. snd_seq_ev_set_pgmchange(&ev, chan, indx); snd_seq_event_output(seq->g_seq, &ev); snd_seq_drain_output(seq->g_seq); }
void sys_alsa_putmidimess(int portno, int a, int b, int c) { int channel; snd_seq_event_t ev; snd_seq_ev_clear(&ev); if (portno >= 0 && portno < alsa_nmidiout) { if (a >= 224) // pitchbend { channel = a-224; snd_seq_ev_set_pitchbend(&ev, channel, (((c<<7)|b)-8192)); /* b and c are already correct but alsa needs to recalculate them */ } else if (a >= 208) // touch { channel = a-208; snd_seq_ev_set_chanpress(&ev,channel,b); } else if (a >= 192) // program { channel = a-192; snd_seq_ev_set_pgmchange(&ev,channel,b); } else if (a >= 176) // controller { channel = a-176; snd_seq_ev_set_controller(&ev,channel,b,c); } else if (a >= 160) // polytouch { channel = a-160; snd_seq_ev_set_keypress(&ev,channel,b,c); } else if (a >= 144) // note { channel = a-144; if (c) snd_seq_ev_set_noteon(&ev,channel,b,c); else snd_seq_ev_set_noteoff(&ev,channel,b,c); } snd_seq_ev_set_direct(&ev); snd_seq_ev_set_subs(&ev); snd_seq_ev_set_source(&ev,alsa_midioutfd[portno]); snd_seq_event_output_direct(midi_handle,&ev); } //post("%d %d %d\n",a,b,c); }
static void program_change(snd_seq_t *seq, int port, int chan, int program) { snd_seq_event_t ev; snd_seq_ev_clear(&ev); snd_seq_ev_set_source(&ev, port); snd_seq_ev_set_subs(&ev); snd_seq_ev_set_direct(&ev); //... // set event type, data, so on.. //set_event_time(&ev, Mf_currtime); //snd_seq_ev_schedule_tick(&ev, q, 0, Mf_currtime); snd_seq_ev_set_pgmchange(&ev, chan, program); int rc = snd_seq_event_output(seq, &ev); if (rc < 0) { printf("written = %i (%s)\n", rc, snd_strerror(rc)); } snd_seq_drain_output(seq); }
void AlsaMidiOutputDevice::writeFeedback(uchar cmd, uchar data1, uchar data2) { if (isOpen() == false) return; // Setup a common event structure for all values 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); uchar midiCmd = MIDI_CMD(cmd); uchar midiCh = MIDI_CH(cmd); bool invalidCmd = false; switch(midiCmd) { case MIDI_NOTE_OFF: snd_seq_ev_set_noteoff(&ev, midiCh, data1, data2); break; case MIDI_NOTE_ON: snd_seq_ev_set_noteon(&ev, midiCh, data1, data2); break; case MIDI_CONTROL_CHANGE: snd_seq_ev_set_controller(&ev, midiCh, data1, data2); break; case MIDI_PROGRAM_CHANGE: snd_seq_ev_set_pgmchange(&ev, midiCh, data1); break; case MIDI_NOTE_AFTERTOUCH: snd_seq_ev_set_keypress(&ev, midiCh, data1, data2); break; case MIDI_CHANNEL_AFTERTOUCH: snd_seq_ev_set_chanpress(&ev, midiCh, data1); break; case MIDI_PITCH_WHEEL: snd_seq_ev_set_pitchbend(&ev, midiCh, ((data1 & 0x7f) | ((data2 & 0x7f) << 7)) - 8192); break; default: // What to do here ?? invalidCmd = true; break; } if (!invalidCmd) { 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 AlsaMidiOutputDevice::writeUniverse(const QByteArray& universe) { if (isOpen() == false) return; // Setup a common event structure for all values 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); // Since MIDI devices can have only 128 real channels, we don't // attempt to write more than that. for (uchar channel = 0; channel < MAX_MIDI_DMX_CHANNELS && channel < universe.size(); channel++) { // Scale 0-255 to 0-127 char scaled = DMX2MIDI(universe[channel]); bool invalidData = false; // Since MIDI is so slow, we only send values that are actually changed if (m_universe[channel] == scaled) continue; // Store the changed MIDI value m_universe[channel] = scaled; if (mode() == Note) { qDebug() << "Send out NOTE"; // 0 is sent as a note off // 1-127 is sent as note on if (scaled == 0) snd_seq_ev_set_noteoff(&ev, midiChannel(), channel, scaled); else snd_seq_ev_set_noteon(&ev, midiChannel(), channel, scaled); snd_seq_event_output(m_alsa, &ev); } else if (mode() == ProgramChange) { qDebug() << "Send out Program Change"; snd_seq_ev_set_pgmchange(&ev, midiChannel(), channel); } else if (mode() == ControlChange) { qDebug() << "Send out CC. Channel: " << midiChannel() << ", CC: " << channel << ", val: " << scaled; // Control change snd_seq_ev_set_controller(&ev, midiChannel(), channel, scaled); } else invalidData = true; if (!invalidData) 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 MidiDriver_ALSA::send(uint32 b) { if (!_isOpen) { warning("MidiDriver_ALSA: Got event while not open"); return; } unsigned int midiCmd[4]; ev.type = SND_SEQ_EVENT_OSS; midiCmd[3] = (b & 0xFF000000) >> 24; midiCmd[2] = (b & 0x00FF0000) >> 16; midiCmd[1] = (b & 0x0000FF00) >> 8; midiCmd[0] = (b & 0x000000FF); ev.data.raw32.d[0] = midiCmd[0]; ev.data.raw32.d[1] = midiCmd[1]; ev.data.raw32.d[2] = midiCmd[2]; unsigned char chanID = midiCmd[0] & 0x0F; switch (midiCmd[0] & 0xF0) { case 0x80: snd_seq_ev_set_noteoff(&ev, chanID, midiCmd[1], midiCmd[2]); send_event(1); break; case 0x90: snd_seq_ev_set_noteon(&ev, chanID, midiCmd[1], midiCmd[2]); send_event(1); break; case 0xA0: snd_seq_ev_set_keypress(&ev, chanID, midiCmd[1], midiCmd[2]); send_event(1); break; case 0xB0: /* is it this simple ? Wow... */ snd_seq_ev_set_controller(&ev, chanID, midiCmd[1], midiCmd[2]); // We save the volume of the first MIDI channel here to utilize it in // our workaround for broken USB-MIDI cables. if (chanID == 0 && midiCmd[1] == 0x07) _channel0Volume = midiCmd[2]; send_event(1); break; case 0xC0: snd_seq_ev_set_pgmchange(&ev, chanID, midiCmd[1]); send_event(0); // Send a volume change command to work around a firmware bug in common // USB-MIDI cables. If the first MIDI command in a USB packet is a // Cx or Dx command, the second command in the packet is dropped // somewhere. send(0x07B0 | (_channel0Volume << 16)); break; case 0xD0: snd_seq_ev_set_chanpress(&ev, chanID, midiCmd[1]); send_event(1); // Send a volume change command to work around a firmware bug in common // USB-MIDI cables. If the first MIDI command in a USB packet is a // Cx or Dx command, the second command in the packet is dropped // somewhere. send(0x07B0 | (_channel0Volume << 16)); break; case 0xE0: { // long theBend = ((((long)midiCmd[1] + (long)(midiCmd[2] << 7))) - 0x2000) / 4; // snd_seq_ev_set_pitchbend(&ev, chanID, theBend); long theBend = ((long)midiCmd[1] + (long)(midiCmd[2] << 7)) - 0x2000; snd_seq_ev_set_pitchbend(&ev, chanID, theBend); send_event(1); } break; default: warning("Unknown MIDI Command: %08x", (int)b); /* I don't know if this works but, well... */ send_event(1); break; } }
void MidiAlsaSeq::processOutEvent( const MidiEvent& event, const MidiTime& time, const MidiPort* port ) { // HACK!!! - need a better solution which isn't that easy since we // cannot store const-ptrs in our map because we need to call non-const // methods of MIDI-port - it's a mess... MidiPort* p = const_cast<MidiPort *>( port ); snd_seq_event_t ev; snd_seq_ev_clear( &ev ); snd_seq_ev_set_source( &ev, ( m_portIDs[p][1] != -1 ) ? m_portIDs[p][1] : m_portIDs[p][0] ); snd_seq_ev_set_subs( &ev ); snd_seq_ev_schedule_tick( &ev, m_queueID, 1, static_cast<int>( time ) ); ev.queue = m_queueID; switch( event.type() ) { case MidiNoteOn: snd_seq_ev_set_noteon( &ev, event.channel(), event.key() + KeysPerOctave, event.velocity() ); break; case MidiNoteOff: snd_seq_ev_set_noteoff( &ev, event.channel(), event.key() + KeysPerOctave, event.velocity() ); break; case MidiKeyPressure: snd_seq_ev_set_keypress( &ev, event.channel(), event.key() + KeysPerOctave, event.velocity() ); break; case MidiControlChange: snd_seq_ev_set_controller( &ev, event.channel(), event.controllerNumber(), event.controllerValue() ); break; case MidiProgramChange: snd_seq_ev_set_pgmchange( &ev, event.channel(), event.program() ); break; case MidiChannelPressure: snd_seq_ev_set_chanpress( &ev, event.channel(), event.channelPressure() ); break; case MidiPitchBend: snd_seq_ev_set_pitchbend( &ev, event.channel(), event.param( 0 ) - 8192 ); break; default: qWarning( "MidiAlsaSeq: unhandled output event %d\n", (int) event.type() ); return; } m_seqMutex.lock(); snd_seq_event_output( m_seqHandle, &ev ); snd_seq_drain_output( m_seqHandle ); m_seqMutex.unlock(); }
void SendMidiCommand(int nIdPortOut, char *buf) { /* MIDI COMMANDS ------------------------------------------------------------------- name status param 1 param 2 ------------------------------------------------------------------- note off 0x80+C key # velocity note on 0x90+C key # velocity poly key pressure 0xA0+C key # pressure value control change 0xB0+C control # control value program change 0xC0+C program # -- mono key pressure 0xD0+C pressure value -- pitch bend 0xE0+C range (LSB) range (MSB) system 0xF0+C manufacturer model ------------------------------------------------------------------- C is the channel number, from 0 to 15; ------------------------------------------------------------------- source: http://ftp.ec.vanderbilt.edu/computermusic/musc216site/MIDI.Commands.html In this program the pitch bend range will be transmitter as one single 8-bit number. So the end result is that MIDI commands will be transmitted as 3 bytes, starting with the operation byte: buf[0] --> operation/channel buf[1] --> param1 buf[2] --> param2 (param2 not transmitted on program change or key press) snd_seq_event_t ev; snd_seq_ev_clear(&ev); snd_seq_ev_set_source(&ev, nIdPortOut); snd_seq_ev_set_subs(&ev); snd_seq_ev_set_direct(&ev); snd_seq_ev_set_noteoff(&ev, 0, note, 60); snd_seq_event_output(t_seq, &ev); */ snd_seq_event_t t_event; snd_seq_ev_clear(&t_event); // printf("Serial port: %u\n", nIdPortOut); snd_seq_ev_set_source(&t_event, nIdPortOutA); snd_seq_ev_set_subs(&t_event); snd_seq_ev_set_direct(&t_event); int operation, channel, param1, param2; operation = buf[0] & 0xF0; channel = buf[0] & 0x0F; param1 = buf[1]; param2 = buf[2]; switch (operation) { case 0x80: printf("OUT ==> 0x%x Note off 0x%x 0x%x 0x%x\n", operation, channel, param1, param2); snd_seq_ev_set_noteoff(&t_event, channel, param1, param2); break; case 0x90: printf("OUT ==> 0x%x Note on 0x%x 0x%x 0x%x\n", operation, channel, param1, param2); snd_seq_ev_set_noteon(&t_event, channel, param1, param2); break; case 0xA0: printf("OUT ==> 0x%x Pressure change 0x%x 0x%x 0x%x\n", operation, channel, param1, param2); snd_seq_ev_set_keypress(&t_event, channel, param1, param2); break; case 0xB0: printf("OUT ==> 0x%x Controller change 0x%x 0x%x 0x%x\n", operation, channel, param1, param2); snd_seq_ev_set_controller(&t_event, channel, param1, param2); break; case 0xC0: printf("OUT ==> 0x%x Program change 0x%x 0x%x 0x%x\n", operation, channel, param1); snd_seq_ev_set_pgmchange(&t_event, channel, param1); break; case 0xD0: printf("OUT ==> 0x%x Channel change 0x%x 0x%x 0x%x\n", operation, channel, param1); snd_seq_ev_set_chanpress(&t_event, channel, param1); break; case 0xE0: param1 = (param1 & 0x7F) + ((param2 & 0x7F) << 7); printf("OUT ==> 0x%x Pitch bend %03u %05i\n", operation, channel, param1); snd_seq_ev_set_pitchbend(&t_event, channel, param1 - 8192); // in alsa MIDI we want signed int break; /* Not implementing system commands (0xF0) */ default: printf("OUT 0x%x Unknown MIDI cmd %03u %03u %03u\n", operation, channel, param1, param2); break; } snd_seq_event_output_direct(t_seq, &t_event); //snd_seq_drain_output(t_seq); //snd_seq_event_output(t_seq, &t_event); }
void sys_alsa_putmidimess(int portno, int a, int b, int c) { if (portno >= 0 && portno < alsa_nmidiout) { snd_seq_event_t ev; snd_seq_ev_clear(&ev); int status = a & 0xf0; int channel = a & 0x0f; status = (status >= MIDI_SYSEX) ? status : (status & 0xf0); switch (status) { case MIDI_NOTEON: snd_seq_ev_set_noteon(&ev, channel, b, c); break; case MIDI_NOTEOFF: snd_seq_ev_set_noteoff(&ev, channel, b, c); break; case MIDI_POLYAFTERTOUCH: snd_seq_ev_set_chanpress(&ev, channel, b); break; case MIDI_CONTROLCHANGE: snd_seq_ev_set_controller(&ev, channel, b, c); break; case MIDI_PROGRAMCHANGE: snd_seq_ev_set_pgmchange(&ev, channel, b); break; case MIDI_AFTERTOUCH: snd_seq_ev_set_chanpress(&ev, channel, b); break; case MIDI_PITCHBEND: /* b and c are already correct but alsa needs to recalculate them */ snd_seq_ev_set_pitchbend(&ev, channel, (((c<<7)|b)-8192)); break; case MIDI_TIMECODE: ev.type = SND_SEQ_EVENT_QFRAME; snd_seq_ev_set_fixed(&ev); ev.data.raw8.d[0] = a & 0xff; /* status */ ev.data.raw8.d[1] = b & 0x7f; /* data */ break; case MIDI_SONGPOS: ev.type = SND_SEQ_EVENT_SONGPOS; snd_seq_ev_set_fixed(&ev); ev.data.raw8.d[0] = a & 0xff; /* status */ ev.data.raw8.d[1] = b & 0x7f; /* data */ ev.data.raw8.d[2] = c & 0x7f; /* data */ break; case MIDI_SONGSELECT: ev.type = SND_SEQ_EVENT_SONGSEL; snd_seq_ev_set_fixed(&ev); ev.data.raw8.d[0] = a & 0xff; /* status */ ev.data.raw8.d[1] = b & 0x7f; /* data */ break; default: bug("couldn't put alsa midi message"); break; } snd_seq_ev_set_direct(&ev); snd_seq_ev_set_subs(&ev); snd_seq_ev_set_source(&ev, alsa_midioutfd[portno]); snd_seq_event_output_direct(midi_handle, &ev); } //post("%d %d %d\n", a, b, c); }
/************************************************************************** * 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; }
/** main * */ int main ( int argc, char **argv ) { int keys = 0; int mc_offset = 0; snd_seq_event_t ev; int patch = 0; int bank = 0; fprintf( stderr, "lsmi-keyhack" " v" VERSION "\n" ); get_args( argc, argv ); fprintf( stderr, "Registering MIDI port...\n" ); seq = open_client( CLIENT_NAME ); if ( NULL == seq ) { fprintf( stderr, "Error opening alsa sequencer!\n" ); exit( 1 ); } if ( ( port = open_output_port( seq ) ) < 0 ) { fprintf( stderr, "Error opening MIDI output port!\n" ); exit( 1 ); } if ( sub_name ) { snd_seq_addr_t addr; if ( snd_seq_parse_address( seq, &addr, sub_name ) < 0 ) fprintf( stderr, "Couldn't parse address '%s'", sub_name ); else if ( snd_seq_connect_to( seq, port, addr.client, addr.port ) < 0 ) { fprintf( stderr, "Error creating subscription for port %i:%i", addr.client, addr.port ); exit( 1 ); } } fprintf( stderr, "Initializing keyboard...\n" ); if ( -1 == ( fd = open( device, O_RDWR ) ) ) { fprintf( stderr, "Error opening event interface! (%s)\n", strerror( errno ) ); exit( 1 ); } init_keyboard(); set_traps(); update_leds(); fprintf( stderr, "Opening database...\n" ); if ( database == defaultdatabase ) { char *home = getenv( "HOME" ); database = malloc( strlen( home ) + strlen( defaultdatabase ) + 2 ); sprintf( database, "%s/%s", home, defaultdatabase ); } if ( -1 == open_database( database ) ) { fprintf( stderr, "******Key database missing or invalid******\n" "Entering learning mode...\n" "Make sure your \"keyboard\" device is connected!\n" ); learn_mode(); } analyze_map( &keys, &mc_offset ); octave_min = ( mc_offset / 12 ) + 1; octave_max = 9 - ( ( keys - mc_offset ) / 12 ); fprintf( stderr, "%i keys, middle C is %ith from the left, lowest MIDI octave == %i, highest, %i\n", keys, mc_offset + 1, octave_min, octave_max ); fprintf( stderr, "Waiting for events...\n" ); for ( ;; ) { int keyi, newstate; keyi = get_keypress( &newstate ); snd_seq_ev_clear( &ev ); if ( map[keyi].control ) { snd_seq_event_t e; if ( newstate == UP ) continue; switch ( map[keyi].control ) { /* All notes off */ snd_seq_ev_set_controller( &ev, channel, 123, 0 ); send_event( &ev ); snd_seq_ev_clear( &ev ); case CKEY_EXIT: fprintf( stderr, "Exiting...\n" ); if ( close_database( database ) < 0 ) fprintf( stderr, "Error saving database!\n" ); clean_up(); exit( 0 ); case CKEY_MODE: prog_mode = prog_mode + 1 > NUM_PROG_MODES - 1 ? 0 : prog_mode + 1; fprintf( stderr, "Input mode change to %s\n", mode_names[prog_mode] ); update_leds(); break; case CKEY_OCTAVE_DOWN: octave = min( octave - 1, octave_min ); break; case CKEY_OCTAVE_UP: octave = max( octave + 1, octave_max ); break; case CKEY_CHANNEL_DOWN: channel = min( channel - 1, 0 ); break; case CKEY_CHANNEL_UP: channel = max( channel + 1, 15 ); break; case CKEY_PATCH_DOWN: if ( patch == 0 && bank > 0 ) { bank = min( bank - 1, 0 ); patch = 127; snd_seq_ev_set_controller( &e, channel, 0, bank ); send_event( &e ); } else patch = min( patch - 1, 0 ); snd_seq_ev_set_pgmchange( &ev, channel, patch ); break; case CKEY_PATCH_UP: if ( patch == 127 && bank < 127 ) { bank = max( bank + 1, 127 ); patch = 0; snd_seq_ev_set_controller( &e, channel, 0, bank ); send_event( &e ); } else patch = max( patch + 1, 127 ); snd_seq_ev_set_pgmchange( &ev, channel, patch ); break; case CKEY_NUMERIC: { struct timeval tv; gettimeofday( &tv, NULL ); /* Timeout in 5 secs */ if ( tv.tv_sec - timeout.tv_sec >= 5 ) { prog_index = 0; } timeout = tv; if ( prog_index == 0 ) printf( "INPUT %s #: ", mode_names[prog_mode] ); } prog_buf[prog_index++] = 48 + map[keyi].number; printf( "%i", map[keyi].number ); fflush( stdout ); if ( prog_index == 2 && prog_mode == CHANNEL ) { /* FIXME: all notes off->channel */ prog_buf[++prog_index] = '\0'; channel = atoi( prog_buf ); channel = max( channel, 15 ); prog_index = 0; printf( " ENTER\n" ); } else if ( prog_index == 3 ) { prog_buf[++prog_index] = '\0'; switch ( prog_mode ) { case PATCH: patch = atoi( prog_buf ); patch = max( patch, 127 ); snd_seq_ev_set_pgmchange( &ev, channel, patch ); break; case BANK: bank = atoi( prog_buf ); bank = max( bank, 127 ); snd_seq_ev_set_controller( &ev, channel, 0, bank ); break; default: fprintf( stderr, "Internal error!\n" ); } prog_index = 0; printf( " ENTER\n" ); } break; default: fprintf( stderr, "Internal error!\n" ); } send_event( &ev ); continue; } else switch ( map[keyi].ev_type ) { case SND_SEQ_EVENT_CONTROLLER: snd_seq_ev_set_controller( &ev, channel, map[keyi].number, newstate == DOWN ? 127 : 0 ); break; case SND_SEQ_EVENT_NOTE: if ( newstate == DOWN ) snd_seq_ev_set_noteon( &ev, channel, map[keyi].number + ( 12 * octave ), 64 ); else snd_seq_ev_set_noteoff( &ev, channel, map[keyi].number + ( 12 * octave ), 64 ); break; default: fprintf( stderr, "Key has invalid mapping!\n" ); break; } send_event( &ev ); } }