/*! \brief Handle a mouse move event on the piano display view * * This handles the user dragging the mouse across the keys. It uses * code from mousePressEvent() and mouseReleaseEvent(), also correcting * for if the mouse movement has stayed within one key and if the mouse * has moved outside the vertical area of the keyboard (which is still * allowed but won't make the volume go up to 11). * * \param _me the ContextMenuEvent to handle. * \todo Paul Wayper thinks that this code should be refactored to * reduce or remove the duplication between this, the mousePressEvent() * and mouseReleaseEvent() methods. */ void PianoView::mouseMoveEvent( QMouseEvent * _me ) { if( m_piano == NULL ) { return; } int key_num = getKeyFromMouse( _me->pos() ); int y_diff = _me->pos().y() - PIANO_BASE; int velocity = (int)( (float) y_diff / ( Piano::isWhiteKey( key_num ) ? PW_WHITE_KEY_HEIGHT : PW_BLACK_KEY_HEIGHT ) * (float) m_piano->instrumentTrack()->midiPort()->baseVelocity() ); // maybe the user moved the mouse-cursor above or under the // piano-widget while holding left button so check that and // correct volume if necessary if( y_diff < 0 ) { velocity = 0; } else if( y_diff > ( Piano::isWhiteKey( key_num ) ? PW_WHITE_KEY_HEIGHT : PW_BLACK_KEY_HEIGHT ) ) { velocity = m_piano->instrumentTrack()->midiPort()->baseVelocity(); } // is the calculated key different from current key? (could be the // user just moved the cursor one pixel left but on the same key) if( key_num != m_lastKey ) { if( m_lastKey != -1 ) { m_piano->midiEventProcessor()->processInEvent( MidiEvent( MidiNoteOff, -1, m_lastKey, 0 ) ); m_piano->setKeyState( m_lastKey, false ); m_lastKey = -1; } if( _me->buttons() & Qt::LeftButton ) { if( _me->pos().y() > PIANO_BASE ) { m_piano->midiEventProcessor()->processInEvent( MidiEvent( MidiNoteOn, -1, key_num, velocity ) ); m_piano->setKeyState( key_num, true ); m_lastKey = key_num; } else { m_piano->instrumentTrack()->baseNoteModel()->setInitValue( (float) key_num ); } } // and let the user see that he pressed a key... :) update(); } else if( m_piano->isKeyPressed( key_num ) ) { m_piano->midiEventProcessor()->processInEvent( MidiEvent( MidiKeyPressure, -1, key_num, velocity ) ); } }
void InstrumentTrack::updatePitchRange() { const int r = m_pitchRangeModel.value(); m_pitchModel.setRange( MinPitchDefault * r, MaxPitchDefault * r ); processOutEvent( MidiEvent( MidiControlChange, midiPort()->realOutputChannel(), MidiControllerRegisteredParameterNumberLSB, MidiPitchBendSensitivityRPN & 0x7F ) ); processOutEvent( MidiEvent( MidiControlChange, midiPort()->realOutputChannel(), MidiControllerRegisteredParameterNumberMSB, ( MidiPitchBendSensitivityRPN >> 8 ) & 0x7F ) ); processOutEvent( MidiEvent( MidiControlChange, midiPort()->realOutputChannel(), MidiControllerDataEntry, midiPitchRange() ) ); }
void InstrumentTrack::processOutEvent( const MidiEvent& event, const MidiTime& time, f_cnt_t offset ) { // do nothing if we do not have an instrument instance (e.g. when loading settings) if( m_instrument == NULL ) { return; } const MidiEvent transposedEvent = applyMasterKey( event ); const int key = transposedEvent.key(); switch( event.type() ) { case MidiNoteOn: m_midiNotesMutex.lock(); m_piano.setKeyState( event.key(), true ); // event.key() = original key if( key >= 0 && key < NumKeys ) { if( m_runningMidiNotes[key] > 0 ) { m_instrument->handleMidiEvent( MidiEvent( MidiNoteOff, midiPort()->realOutputChannel(), key, 0 ), time, offset ); } ++m_runningMidiNotes[key]; m_instrument->handleMidiEvent( MidiEvent( MidiNoteOn, midiPort()->realOutputChannel(), key, event.velocity() ), time, offset ); } m_midiNotesMutex.unlock(); emit newNote(); break; case MidiNoteOff: m_midiNotesMutex.lock(); m_piano.setKeyState( event.key(), false ); // event.key() = original key if( key >= 0 && key < NumKeys && --m_runningMidiNotes[key] <= 0 ) { m_instrument->handleMidiEvent( MidiEvent( MidiNoteOff, midiPort()->realOutputChannel(), key, 0 ), time, offset ); } m_midiNotesMutex.unlock(); break; default: m_instrument->handleMidiEvent( transposedEvent, time, offset ); break; } // if appropriate, midi-port does futher routing m_midiPort.processOutEvent( event, time ); }
void NotePlayHandle::noteOff( const f_cnt_t _s ) { if( m_released ) { return; } // first note-off all sub-notes for( NotePlayHandleList::Iterator it = m_subNotes.begin(); it != m_subNotes.end(); ++it ) { ( *it )->noteOff( _s ); } // then set some variables indicating release-state m_framesBeforeRelease = _s; m_releaseFramesToDo = qMax<f_cnt_t>( 0, actualReleaseFramesToDo() ); if( hasParent() || ! m_instrumentTrack->isArpeggioEnabled() ) { // send MidiNoteOff event m_instrumentTrack->processOutEvent( MidiEvent( MidiNoteOff, midiChannel(), midiKey(), 0 ), MidiTime::fromFrames( _s, engine::framesPerTick() ), _s ); } // inform attached components about MIDI finished (used for recording in Piano Roll) if( m_origin == OriginMidiInput ) { setLength( MidiTime( static_cast<f_cnt_t>( totalFramesPlayed() / engine::framesPerTick() ) ) ); m_instrumentTrack->midiNoteOff( *this ); } m_released = true; }
void sfxrInstrumentView::previewSound() { sfxrInstrument* s = castModel<sfxrInstrument>(); InstrumentTrack* it = s->instrumentTrack(); it->silenceAllNotes(); it->processInEvent( MidiEvent( MidiNoteOn, 0, it->baseNoteModel()->value(), MidiDefaultVelocity ) ); }
/*! \brief Handle the focus leaving the piano display view * * Turn off all notes if we lose focus. * * \todo Is there supposed to be a parameter given here? */ void PianoView::focusOutEvent( QFocusEvent * ) { if( m_piano == NULL ) { return; } // focus just switched to another control inside the instrument track // window we live in? if( parentWidget()->parentWidget()->focusWidget() != this && parentWidget()->parentWidget()->focusWidget() != NULL && !parentWidget()->parentWidget()-> focusWidget()->inherits( "QLineEdit" ) ) { // then reclaim keyboard focus! setFocus(); return; } // if we loose focus, we HAVE to note off all running notes because // we don't receive key-release-events anymore and so the notes would // hang otherwise for( int i = 0; i < NumKeys; ++i ) { m_piano->midiEventProcessor()->processInEvent( MidiEvent( MidiNoteOff, -1, i, 0 ) ); m_piano->setKeyState( i, false ); } update(); }
void NotePlayHandle::setVolume( volume_t _volume ) { note::setVolume( _volume ); const int baseVelocity = m_instrumentTrack->midiPort()->baseVelocity(); m_instrumentTrack->processOutEvent( MidiEvent( MidiKeyPressure, midiChannel(), midiKey(), midiVelocity( baseVelocity ) ) ); }
/*! \brief Handle a note being released on our keyboard display * * \param key the key being releassed */ void Piano::handleKeyRelease( int key ) { if( isValidKey( key ) ) { m_midiEvProc->processInEvent( MidiEvent( MidiNoteOff, -1, key, 0 ) ); m_pressedKeys[key] = false; } }
void MidiWinMM::handleInputEvent( HMIDIIN hm, DWORD ev ) { const int cmd = ev & 0xff; if( cmd == MidiActiveSensing ) { return; } const int par1 = ( ev >> 8 ) & 0xff; const int par2 = ev >> 16; const MidiEventTypes cmdtype = static_cast<MidiEventTypes>( cmd & 0xf0 ); const int chan = cmd & 0x0f; const QString d = m_inputDevices.value( hm ); if( d.isEmpty() || !m_inputSubs.contains( d ) ) { return; } const MidiPortList & l = m_inputSubs[d]; for( MidiPortList::ConstIterator it = l.begin(); it != l.end(); ++it ) { switch( cmdtype ) { case MidiNoteOn: case MidiNoteOff: case MidiKeyPressure: ( *it )->processInEvent( MidiEvent( cmdtype, chan, par1 - KeysPerOctave, par2 & 0xff, &hm ) ); break; case MidiControlChange: case MidiProgramChange: case MidiChannelPressure: ( *it )->processInEvent( MidiEvent( cmdtype, chan, par1, par2 & 0xff, &hm ) ); break; case MidiPitchBend: ( *it )->processInEvent( MidiEvent( cmdtype, chan, par1 + par2*128, 0, &hm ) ); break; default: qWarning( "MidiWinMM: unhandled input event %d\n", cmdtype ); break; } } }
void VestigeInstrumentView::noteOffAll( void ) { m_vi->m_pluginMutex.lock(); if( m_vi->m_plugin != NULL ) { for( int key = 0; key <= MidiMaxKey; ++key ) { m_vi->m_plugin->processMidiEvent( MidiEvent( MidiNoteOff, 0, key, 0 ), 0 ); } } m_vi->m_pluginMutex.unlock(); }
/*! \brief Handle a note being pressed on our keyboard display * * \param key the key being pressed */ void Piano::handleKeyPress( int key, int midiVelocity ) { if( midiVelocity == -1 ) { midiVelocity = m_instrumentTrack->midiPort()->baseVelocity(); } if( isValidKey( key ) ) { m_midiEvProc->processInEvent( MidiEvent( MidiNoteOn, -1, key, midiVelocity ) ); m_pressedKeys[key] = true; } }
/*! \brief Handle a mouse click on this piano display view * * We first determine the key number using the getKeyFromMouse() method. * * If we're below the 'root key selection' area, * we set the volume of the note to be proportional to the vertical * position on the keyboard - lower down the key is louder, within the * boundaries of the (white or black) key pressed. We then tell the * instrument to play that note, scaling for MIDI max loudness = 127. * * If we're in the 'root key selection' area, of course, we set the * root key to be that key. * * We finally update ourselves to show the key press * * \param _me the mouse click to handle. */ void PianoView::mousePressEvent( QMouseEvent * _me ) { if( _me->button() == Qt::LeftButton && m_piano != NULL ) { // get pressed key int key_num = getKeyFromMouse( _me->pos() ); if( _me->pos().y() > PIANO_BASE ) { int y_diff = _me->pos().y() - PIANO_BASE; int velocity = (int)( ( float ) y_diff / ( Piano::isWhiteKey( key_num ) ? PW_WHITE_KEY_HEIGHT : PW_BLACK_KEY_HEIGHT ) * (float) m_piano->instrumentTrack()->midiPort()->baseVelocity() ); if( y_diff < 0 ) { velocity = 0; } else if( y_diff > ( Piano::isWhiteKey( key_num ) ? PW_WHITE_KEY_HEIGHT : PW_BLACK_KEY_HEIGHT ) ) { velocity = m_piano->instrumentTrack()->midiPort()->baseVelocity(); } // set note on m_piano->midiEventProcessor()->processInEvent( MidiEvent( MidiNoteOn, -1, key_num, velocity ) ); m_piano->setKeyState( key_num, true ); m_lastKey = key_num; emit keyPressed( key_num ); } else { if( _me->modifiers() & Qt::ControlModifier ) { new StringPairDrag( "automatable_model", QString::number( m_piano->instrumentTrack()->baseNoteModel()->id() ), QPixmap(), this ); _me->accept(); } else { m_piano->instrumentTrack()->baseNoteModel()->setInitValue( (float) key_num ); emit baseNoteChanged(); } } // and let the user see that he pressed a key... :) update(); } }
/*! \brief Handle a mouse release event on the piano display view * * If a key was pressed by the in the mousePressEvent() function, we * turn the note off. * * \param _me the mousePressEvent to handle. */ void PianoView::mouseReleaseEvent( QMouseEvent * ) { if( m_lastKey != -1 ) { if( m_piano != NULL ) { m_piano->midiEventProcessor()->processInEvent( MidiEvent( MidiNoteOff, -1, m_lastKey, 0 ) ); m_piano->setKeyState( m_lastKey, false ); } // and let the user see that he released a key... :) update(); m_lastKey = -1; } }
MidiEvent MidiBuffer::readEvent(int index, bool *ok) { if(!isValid()) { if(ok) { (*ok) = false; } return MidiEvent(); } MidiEvent midiEvent; bool success = (jack_midi_event_get( &midiEvent, _jackBuffer, index) == 0); if(ok) { (*ok) = success; } return midiEvent; }
void MidiPort::updateOutputProgram() { processOutEvent( MidiEvent( MidiProgramChange, realOutputChannel(), outputProgram()-1 ) ); }
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); } }
void InstrumentTrack::updatePitch() { updateBaseNote(); processOutEvent( MidiEvent( MidiPitchBend, midiPort()->realOutputChannel(), midiPitch() ) ); }
void InstrumentTrackView::activityIndicatorReleased() { model()->processInEvent( MidiEvent( MidiNoteOff, 0, DefaultKey, 0 ) ); }
void InstrumentTrackView::activityIndicatorPressed() { model()->processInEvent( MidiEvent( MidiNoteOn, 0, DefaultKey, MidiDefaultVelocity ) ); }
int main(int argc, char* argv[]) { int c; while ((c = getopt(argc, argv, "vdD:r")) != EOF) { switch (c) { case 'v': printVersion(); return 0; case 'd': debugMode = true; break; default: usage(); return -1; } } QIODevice* in = 0; QIODevice* out = 0; switch (argc - optind) { case 2: out = new QFile(argv[1 + optind]); if (!out->open(QIODevice::WriteOnly)) { printf("cannot open output file <%s>: %s\n", argv[optind+1], strerror(errno)); return -3; } case 1: in = new QFile(argv[optind]); if (!in->open(QIODevice::ReadOnly)) { printf("cannot open input file <%s>: %s\n", argv[optind], strerror(errno)); return -4; } break; case 0: break; default: usage(); return -2; break; } if (in == 0) { in = new QFile; ((QFile*)in)->open(stdin, QIODevice::ReadOnly); } if (out == 0) { out = new QFile; ((QFile*)out)->open(stdout, QIODevice::WriteOnly); } MidiFile mf; mf.setFormat(1); XmlReader e(in); while (e.readNextStartElement()) { const QStringRef& tag(e.name()); if (tag == "SMF") { while (e.readNextStartElement()) { const QStringRef& tag(e.name()); if (tag == "Track") { MidiTrack* track = new MidiTrack(&mf); while (e.readNextStartElement()) { const QStringRef& tag(e.name()); if (tag == "NoteOff") { MidiEventType t = MidiEventType::NOTEOFF; int tick = e.intAttribute("tick"); uchar c = e.intAttribute("c"); uchar a = e.intAttribute("a", 0, 16); uchar b = e.intAttribute("b", 0, 16); track->events().insert(std::pair<int,MidiEvent>(tick, MidiEvent(t, c, a, b))); e.skipCurrentElement(); } else if (tag == "NoteOn") { MidiEventType t = MidiEventType::NOTEON; int tick = e.intAttribute("tick"); uchar c = e.intAttribute("c"); uchar a = e.intAttribute("a", 0, 16); uchar b = e.intAttribute("b", 0, 16); track->events().insert(std::pair<int,MidiEvent>(tick, MidiEvent(t, c, a, b))); e.skipCurrentElement(); } else if (tag == "Ctrl") { MidiEventType t = MidiEventType::CONTROLLER; int tick = e.intAttribute("tick"); uchar c = e.intAttribute("c"); uchar a = e.intAttribute("a", 0, 16); uchar b = e.intAttribute("b", 0, 16); track->events().insert(std::pair<int,MidiEvent>(tick, MidiEvent(t, c, a, b))); e.skipCurrentElement(); } else if (tag == "Program") { MidiEventType t = MidiEventType::PROGRAM; int tick = e.intAttribute("tick"); uchar c = e.intAttribute("c"); uchar a = e.intAttribute("a", 0, 16); track->events().insert(std::pair<int,MidiEvent>(tick, MidiEvent(t, c, a, 0))); e.skipCurrentElement(); } else if (tag == "Event") { uchar t = e.intAttribute("t"); int tick = e.intAttribute("tick"); uchar c = e.intAttribute("c"); uchar a = e.intAttribute("a", 0, 16); uchar b = e.intAttribute("b", 0, 16); track->events().insert(std::pair<int,MidiEvent>(tick, MidiEvent(MidiEventType(t), c, a, b))); e.skipCurrentElement(); } else e.unknown(); } mf.tracks().push_back(track); } else if (tag == "division") mf.setDivision(e.readInt()); else if (tag == "format") mf.setFormat(e.readInt()); else e.unknown(); } } else e.unknown(); } mf.write(out); delete out; delete in; return 0; }
NotePlayHandle::NotePlayHandle( InstrumentTrack* instrumentTrack, const f_cnt_t _offset, const f_cnt_t _frames, const note& n, NotePlayHandle *parent, int midiEventChannel, Origin origin ) : PlayHandle( TypeNotePlayHandle, _offset ), note( n.length(), n.pos(), n.key(), n.getVolume(), n.getPanning(), n.detuning() ), m_pluginData( NULL ), m_filter( NULL ), m_instrumentTrack( instrumentTrack ), m_frames( 0 ), m_totalFramesPlayed( 0 ), m_framesBeforeRelease( 0 ), m_releaseFramesToDo( 0 ), m_releaseFramesDone( 0 ), m_released( false ), m_hasParent( parent != NULL ), m_hadChildren( false ), m_muted( false ), m_bbTrack( NULL ), m_origTempo( engine::getSong()->getTempo() ), m_origBaseNote( instrumentTrack->baseNote() ), m_frequency( 0 ), m_unpitchedFrequency( 0 ), m_baseDetuning( NULL ), m_songGlobalParentOffset( 0 ), m_midiChannel( midiEventChannel >= 0 ? midiEventChannel : instrumentTrack->midiPort()->realOutputChannel() ), m_origin( origin ) { if( hasParent() == false ) { m_baseDetuning = new BaseDetuning( detuning() ); m_instrumentTrack->m_processHandles.push_back( this ); } else { m_baseDetuning = parent->m_baseDetuning; parent->m_subNotes.push_back( this ); parent->m_hadChildren = true; m_bbTrack = parent->m_bbTrack; } updateFrequency(); setFrames( _frames ); // inform attached components about new MIDI note (used for recording in Piano Roll) if( m_origin == OriginMidiInput ) { m_instrumentTrack->midiNoteOn( *this ); } if( hasParent() || ! m_instrumentTrack->isArpeggioEnabled() ) { const int baseVelocity = m_instrumentTrack->midiPort()->baseVelocity(); // send MidiNoteOn event m_instrumentTrack->processOutEvent( MidiEvent( MidiNoteOn, midiChannel(), midiKey(), midiVelocity( baseVelocity ) ), MidiTime::fromFrames( offset(), engine::framesPerTick() ), offset() ); } }
void ZynAddSubFxInstrument::sendControlChange( MidiControllers midiCtl, float value ) { handleMidiEvent( MidiEvent( MidiControlChange, instrumentTrack()->midiPort()->realOutputChannel(), midiCtl, (int) value, this ) ); }
void MidiAlsaSeq::run() { // watch the pipe and sequencer input events int pollfd_count = snd_seq_poll_descriptors_count( m_seqHandle, POLLIN ); struct pollfd * pollfd_set = new struct pollfd[pollfd_count + 1]; snd_seq_poll_descriptors( m_seqHandle, pollfd_set + 1, pollfd_count, POLLIN ); pollfd_set[0].fd = m_pipe[0]; pollfd_set[0].events = POLLIN; ++pollfd_count; while( m_quit == false ) { int pollRet = poll( pollfd_set, pollfd_count, EventPollTimeOut ); if( pollRet == 0 ) { continue; } else if( pollRet == -1 ) { // gdb may interrupt the poll if( errno == EINTR ) { continue; } qCritical( "error while polling ALSA sequencer handle" ); break; } // shutdown? if( m_quit ) { break; } m_seqMutex.lock(); // while event queue is not empty while( snd_seq_event_input_pending( m_seqHandle, true ) > 0 ) { snd_seq_event_t * ev; if( snd_seq_event_input( m_seqHandle, &ev ) < 0 ) { m_seqMutex.unlock(); qCritical( "error while fetching MIDI event from sequencer" ); break; } m_seqMutex.unlock(); snd_seq_addr_t * source = NULL; MidiPort * dest = NULL; for( int i = 0; i < m_portIDs.size(); ++i ) { if( m_portIDs.values()[i][0] == ev->dest.port ) { dest = m_portIDs.keys()[i]; } if( ( m_portIDs.values()[i][1] != -1 && m_portIDs.values()[i][1] == ev->source.port ) || m_portIDs.values()[i][0] == ev->source.port ) { source = &ev->source; } } if( dest == NULL ) { continue; } switch( ev->type ) { case SND_SEQ_EVENT_NOTEON: dest->processInEvent( MidiEvent( MidiNoteOn, ev->data.note.channel, ev->data.note.note - KeysPerOctave, ev->data.note.velocity, source ), MidiTime( ev->time.tick ) ); break; case SND_SEQ_EVENT_NOTEOFF: dest->processInEvent( MidiEvent( MidiNoteOff, ev->data.note.channel, ev->data.note.note - KeysPerOctave, ev->data.note.velocity, source ), MidiTime( ev->time.tick) ); break; case SND_SEQ_EVENT_KEYPRESS: dest->processInEvent( MidiEvent( MidiKeyPressure, ev->data.note.channel, ev->data.note.note - KeysPerOctave, ev->data.note.velocity, source ), MidiTime() ); break; case SND_SEQ_EVENT_CONTROLLER: dest->processInEvent( MidiEvent( MidiControlChange, ev->data.control.channel, ev->data.control.param, ev->data.control.value, source ), MidiTime() ); break; case SND_SEQ_EVENT_PGMCHANGE: dest->processInEvent( MidiEvent( MidiProgramChange, ev->data.control.channel, ev->data.control.param, ev->data.control.value, source ), MidiTime() ); break; case SND_SEQ_EVENT_CHANPRESS: dest->processInEvent( MidiEvent( MidiChannelPressure, ev->data.control.channel, ev->data.control.param, ev->data.control.value, source ), MidiTime() ); break; case SND_SEQ_EVENT_PITCHBEND: dest->processInEvent( MidiEvent( MidiPitchBend, ev->data.control.channel, ev->data.control.value + 8192, 0, source ), MidiTime() ); break; case SND_SEQ_EVENT_SENSING: case SND_SEQ_EVENT_CLOCK: break; default: fprintf( stderr, "ALSA-sequencer: unhandled input " "event %d\n", ev->type ); break; } // end switch m_seqMutex.lock(); } // end while m_seqMutex.unlock(); } delete[] pollfd_set; }