//----------------------------------------------------------------------------------------- VstInt32 VstXSynth::processEvents (VstEvents* ev) { for (VstInt32 i = 0; i < ev->numEvents; i++) { if ((ev->events[i])->type != kVstMidiType) continue; VstMidiEvent* event = (VstMidiEvent*)ev->events[i]; char* midiData = event->midiData; VstInt32 status = midiData[0] & 0xf0; // ignoring channel if (status == 0x90 || status == 0x80) // we only look at notes { VstInt32 note = midiData[1] & 0x7f; VstInt32 velocity = midiData[2] & 0x7f; if (status == 0x80) velocity = 0; // note off by velocity 0 if (!velocity && (note == currentNote)) noteOff (); else noteOn (note, velocity, event->deltaFrames); } else if (status == 0xb0) { if (midiData[1] == 0x7e || midiData[1] == 0x7b) // all notes off noteOff (); } event++; } return 1; }
void MIDIReceiver::advance() { while (!mMidiQueue.Empty()) { IMidiMsg* midiMessage = mMidiQueue.Peek(); if (midiMessage->mOffset > mOffset) break; IMidiMsg::EStatusMsg status = midiMessage->StatusMsg(); int noteNumber = midiMessage->NoteNumber(); int velocity = midiMessage->Velocity(); // There are only note on/off messages in the queue, see ::OnMessageReceived if (status == IMidiMsg::kNoteOn && velocity) { if (mKeyStatus[noteNumber] == false) { mKeyStatus[noteNumber] = true; mNumKeys += 1; noteOn(noteNumber, velocity); } } else { if (mKeyStatus[noteNumber] == true) { mKeyStatus[noteNumber] = false; mNumKeys -= 1; noteOff(noteNumber, velocity); } } mMidiQueue.Remove(); } mOffset++; }
NotePlayHandle::~NotePlayHandle() { noteOff( 0 ); if( hasParent() == false ) { delete m_baseDetuning; m_instrumentTrack->m_processHandles.removeAll( this ); } if( m_pluginData != NULL ) { m_instrumentTrack->deleteNotePluginData( this ); } if( m_instrumentTrack->m_notes[key()] == this ) { m_instrumentTrack->m_notes[key()] = NULL; } for( NotePlayHandleList::Iterator it = m_subNotes.begin(); it != m_subNotes.end(); ++it ) { delete *it; } m_subNotes.clear(); delete m_filter; }
// Functions for handling midi events and meta events void handleNoteOff(uint32_t tics, int channel, int note, int velocity) { logger(LOG_INFO, "Note Off at: %d for Channel: %d, Note: %d, Velocity: %d\n", tics, channel, note, velocity); waitForTicCount(tics); noteOff(channel, note); }
void MidiReader::onMidiMessage(double deltaTime, std::vector<unsigned char> *message) { size_t bytesCount = message->size(); if (bytesCount == 1 && message->at(0) == 254) return; // Skip 'Active sense' bytes for (size_t i = 0; i < bytesCount; ++i) qdbg << "Byte " << i << " = " << (int)message->at(i) << ", "; if (bytesCount > 0) qdbg << "stamp = " << deltaTime << endl; if (bytesCount >= 3) { quint8 byte1 = (*message)[0]; int channel = byte1 & 0b1111; int cmd = byte1 >> 4; qdbg << "[Channel " << channel << "] "; if (cmd == 0b1000) { // Note Off int key = (*message)[1]; int velocity = (*message)[2]; qdbg << "Note off: key=" << key << ", velocity=" << velocity; emit noteOff(key, velocity); } else if (cmd == 0b1001) { // Note On int key = (*message)[1]; int velocity = (*message)[2]; qdbg << "Note on: key=" << key << ", velocity=" << velocity; emit noteOn(key, velocity); } qdbg << endl; }
void NotePlayHandle::done() { lock(); noteOff( 0 ); if( hasParent() == false ) { delete m_baseDetuning; m_instrumentTrack->m_processHandles.removeAll( this ); } else { m_parent->m_subNotes.removeOne( this ); } if( m_pluginData != NULL ) { m_instrumentTrack->deleteNotePluginData( this ); } if( m_instrumentTrack->m_notes[key()] == this ) { m_instrumentTrack->m_notes[key()] = NULL; } m_subNotes.clear(); delete m_filter; if( buffer() ) releaseBuffer(); unlock(); }
void Synthesiser::handleMidiEvent (const MidiMessage& m) { if (m.isNoteOn()) { noteOn (m.getChannel(), m.getNoteNumber(), m.getFloatVelocity()); } else if (m.isNoteOff()) { noteOff (m.getChannel(), m.getNoteNumber(), true); } else if (m.isAllNotesOff() || m.isAllSoundOff()) { allNotesOff (m.getChannel(), true); } else if (m.isPitchWheel()) { const int channel = m.getChannel(); const int wheelPos = m.getPitchWheelValue(); lastPitchWheelValues [channel - 1] = wheelPos; handlePitchWheel (channel, wheelPos); } else if (m.isController()) { handleController (m.getChannel(), m.getControllerNumber(), m.getControllerValue()); } }
void OPN2::silenceAll() // Silence all OPL channels. { for(size_t c = 0; c < m_numChannels; ++c) { noteOff(c); touchNote(c, 0); } }
VstInt32 SorolletVSTi::processEvents(VstEvents* ev) { for (VstInt32 i = 0; i < ev->numEvents; i++) { if ((ev->events[i])->type != kVstMidiType) continue; VstMidiEvent* event = (VstMidiEvent*) ev->events[i]; char* midiData = event->midiData; VstInt32 status = midiData[0] & 0xf0; // ignoring channel if (status == 0x90 || status == 0x80) // we only look at notes { VstInt32 note = midiData[1] & 0x7f; VstInt32 velocity = midiData[2] & 0x7f; if (status == 0x80) velocity = 0; // note off by velocity 0 if (!velocity && (note == currentNote)) noteOff(event->deltaFrames); else noteOn(note, velocity, event->deltaFrames); }/*else if(status == 0xA0) { printf("polyphonic Aftertouch\n"); } else if(status == 0xD0) { printf("channel Aftertouch\n"); }*/ else if (0xC0 == status) { // Control change int number = midiData[1] & 0x7F; float value = (float) ((midiData[2] & 0x7F)); printf("CC %d value = %d , float = %f\n", number, midiData[2] & 0x7F, value); } else if (status == 0xb0) { if (midiData[1] == 0x7e || midiData[1] == 0x7b) // all notes off noteOff(event->deltaFrames); } event++; } return 1; }
void sf2Instrument::deleteNotePluginData( NotePlayHandle * _n ) { SF2PluginData * pluginData = static_cast<SF2PluginData *>( _n->m_pluginData ); if( ! pluginData->noteOffSent ) // if we for some reason haven't noteoffed the note before it gets deleted, // do it here { noteOff( pluginData ); } delete pluginData; }
void PianoScene::triggerNoteOff( const int note, const int vel ) { int n = m_baseOctave*12 + note + m_transpose; if ((n >= m_minNote) && (n <= m_maxNote)) { if (m_handler != NULL) { m_handler->noteOff(n, vel); } else { emit noteOff(n, vel); } } }
void MIDISeq::BuildMIDIMessages() { if(note_num_set) { MidiMessage noteOn(midi_channel, note_num, 127); midi_messages[0] = noteOn; MidiMessage noteOff(midi_channel,note_num,0); midi_messages[1] = noteOff; } }
/** * @short Gets the audio signals for both channels (actually a copy) */ void Polybase::getAudio(float *audio[2], unsigned int nsamples, const MidiEventList &list){ if (nsamples>chunksize){ if (chunk){ delete chunk; } chunk=new float[nsamples]; } unsigned int uptoSample=0; unsigned int i; foreach(MidiEvent ev, list){ if (ev.sampleOffset>uptoSample){ calculateChunk(&audio[0][uptoSample], ev.sampleOffset-uptoSample); uptoSample=ev.sampleOffset; } switch (ev.type){ case MidiEvent::noteOn: noteOn(ev.data[0], ev.data[1]); break; case MidiEvent::noteOff: noteOff(ev.data[0], ev.data[1]); break; case MidiEvent::controller: controller(ev.data[0], ev.data[1]); break; default: break; } } calculateChunk(&audio[0][uptoSample], nsamples-uptoSample); for (i=0;i<nsamples;i++){ float s=audio[0][i]*volume; if (s>1.0 || s<-1.0){ volume*=0.9; if (s<0.0) s=-1.0; else s=1.0; WARNING("Clip %f! lowering volume to %f", s, volume); emit sendController(0, volume*127); } audio[0][i]=s; } // no stereo by the moment memcpy(audio[1],audio[0],sizeof(float)*nsamples); }
void MMidi::midiHandler() { //midiTime = millis(); uint8_t midiChannel = (midiBuffer[0] & 0x0F); switch(midiBuffer[0] & 0xF0) { // bit mask with &0xF0 ? case 0x80: noteOff (midiBuffer[0] & 0x0F, // midi channel 0-16 midiBuffer[1] & 0x7F, // note value 0-127 midiBuffer[2] & 0x7F); // note velocity 0-127 break; case 0x90: noteOn (midiBuffer[0] & 0x0F, // midi channel 0-16 midiBuffer[1] & 0x7F, // note value 0-127 midiBuffer[2] & 0x7F); // note velocity 0-127 break; case 0xA0: aftertouch (midiBuffer[0] & 0x0F, // midi channel 0-16 midiBuffer[1] & 0x7F, // note value 0-127 midiBuffer[2] & 0x7F);// note velocity 0-127 break; case 0xB0: controller (midiBuffer[0] & 0x0F, // midi channel 0-16 midiBuffer[1] & 0x7F, // controller number 0-127 midiBuffer[2] & 0x7F);// controller value 0-127 break; case 0xC0: programChange (midiBuffer[0] & 0x0F, // midi channel 0-16 midiBuffer[1] & 0x7F); // program number 0-127 break; case 0xD0: channelPressure (midiBuffer[0] & 0x0F, // midi channel 0-16 midiBuffer[1] & 0x7F); // pressure amount 0-127 break; case 0xE0: pitchWheel (midiBuffer[0] & 0x0F, // midi channel 0-16 midiBuffer[1] & 0x7F, // higher bits 0-6 midiBuffer[2] & 0x7F);// lower bits 7-13 break; default: break; } }
void updateMidi() { int b = Serial.read(); if(b!=-1) { midiByte2 = midiByte1; midiByte1 = midiByte0; midiByte0 = b; // only work if we've got a status byte // of some sort if(!(midiByte2 & B10000000)) return; int st = HI_NIBBLE(midiByte2); int channel = LO_NIBBLE(midiByte2); // channel += 1; // we're doing this with defines // now check to see if we have a midi if(st==NOTE_ON_STATUS) { if(midiByte0==0) { // if the volume is zero, it's a note off noteOff(channel, midiByte1); } else { noteOn(channel, midiByte1, midiByte0); } } else if(st==NOTE_OFF_STATUS) { noteOff(channel, midiByte1); #ifdef USING_CC } else if(st==CC_STATUS) { cc(channel, midiByte1, midiByte0); } else if(st==PITCHBEND_STATUS) { cc(channel, -1, midiByte0); #endif } } }
boolean Instrument::evHandler( obEvent ev ) { evType evtype = ev.type(); switch ( evtype ) { case KEY_DOWN: // note On case KEY_UP: // note Off { if ( ! keybrd.muted() ) { key k = ev.getKey(); if ( ! ev.octOn() ) k.setOctave( keybrd.octave ); if ( evtype == KEY_DOWN ) noteOn( k ); else noteOff( k ); } else return false; break; } case BUT0_TAP: // octave down (if keybrd active) if ( ! keybrd.muted() ) keybrd.downOctave(); else return false; break; case BUT1_TAP: // octave up (if keybrd active) if ( ! keybrd.muted() ) keybrd.upOctave(); else return false; break; default: return super::evHandler( ev ); } return true; }
void PixmapKeyboard::sendNoteOff(int note, bool sendSignal) { if (note >= 0 && note <= 127 && fEnabledKeys.contains(note)) { fEnabledKeys.removeOne(note); if (sendSignal) emit noteOff(note); update(); } if (fEnabledKeys.count() == 0) emit notesOff(); }
void MidiKeyboardState::allNotesOff (const int midiChannel) { const ScopedLock sl (lock); if (midiChannel <= 0) { for (int i = 1; i <= 16; ++i) allNotesOff (i); } else { for (int i = 0; i < 128; ++i) noteOff (midiChannel, i, 0.0f); } }
void sf2Instrument::deleteNotePluginData( NotePlayHandle * _n ) { SF2PluginData * pluginData = static_cast<SF2PluginData *>( _n->m_pluginData ); if( ! pluginData->noteOffSent ) // if we for some reason haven't noteoffed the note before it gets deleted, // do it here { noteOff( pluginData ); m_playingNotesMutex.lock(); if( m_playingNotes.indexOf( _n ) >= 0 ) { m_playingNotes.remove( m_playingNotes.indexOf( _n ) ); } m_playingNotesMutex.unlock(); } delete pluginData; }
void __ISR(_ADC_VECTOR, IPL7AUTO) ADCHandle(void){ mAD1ClearIntFlag(); int i=0; for(i; i<16; i++){ adcread = ReadADC10(i); switch(keyState[i]){ case GET_ON: // Previous force value moved into bin 0 // Bin 1 gets new value from ADC forceData[i][0] = forceData[i][1]; forceData[i][1] = adcread; // Previous slope bit moved into bin 0 // New slope bit determined from backward differentiator // if y[n] - y[n-1] is positive --> slope in bin 1 is '1' // else, negative slope gets '0' slopeData[i][0] = slopeData[i][1]; if(forceData[i][1]>forceData[i][0]){ slopeData[i][1]=1; }else{ slopeData[i][1]=0; } // Slope in bin 1 will be less than bin 0 if the slope changes from // Positive to negative, meaning a peak has been found // If so, send out noteOn signal // Else keep searching for noteOn conditions if (slopeData[i][1]<slopeData[i][0] && forceData[i][0] > threshold){ noteOn(i, forceData[i][0]); keyState[i] = GET_OFF; }else{ keyState[i] = GET_ON; } break; case GET_OFF: //TODO: Change this to digital input from comparator if(1){ noteOff(i); keyState[i] = GET_ON; } break; } } }
void musicBlock::noteOn(uint32_t channel, uint8_t key, int volume) { if (volume <= 0) { noteOff(channel, key); return; } GenMidiInstrument *instrument; // Percussion channel is treated differently. if (channel == CHAN_PERCUSSION) { if (key < GENMIDI_FIST_PERCUSSION || key >= GENMIDI_FIST_PERCUSSION + GENMIDI_NUM_PERCUSSION) { return; } instrument = &OPLinstruments[key + (GENMIDI_NUM_INSTRS - GENMIDI_FIST_PERCUSSION)]; } else { auto inst = oplchannels[channel].Instrument; if (inst >= GENMIDI_NUM_TOTAL) return; // better safe than sorry. instrument = &OPLinstruments[inst]; } bool double_voice = ((instrument->flags) & GENMIDI_FLAG_2VOICE) && !opl_singlevoice; int i = findFreeVoice(); if (i < 0) i = replaceExistingVoice(); if (i >= 0) { voiceKeyOn(i, channel, instrument, 0, key, volume); if (double_voice) { i = findFreeVoice(); if (i > 0) { voiceKeyOn(i, channel, instrument, 1, key, volume); } } } }
void VPiano::customEvent ( QEvent *event ) { if (event->type() == NoteOnEventType ) { NoteOnEvent *ev = static_cast<NoteOnEvent*>(event); ui.pianokeybd->showNoteOn(ev->getNote()); if (m_midiThru) noteOn(ev->getNote()); event->accept(); } else if (event->type() == NoteOffEventType ) { NoteOffEvent *ev = static_cast<NoteOffEvent*>(event); ui.pianokeybd->showNoteOff(ev->getNote()); if (m_midiThru) noteOff(ev->getNote()); event->accept(); } else if (event->type() == ControllerEventType ) { ControllerEvent *ev = static_cast<ControllerEvent*>(event); updateController(ev->getController(), ev->getValue()); if (m_midiThru) sendController(ev->getController(), ev->getValue()); event->accept(); } }
int MainWindow::qt_metacall(QMetaObject::Call _c, int _id, void **_a) { _id = QMainWindow::qt_metacall(_c, _id, _a); if (_id < 0) return _id; if (_c == QMetaObject::InvokeMetaMethod) { switch (_id) { case 0: noteOn((*reinterpret_cast< const int(*)>(_a[1]))); break; case 1: noteOff((*reinterpret_cast< const int(*)>(_a[1]))); break; case 2: pauseActive((*reinterpret_cast< int(*)>(_a[1]))); break; case 3: setChannelChanged((*reinterpret_cast< int(*)>(_a[1]))); break; case 4: setVelocityChanged((*reinterpret_cast< int(*)>(_a[1]))); break; case 5: setBase_octaveChanged((*reinterpret_cast< int(*)>(_a[1]))); break; case 6: setTransposeChanged((*reinterpret_cast< int(*)>(_a[1]))); break; case 7: setEditEnable((*reinterpret_cast< bool(*)>(_a[1]))); break; case 8: editChord((*reinterpret_cast< QPoint(*)>(_a[1]))); break; case 9: on_actionOpenMidi_triggered(); break; case 10: on_actionOpen_triggered(); break; case 11: on_actionPlayMidi_triggered(); break; case 12: on_btn_9_clicked(); break; case 13: on_btn_8_clicked(); break; case 14: on_btn_7_clicked(); break; case 15: on_btn_6_clicked(); break; case 16: on_btn_5_clicked(); break; case 17: on_btn_4_clicked(); break; case 18: on_btn_3_clicked(); break; case 19: on_btn_2_clicked(); break; case 20: on_btn_1_clicked(); break; case 21: on_btn_0_clicked(); break; case 22: on_chordAnalyse_triggered(); break; case 23: on_redoAction_triggered(); break; case 24: on_undoAction_triggered(); break; case 25: on_actionSave_triggered(); break; case 26: on_actionMIDI_controller_triggered((*reinterpret_cast< bool(*)>(_a[1]))); break; case 27: saveStaff(); break; case 28: loadStaff((*reinterpret_cast< QString(*)>(_a[1]))); break; case 29: processFinished((*reinterpret_cast< int(*)>(_a[1])),(*reinterpret_cast< QProcess::ExitStatus(*)>(_a[2]))); break; default: ; } _id -= 30; } return _id; }
void InstrumentTrack::deleteNotePluginData( notePlayHandle * _n ) { if( m_instrument != NULL ) { m_instrument->deleteNotePluginData( _n ); } // Notes deleted when keys still pressed if( m_notes[_n->key()] == _n ) { note done_note( midiTime( static_cast<f_cnt_t>( _n->totalFramesPlayed() / engine::framesPerTick() ) ), 0, _n->key(), _n->getVolume(), _n->getPanning() ); _n->noteOff(); m_notes[_n->key()] = NULL; emit noteOff( done_note ); } }
/** Sends system resets: all controllers, all sounds off, all notes off */ void MIDI::reset() { send(0xb0 | channel); // system reset for channel send(121); // reset all controllers send(0x00); send(0xb0 | channel); // system reset for channel send(120); // sound off send(0x00); send(0xb0 | channel); // system reset for channel send(123); // all notes off send(0x00); for(int c=0; c<16; c++) { for(int i=0; i<128; i++) { noteOff(i, c, 0); } } if(verbose) { std::cout << "MIDI RESET" << std::endl; } }
void Synthesiser::handleMidiEvent (const MidiMessage& m) { const int channel = m.getChannel(); if (m.isNoteOn()) { noteOn (channel, m.getNoteNumber(), m.getFloatVelocity()); } else if (m.isNoteOff()) { noteOff (channel, m.getNoteNumber(), m.getFloatVelocity(), true); } else if (m.isAllNotesOff() || m.isAllSoundOff()) { allNotesOff (channel, true); } else if (m.isPitchWheel()) { const int wheelPos = m.getPitchWheelValue(); lastPitchWheelValues [channel - 1] = wheelPos; handlePitchWheel (channel, wheelPos); } else if (m.isAftertouch()) { handleAftertouch (channel, m.getNoteNumber(), m.getAfterTouchValue()); } else if (m.isChannelPressure()) { handleChannelPressure (channel, m.getChannelPressureValue()); } else if (m.isController()) { handleController (channel, m.getControllerNumber(), m.getControllerValue()); } else if (m.isProgramChange()) { handleProgramChange (channel, m.getProgramChangeNumber()); } }
void MidiSequencer::eventReceived(drumstick::SequencerEvent *ev) { static QChar fill('0'); drumstick::KeyEvent *kev; if (!(kev = static_cast<drumstick::KeyEvent*>(ev))) return; if (kev->getSequencerType() == SND_SEQ_EVENT_NOTEON && kev->getTag() == 1) emit noteOn(kev->getChannel(), kev->getKey(), kev->getVelocity()); if (kev->getSequencerType() == SND_SEQ_EVENT_NOTEOFF && kev->getTag() == 1) { if (m_eventSchedulingMode == FROM_ENGINE) emit noteOff(kev->getChannel(), kev->getKey(), kev->getVelocity()); else emit noteHighlight(kev->getChannel(), kev->getKey(), kev->getVelocity(), QStringLiteral("#B3CADB")); } if (m_tick != 0 && m_midiSequencerOutputThread->isRunning()) { const snd_seq_real_time_t *rt = m_queue->getStatus().getRealtime(); int mins = rt->tv_sec / 60; int secs = rt->tv_sec % 60; int cnts = qFloor( rt->tv_nsec / 1.0e7 ); emit timeLabelChanged(QString("%1:%2.%3").arg(mins,2,10,fill).arg(secs,2,10,fill).arg(cnts,2,10,fill)); } }
void Player_AD::stopMusic() { if (_soundPlaying == -1) { return; } // Unlock the music resource if present _vm->_res->unlock(rtSound, _soundPlaying); _soundPlaying = -1; // Stop the music playback _curOffset = 0; // Stop all music voice channels for (int i = 0; i < ARRAYSIZE(_voiceChannels); ++i) { if (_voiceChannels[i].lastEvent) { noteOff(i); } } // Reset rhythm state writeReg(0xBD, 0x00); limitHWChannels(9); }
void InstrumentTrack::processInEvent( const midiEvent & _me, const midiTime & _time ) { engine::getMixer()->lock(); switch( _me.m_type ) { // we don't send MidiNoteOn, MidiNoteOff and MidiKeyPressure // events to instrument as notePlayHandle will send them on its // own case MidiNoteOn: if( _me.velocity() > 0 ) { if( m_notes[_me.key()] == NULL ) { if( !configManager::inst()->value( "ui", "manualchannelpiano" ).toInt() ) { m_piano.setKeyState( _me.key(), true ); } // create temporary note note n; n.setKey( _me.key() ); n.setVolume( _me.getVolume() ); // create (timed) note-play-handle notePlayHandle * nph = new notePlayHandle( this, _time.frames( engine::framesPerTick() ), typeInfo<f_cnt_t>::max() / 2, n ); if( engine::getMixer()->addPlayHandle( nph ) ) { m_notes[_me.key()] = nph; } emit noteOn( n ); } break; } case MidiNoteOff: { notePlayHandle * n = m_notes[_me.key()]; if( n != NULL ) { // create dummy-note which has the same length // as the played note for sending it later // to all slots connected to signal noteOff() // this is for example needed by piano-roll for // recording notes into a pattern note done_note( midiTime( static_cast<f_cnt_t>( n->totalFramesPlayed() / engine::framesPerTick() ) ), 0, n->key(), n->getVolume(), n->getPanning() ); n->noteOff(); m_notes[_me.key()] = NULL; emit noteOff( done_note ); } break; } case MidiKeyPressure: if( m_notes[_me.key()] != NULL ) { m_notes[_me.key()]->setVolume( _me.getVolume() ); } break; case MidiPitchBend: // updatePitch() is connected to // m_pitchModel::dataChanged() which will send out // MidiPitchBend events m_pitchModel.setValue( m_pitchModel.minValue() + _me.m_data.m_param[0] * m_pitchModel.range() / 16384 ); break; case MidiControlChange: case MidiProgramChange: m_instrument->handleMidiEvent( _me, _time ); break; case MidiMetaEvent: // handle special cases such as note panning switch( _me.m_metaEvent ) { case MidiNotePanning: if( m_notes[_me.key()] != NULL ) { m_notes[_me.key()]->setPanning( _me.getPanning() ); } break; default: printf( "instrument-track: unhandled " "MIDI meta event: %i\n", _me.m_metaEvent ); break; } break; default: if( !m_instrument->handleMidiEvent( _me, _time ) ) { printf( "instrument-track: unhandled " "MIDI event %d\n", _me.m_type ); } break; } engine::getMixer()->unlock(); }
void sf2Instrument::play( sampleFrame * _working_buffer ) { const fpp_t frames = Engine::mixer()->framesPerPeriod(); // set midi pitch for this period const int currentMidiPitch = instrumentTrack()->midiPitch(); if( m_lastMidiPitch != currentMidiPitch ) { m_lastMidiPitch = currentMidiPitch; m_synthMutex.lock(); fluid_synth_pitch_bend( m_synth, m_channel, m_lastMidiPitch ); m_synthMutex.unlock(); } const int currentMidiPitchRange = instrumentTrack()->midiPitchRange(); if( m_lastMidiPitchRange != currentMidiPitchRange ) { m_lastMidiPitchRange = currentMidiPitchRange; m_synthMutex.lock(); fluid_synth_pitch_wheel_sens( m_synth, m_channel, m_lastMidiPitchRange ); m_synthMutex.unlock(); } // if we have no new noteons/noteoffs, just render a period and call it a day if( m_playingNotes.isEmpty() ) { renderFrames( frames, _working_buffer ); instrumentTrack()->processAudioBuffer( _working_buffer, frames, NULL ); return; } // processing loop // go through noteplayhandles in processing order f_cnt_t currentFrame = 0; while( ! m_playingNotes.isEmpty() ) { // find the note with lowest offset NotePlayHandle * currentNote = m_playingNotes[0]; for( int i = 1; i < m_playingNotes.size(); ++i ) { SF2PluginData * currentData = static_cast<SF2PluginData *>( currentNote->m_pluginData ); SF2PluginData * iData = static_cast<SF2PluginData *>( m_playingNotes[i]->m_pluginData ); if( currentData->offset > iData->offset ) { currentNote = m_playingNotes[i]; } } // process the current note: // first see if we're synced in frame count SF2PluginData * currentData = static_cast<SF2PluginData *>( currentNote->m_pluginData ); if( currentData->offset > currentFrame ) { renderFrames( currentData->offset - currentFrame, _working_buffer + currentFrame ); currentFrame = currentData->offset; } if( currentData->isNew ) { noteOn( currentData ); if( currentNote->isReleased() ) // if the note is released during the same period, we have to process it again for noteoff { currentData->isNew = false; currentData->offset = currentNote->framesBeforeRelease(); } else // otherwise remove the handle { m_playingNotesMutex.lock(); m_playingNotes.remove( m_playingNotes.indexOf( currentNote ) ); m_playingNotesMutex.unlock(); } } else { noteOff( currentData ); m_playingNotesMutex.lock(); m_playingNotes.remove( m_playingNotes.indexOf( currentNote ) ); m_playingNotesMutex.unlock(); } } if( currentFrame < frames ) { renderFrames( frames - currentFrame, _working_buffer + currentFrame ); } instrumentTrack()->processAudioBuffer( _working_buffer, frames, NULL ); }