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 InstrumentTrack::updatePitch() { updateBaseNote(); processOutEvent( midiEvent( MidiPitchBend, midiPort()->realOutputChannel(), midiPitch() ), 0 ); }
void MidiAlsaDevice::writeRouting(int level, Xml& xml) const { // If this device is not actually in use by the song, do not write any routes. // This prevents bogus routes from being saved and propagated in the los file. if (midiPort() == -1) return; QString s; for (ciRoute r = _outRoutes.begin(); r != _outRoutes.end(); ++r) { if (!r->name().isEmpty()) { s = QT_TRANSLATE_NOOP("@default", "Route"); if (r->channel != -1) s += QString(QT_TRANSLATE_NOOP("@default", " channel=\"%1\"")).arg(r->channel); xml.tag(level++, s.toLatin1().constData()); xml.tag(level, "source devtype=\"%d\" name=\"%s\"/", MidiDevice::ALSA_MIDI, Xml::xmlString(name()).toLatin1().constData()); s = QT_TRANSLATE_NOOP("@default", "dest"); if (r->type == Route::MIDI_DEVICE_ROUTE) s += QString(QT_TRANSLATE_NOOP("@default", " devtype=\"%1\"")).arg(r->device->deviceType()); else if (r->type != Route::TRACK_ROUTE) s += QString(QT_TRANSLATE_NOOP("@default", " type=\"%1\"")).arg(r->type); else if(r->type == Route::TRACK_ROUTE) s += QString(QT_TRANSLATE_NOOP("@default", " trackId=\"%1\"")).arg(r->track->id()); s += QString(QT_TRANSLATE_NOOP("@default", " name=\"%1\"/")).arg(Xml::xmlString(r->name())); xml.tag(level, s.toLatin1().constData()); xml.etag(--level, "Route"); } } }
void MidiDevice::midiClockInput(unsigned int frame) { // Put a midi clock record event into the clock history fifo. Ignore port and channel. // Timestamp with the current frame. const ExtMidiClock ext_clk = MusEGlobal::midiSyncContainer.midiClockInput(midiPort(), frame); if(ext_clk.isValid() && extClockHistory()) extClockHistory()->put(ext_clk); }
void InstrumentTrack::processOutEvent( const midiEvent & _me, const midiTime & _time ) { int k; switch( _me.m_type ) { case MidiNoteOn: if( !configManager::inst()->value( "ui", "manualchannelpiano" ).toInt() ) { m_piano.setKeyState( _me.key(), true ); } if( !configManager::inst()->value( "ui", "disablechannelactivityindicators" ).toInt() ) { if( m_notes[_me.key()] == NULL ) { emit newNote(); } } k = masterKey( _me.key() ); if( k >= 0 && k < NumKeys ) { if( m_runningMidiNotes[k] > 0 ) { m_instrument->handleMidiEvent( midiEvent( MidiNoteOff, midiPort()->realOutputChannel(), k, 0 ), _time ); } ++m_runningMidiNotes[k]; m_instrument->handleMidiEvent( midiEvent( MidiNoteOn, midiPort()->realOutputChannel(), k, _me.velocity() ), _time ); } break; case MidiNoteOff: if( !configManager::inst()->value( "ui", "manualchannelpiano" ).toInt() ) { m_piano.setKeyState( _me.key(), false ); } k = masterKey( _me.key() ); if( k >= 0 && k < NumKeys && --m_runningMidiNotes[k] <= 0 ) { m_runningMidiNotes[k] = qMax( 0, m_runningMidiNotes[k] ); m_instrument->handleMidiEvent( midiEvent( MidiNoteOff, midiPort()->realOutputChannel(), k, 0 ), _time ); } break; default: if( m_instrument != NULL ) { m_instrument->handleMidiEvent( applyMasterKey( _me ), _time ); } break; } // if appropriate, midi-port does futher routing m_midiPort.processOutEvent( _me, _time ); }
void InstrumentTrack::processInEvent( const MidiEvent& event, const MidiTime& time, f_cnt_t offset ) { bool eventHandled = false; switch( event.type() ) { // we don't send MidiNoteOn, MidiNoteOff and MidiKeyPressure // events to instrument as NotePlayHandle will send them on its // own case MidiNoteOn: if( event.velocity() > 0 ) { NotePlayHandle* nph; m_notesMutex.lock(); if( m_notes[event.key()] == NULL ) { nph = NotePlayHandleManager::acquire( this, offset, typeInfo<f_cnt_t>::max() / 2, Note( MidiTime(), MidiTime(), event.key(), event.volume( midiPort()->baseVelocity() ) ), NULL, event.channel(), NotePlayHandle::OriginMidiInput ); m_notes[event.key()] = nph; if( ! Engine::mixer()->addPlayHandle( nph ) ) { m_notes[event.key()] = NULL; } } m_notesMutex.unlock(); eventHandled = true; break; } case MidiNoteOff: m_notesMutex.lock(); if( m_notes[event.key()] != NULL ) { // do actual note off and remove internal reference to NotePlayHandle (which itself will // be deleted later automatically) m_notes[event.key()]->noteOff( offset ); m_notes[event.key()] = NULL; } m_notesMutex.unlock(); eventHandled = true; break; case MidiKeyPressure: if( m_notes[event.key()] != NULL ) { // setVolume() calls processOutEvent() with MidiKeyPressure so the // attached instrument will receive the event as well m_notes[event.key()]->setVolume( event.volume( midiPort()->baseVelocity() ) ); } eventHandled = true; break; case MidiPitchBend: // updatePitch() is connected to m_pitchModel::dataChanged() which will send out // MidiPitchBend events m_pitchModel.setValue( m_pitchModel.minValue() + event.pitchBend() * m_pitchModel.range() / MidiMaxPitchBend ); break; case MidiControlChange: if( event.controllerNumber() == MidiControllerSustain ) { if( event.controllerValue() > MidiMaxControllerValue/2 ) { m_sustainPedalPressed = true; } else { m_sustainPedalPressed = false; } } if( event.controllerNumber() == MidiControllerAllSoundOff || event.controllerNumber() == MidiControllerAllNotesOff || event.controllerNumber() == MidiControllerOmniOn || event.controllerNumber() == MidiControllerOmniOff || event.controllerNumber() == MidiControllerMonoOn || event.controllerNumber() == MidiControllerPolyOn ) { silenceAllNotes(); } break; case MidiMetaEvent: // handle special cases such as note panning switch( event.metaEvent() ) { case MidiNotePanning: if( m_notes[event.key()] != NULL ) { eventHandled = true; m_notes[event.key()]->setPanning( event.panning() ); } break; default: qWarning( "InstrumentTrack: unhandled MIDI meta event: %i", event.metaEvent() ); break; } break; default: break; } if( eventHandled == false && instrument()->handleMidiEvent( event, time, offset ) == false ) { qWarning( "InstrumentTrack: unhandled MIDI event %d", event.type() ); } }
PassRefPtr<MIDIPort> MIDIPort::create(ScriptExecutionContext* context, const String& id, const String& manufacturer, const String& name, MIDIPortTypeCode type, const String& version) { RefPtr<MIDIPort> midiPort(adoptRef(new MIDIPort(context, id, manufacturer, name, type, version))); midiPort->suspendIfNeeded(); return midiPort.release(); }