void InstrumentTrack::updatePitch() { updateBaseNote(); processOutEvent( midiEvent( MidiPitchBend, midiPort()->realOutputChannel(), midiPitch() ), 0 ); }
/*! \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->m_midiEvProc->processInEvent( midiEvent( MidiNoteOff, 0, i, 0 ), midiTime() ); m_piano->m_pressedKeys[i] = false; } update(); }
void SeqDriver::procEvents() { int l1; snd_seq_event_t *evIn, evOut; bool outOfRange = false; bool unmatched = false; MidiMap* mm; do { snd_seq_event_input(seq_handle, &evIn); emit midiEvent(evIn); unmatched = true; for(l1 = 0; l1 < midiMapList->count(); l1++) { mm = midiMapList->at(l1); if (mm->isMap(evIn)) { unmatched = false; mm->doMap(evIn, &evOut, &outOfRange); if (!outOfRange) { snd_seq_ev_set_subs(&evOut); snd_seq_ev_set_direct(&evOut); snd_seq_ev_set_source(&evOut, portid_out[mm->portOut]); snd_seq_event_output_direct(seq_handle, &evOut); } } } if (!discardUnmatched && unmatched) { snd_seq_ev_set_subs(evIn); snd_seq_ev_set_direct(evIn); snd_seq_ev_set_source(evIn, portid_out[portUnmatched]); snd_seq_event_output_direct(seq_handle, evIn); } } while (snd_seq_event_input_pending(seq_handle, 0) > 0); }
/*! \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 Uint32 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 / ( ( KEY_ORDER[key_num % KeysPerOctave] == Piano::WhiteKey ) ? PW_WHITE_KEY_HEIGHT : PW_BLACK_KEY_HEIGHT ) * (float) MidiMaxVelocity ); if( y_diff < 0 ) { velocity = 0; } else if( y_diff > ( ( KEY_ORDER[key_num % KeysPerOctave] == Piano::WhiteKey ) ? PW_WHITE_KEY_HEIGHT : PW_BLACK_KEY_HEIGHT ) ) { velocity = MidiMaxVelocity; } // set note on m_piano->m_midiEvProc->processInEvent( midiEvent( MidiNoteOn, 0, key_num, velocity ), midiTime() ); m_piano->m_pressedKeys[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-> m_midiEvProc-> baseNoteModel()->id() ), QPixmap(), this ); _me->accept(); } else { m_piano->m_midiEvProc-> baseNoteModel()-> setInitValue( (float) key_num ); emit baseNoteChanged(); } } // and let the user see that he pressed a key... :) update(); } }
void Send::sendToArdour(Jack *pJack) { char *data = new char[3]; data[0] = CC_MASK + id; data[1] = (char) trackId; data[2] = gain; MidiEvent midiEvent(data); //Send it to the jack client to handle send to Ardour jack_ringbuffer_write(pJack->sceneLoadBuffer, (char *) &midiEvent,sizeof(MidiEvent)); std::cout << "Send a send on channel " << (int) id << std::endl; }
void ResourcePreviewer::preview( ResourceItem * _item ) { // stop any existing preview sounds stopPreview(); // disable journalling of changes in our preview track const bool j = engine::projectJournal()->isJournalling(); engine::projectJournal()->setJournalling( false ); engine::setSuppressMessages( true ); // handle individual resource types bool handledItem = true; switch( _item->type() ) { case ResourceItem::TypePreset: // restore default settings, in case we're going to load // an incomplete preset m_previewTrack->loadTrackSpecificSettings( m_defaultSettings.content(). firstChild().toElement() ); ResourceAction( _item ).loadPreset( m_previewTrack ); m_previewTrack->midiPort()->setMode( MidiPort::Disabled ); break; case ResourceItem::TypeSample: case ResourceItem::TypePluginSpecificResource: // restore default settings we are going to preview a // sample (which should be played at a default // instrument track) m_previewTrack->loadTrackSpecificSettings( m_defaultSettings.content(). firstChild().toElement() ); ResourceAction( _item ).loadByPlugin( m_previewTrack ); break; default: handledItem = false; break; } // re-enable journalling engine::setSuppressMessages( false ); engine::projectJournal()->setJournalling( j ); if( handledItem ) { // playback default note m_previewTrack->processInEvent( midiEvent( MidiNoteOn, 0, DefaultKey, MidiMaxVelocity ), midiTime() ); } }
/*! \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->m_midiEvProc->processInEvent( midiEvent( MidiNoteOff, 0, m_lastKey, 0 ), midiTime() ); m_piano->m_pressedKeys[m_lastKey] = false; } // and let the user see that he released a key... :) update(); m_lastKey = -1; } }
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 InstrumentTrackView::activityIndicatorReleased() { model()->processInEvent( midiEvent( MidiNoteOff, 0, DefaultKey, 0 ), midiTime() ); }
void InstrumentTrackView::activityIndicatorPressed() { model()->processInEvent( midiEvent( MidiNoteOn, 0, DefaultKey, MidiMaxVelocity ), midiTime() ); }
/*! \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 / ( ( KEY_ORDER[key_num % KeysPerOctave] == Piano::WhiteKey ) ? PW_WHITE_KEY_HEIGHT : PW_BLACK_KEY_HEIGHT ) * (float) MidiMaxVelocity ); // 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 > ( ( KEY_ORDER[key_num % KeysPerOctave] == Piano::WhiteKey ) ? PW_WHITE_KEY_HEIGHT : PW_BLACK_KEY_HEIGHT ) ) { velocity = MidiMaxVelocity; } // 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->m_midiEvProc->processInEvent( midiEvent( MidiNoteOff, 0, m_lastKey, 0 ), midiTime() ); m_piano->m_pressedKeys[m_lastKey] = false; m_lastKey = -1; } if( _me->buttons() & Qt::LeftButton ) { if( _me->pos().y() > PIANO_BASE ) { m_piano->m_midiEvProc->processInEvent( midiEvent( MidiNoteOn, 0, key_num, velocity ), midiTime() ); m_piano->m_pressedKeys[key_num] = true; m_lastKey = key_num; } else { m_piano->m_midiEvProc-> baseNoteModel()-> setInitValue( (float) key_num ); } } // and let the user see that he pressed a key... :) update(); } else if( m_piano->m_pressedKeys[key_num] == true ) { m_piano->m_midiEvProc->processInEvent( midiEvent( MidiKeyPressure, 0, key_num, velocity ), midiTime() ); } }
int OSCServer::genericHandler( const char *path, const char *types, lo_arg **argv, int argc, void *data) { UNUSED(argc); UNUSED(types); if(!contacted) { firstContact(lo_message_get_source((lo_message)data)); contacted = true; } //find out what this message is for (track bus or master) std::string pathStr(path); pathStr = pathStr.substr(1); pathStr = pathStr.substr(pathStr.find("/") + 1); std::string object = pathStr.substr(0,pathStr.find("/")); pathStr = pathStr.substr(pathStr.find("/") + 1); std::string controllable = pathStr.substr(0,pathStr.find("/")); if(object == "track") { if(controllable == "fader") { //get the track number pathStr= pathStr.substr(pathStr.find("/") + 1); //build a midi event from the fader value and track number char data[3]; if(pthread_mutex_lock(&idMutex) == 0) { data[0] = (char) CC_MASK; data[1] = trackIds[atoi(pathStr.c_str()) - 1]; data[2] = (char) ((int) argv[0]->f); pthread_mutex_unlock(&idMutex); } MidiEvent midiEvent(data,true); //Send it to the jack client to handle send to Ardour if(!((unsigned char)data[1] == 0xFF)){ jack_ringbuffer_write(controllerBuffer, (char *) &midiEvent,sizeof(MidiEvent)); } } if(controllable == "bank") { if (argv[0]->f > 0.5){ pathStr= pathStr.substr(pathStr.find("/") + 1); if(pathStr == "up"){ int tb = getTrackBank(); if((tb+1) < numTrackBanks) { sendTrackBank(tb+1); setTrackBank(tb+1); } } else if(pathStr == "down"){ int tb = getTrackBank(); if(tb > 0) { sendTrackBank(tb-1); setTrackBank(tb-1); } } } } } else if (object == "bus") { if(controllable == "fader") { //get the bus number(void *)this pathStr= pathStr.substr(pathStr.find("/") + 1); char data[3]; if(pthread_mutex_lock(&idMutex) == 0) { data[0] = (char) CC_MASK; data[1] = busIds[atoi(pathStr.c_str()) - 1]; data[2] = (char) ((int) argv[0]->f); pthread_mutex_unlock(&idMutex); } MidiEvent midiEvent(data,true); //Send it to the jack client to handle send to Ardour //Send it to the jack client to handle send to Ardour if(!((unsigned char)data[1] == 0xFF)){ jack_ringbuffer_write(controllerBuffer, (char *) &midiEvent,sizeof(MidiEvent)); } } if(controllable == "bank") { if (argv[0]->f > 0.5){ pathStr= pathStr.substr(pathStr.find("/") + 1); if(pathStr == "up"){ int bb = getBusBank(); if((bb+1) < numBusBanks) { setBusBank(bb+1); sendBusBank(bb+1); } } else if(pathStr == "down"){ int bb = getBusBank(); if(bb > 0) { setBusBank(bb-1); sendBusBank(bb-1); } } } } } else if (object == "master") { if(controllable == "fader") { //build a midi event from the fader value and track number char data[3] = {(char) CC_MASK,MASTER_CC,(char)((int) argv[0]->f)}; MidiEvent midiEvent(data,true); //Send it to the jack client to handle send to Ardour jack_ringbuffer_write(controllerBuffer, (char *) &midiEvent,sizeof(MidiEvent)); } } else if (object == "scene") { } return 0; }
/*! \brief Handle a note being pressed on our keyboard display * * \param _key the key being pressed */ void Piano::handleKeyPress( int _key ) { m_midiEvProc->processInEvent( midiEvent( MidiNoteOn, 0, _key, MidiMaxVelocity ), midiTime() ); m_pressedKeys[_key] = true; }
/*! \brief Handle a note being released on our keyboard display * * \param _key the key being releassed */ void Piano::handleKeyRelease( int _key ) { m_midiEvProc->processInEvent( midiEvent( MidiNoteOff, 0, _key, 0 ), midiTime() ); m_pressedKeys[_key] = false; }
void jackProcess(const jack_nframes_t nframes) { #if DISTRHO_PLUGIN_NUM_INPUTS > 0 const float* audioIns[DISTRHO_PLUGIN_NUM_INPUTS]; for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_INPUTS; ++i) audioIns[i] = (const float*)jack_port_get_buffer(fPortAudioIns[i], nframes); #else static const float** audioIns = nullptr; #endif #if DISTRHO_PLUGIN_NUM_OUTPUTS > 0 float* audioOuts[DISTRHO_PLUGIN_NUM_OUTPUTS]; for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_OUTPUTS; ++i) audioOuts[i] = (float*)jack_port_get_buffer(fPortAudioOuts[i], nframes); #else static float** audioOuts = nullptr; #endif #if DISTRHO_PLUGIN_WANT_TIMEPOS jack_position_t pos; fTimePosition.playing = (jack_transport_query(fClient, &pos) == JackTransportRolling); if (pos.unique_1 == pos.unique_2) { fTimePosition.frame = pos.frame; if (pos.valid & JackTransportBBT) { fTimePosition.bbt.valid = true; fTimePosition.bbt.bar = pos.bar; fTimePosition.bbt.beat = pos.beat; fTimePosition.bbt.tick = pos.tick; fTimePosition.bbt.barStartTick = pos.bar_start_tick; fTimePosition.bbt.beatsPerBar = pos.beats_per_bar; fTimePosition.bbt.beatType = pos.beat_type; fTimePosition.bbt.ticksPerBeat = pos.ticks_per_beat; fTimePosition.bbt.beatsPerMinute = pos.beats_per_minute; } else fTimePosition.bbt.valid = false; } else { fTimePosition.bbt.valid = false; fTimePosition.frame = 0; } fPlugin.setTimePosition(fTimePosition); #endif #if DISTRHO_PLUGIN_IS_SYNTH void* const midiBuf = jack_port_get_buffer(fPortMidiIn, nframes); if (const uint32_t eventCount = jack_midi_get_event_count(midiBuf)) { uint32_t midiEventCount = 0; MidiEvent midiEvents[eventCount]; jack_midi_event_t jevent; for (uint32_t i=0; i < eventCount; ++i) { if (jack_midi_event_get(&jevent, midiBuf, i) != 0) break; MidiEvent& midiEvent(midiEvents[midiEventCount++]); midiEvent.frame = jevent.time; midiEvent.size = jevent.size; if (midiEvent.size > MidiEvent::kDataSize) midiEvent.dataExt = jevent.buffer; else std::memcpy(midiEvent.data, jevent.buffer, midiEvent.size); } fPlugin.run(audioIns, audioOuts, nframes, midiEvents, midiEventCount); } else { fPlugin.run(audioIns, audioOuts, nframes, nullptr, 0); } #else fPlugin.run(audioIns, audioOuts, nframes); #endif }
void lv2_run(const uint32_t sampleCount) { // cache midi input and time position first #if DISTRHO_PLUGIN_WANT_MIDI_INPUT uint32_t midiEventCount = 0; #endif #if DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_TIMEPOS LV2_ATOM_SEQUENCE_FOREACH(fPortEventsIn, event) { if (event == nullptr) break; # if DISTRHO_PLUGIN_WANT_MIDI_INPUT if (event->body.type == fURIDs.midiEvent) { if (midiEventCount >= kMaxMidiEvents) continue; const uint8_t* const data((const uint8_t*)(event + 1)); MidiEvent& midiEvent(fMidiEvents[midiEventCount++]); midiEvent.frame = event->time.frames; midiEvent.size = event->body.size; if (midiEvent.size > MidiEvent::kDataSize) { midiEvent.dataExt = data; std::memset(midiEvent.data, 0, MidiEvent::kDataSize); } else { midiEvent.dataExt = nullptr; std::memcpy(midiEvent.data, data, midiEvent.size); } continue; } # endif # if DISTRHO_PLUGIN_WANT_TIMEPOS if (event->body.type == fURIDs.atomBlank || event->body.type == fURIDs.atomObject) { const LV2_Atom_Object* const obj((const LV2_Atom_Object*)&event->body); if (obj->body.otype != fURIDs.timePosition) continue; LV2_Atom* bar = nullptr; LV2_Atom* barBeat = nullptr; LV2_Atom* beatUnit = nullptr; LV2_Atom* beatsPerBar = nullptr; LV2_Atom* beatsPerMinute = nullptr; LV2_Atom* frame = nullptr; LV2_Atom* speed = nullptr; LV2_Atom* ticksPerBeat = nullptr; lv2_atom_object_get(obj, fURIDs.timeBar, &bar, fURIDs.timeBarBeat, &barBeat, fURIDs.timeBeatUnit, &beatUnit, fURIDs.timeBeatsPerBar, &beatsPerBar, fURIDs.timeBeatsPerMinute, &beatsPerMinute, fURIDs.timeFrame, &frame, fURIDs.timeSpeed, &speed, fURIDs.timeTicksPerBeat, &ticksPerBeat, nullptr); // need to handle this first as other values depend on it if (ticksPerBeat != nullptr) { /**/ if (ticksPerBeat->type == fURIDs.atomDouble) fLastPositionData.ticksPerBeat = ((LV2_Atom_Double*)ticksPerBeat)->body; else if (ticksPerBeat->type == fURIDs.atomFloat) fLastPositionData.ticksPerBeat = ((LV2_Atom_Float*)ticksPerBeat)->body; else if (ticksPerBeat->type == fURIDs.atomInt) fLastPositionData.ticksPerBeat = ((LV2_Atom_Int*)ticksPerBeat)->body; else if (ticksPerBeat->type == fURIDs.atomLong) fLastPositionData.ticksPerBeat = ((LV2_Atom_Long*)ticksPerBeat)->body; else d_stderr("Unknown lv2 ticksPerBeat value type"); if (fLastPositionData.ticksPerBeat > 0) fTimePosition.bbt.ticksPerBeat = fLastPositionData.ticksPerBeat; } // same if (speed != nullptr) { /**/ if (speed->type == fURIDs.atomDouble) fLastPositionData.speed = ((LV2_Atom_Double*)speed)->body; else if (speed->type == fURIDs.atomFloat) fLastPositionData.speed = ((LV2_Atom_Float*)speed)->body; else if (speed->type == fURIDs.atomInt) fLastPositionData.speed = ((LV2_Atom_Int*)speed)->body; else if (speed->type == fURIDs.atomLong) fLastPositionData.speed = ((LV2_Atom_Long*)speed)->body; else d_stderr("Unknown lv2 speed value type"); fTimePosition.playing = d_isNotZero(fLastPositionData.speed); } if (bar != nullptr) { /**/ if (bar->type == fURIDs.atomDouble) fLastPositionData.bar = ((LV2_Atom_Double*)bar)->body; else if (bar->type == fURIDs.atomFloat) fLastPositionData.bar = ((LV2_Atom_Float*)bar)->body; else if (bar->type == fURIDs.atomInt) fLastPositionData.bar = ((LV2_Atom_Int*)bar)->body; else if (bar->type == fURIDs.atomLong) fLastPositionData.bar = ((LV2_Atom_Long*)bar)->body; else d_stderr("Unknown lv2 bar value type"); if (fLastPositionData.bar >= 0) fTimePosition.bbt.bar = fLastPositionData.bar + 1; } if (barBeat != nullptr) { /**/ if (barBeat->type == fURIDs.atomDouble) fLastPositionData.barBeat = ((LV2_Atom_Double*)barBeat)->body; else if (barBeat->type == fURIDs.atomFloat) fLastPositionData.barBeat = ((LV2_Atom_Float*)barBeat)->body; else if (barBeat->type == fURIDs.atomInt) fLastPositionData.barBeat = ((LV2_Atom_Int*)barBeat)->body; else if (barBeat->type == fURIDs.atomLong) fLastPositionData.barBeat = ((LV2_Atom_Long*)barBeat)->body; else d_stderr("Unknown lv2 barBeat value type"); if (fLastPositionData.barBeat >= 0.0f) { const double rest = std::fmod(fLastPositionData.barBeat, 1.0); fTimePosition.bbt.beat = fLastPositionData.barBeat-rest+1.0; fTimePosition.bbt.tick = rest*fTimePosition.bbt.ticksPerBeat+0.5; } } if (beatUnit != nullptr) { /**/ if (beatUnit->type == fURIDs.atomDouble) fLastPositionData.beatUnit = ((LV2_Atom_Double*)beatUnit)->body; else if (beatUnit->type == fURIDs.atomFloat) fLastPositionData.beatUnit = ((LV2_Atom_Float*)beatUnit)->body; else if (beatUnit->type == fURIDs.atomInt) fLastPositionData.beatUnit = ((LV2_Atom_Int*)beatUnit)->body; else if (beatUnit->type == fURIDs.atomLong) fLastPositionData.beatUnit = ((LV2_Atom_Long*)beatUnit)->body; else d_stderr("Unknown lv2 beatUnit value type"); if (fLastPositionData.beatUnit > 0) fTimePosition.bbt.beatType = fLastPositionData.beatUnit; } if (beatsPerBar != nullptr) { /**/ if (beatsPerBar->type == fURIDs.atomDouble) fLastPositionData.beatsPerBar = ((LV2_Atom_Double*)beatsPerBar)->body; else if (beatsPerBar->type == fURIDs.atomFloat) fLastPositionData.beatsPerBar = ((LV2_Atom_Float*)beatsPerBar)->body; else if (beatsPerBar->type == fURIDs.atomInt) fLastPositionData.beatsPerBar = ((LV2_Atom_Int*)beatsPerBar)->body; else if (beatsPerBar->type == fURIDs.atomLong) fLastPositionData.beatsPerBar = ((LV2_Atom_Long*)beatsPerBar)->body; else d_stderr("Unknown lv2 beatsPerBar value type"); if (fLastPositionData.beatsPerBar > 0.0f) fTimePosition.bbt.beatsPerBar = fLastPositionData.beatsPerBar; } if (beatsPerMinute != nullptr) { /**/ if (beatsPerMinute->type == fURIDs.atomDouble) fLastPositionData.beatsPerMinute = ((LV2_Atom_Double*)beatsPerMinute)->body; else if (beatsPerMinute->type == fURIDs.atomFloat) fLastPositionData.beatsPerMinute = ((LV2_Atom_Float*)beatsPerMinute)->body; else if (beatsPerMinute->type == fURIDs.atomInt) fLastPositionData.beatsPerMinute = ((LV2_Atom_Int*)beatsPerMinute)->body; else if (beatsPerMinute->type == fURIDs.atomLong) fLastPositionData.beatsPerMinute = ((LV2_Atom_Long*)beatsPerMinute)->body; else d_stderr("Unknown lv2 beatsPerMinute value type"); if (fLastPositionData.beatsPerMinute > 0.0f) { fTimePosition.bbt.beatsPerMinute = fLastPositionData.beatsPerMinute; if (d_isNotZero(fLastPositionData.speed)) fTimePosition.bbt.beatsPerMinute *= std::abs(fLastPositionData.speed); } } if (frame != nullptr) { /**/ if (frame->type == fURIDs.atomDouble) fLastPositionData.frame = ((LV2_Atom_Double*)frame)->body; else if (frame->type == fURIDs.atomFloat) fLastPositionData.frame = ((LV2_Atom_Float*)frame)->body; else if (frame->type == fURIDs.atomInt) fLastPositionData.frame = ((LV2_Atom_Int*)frame)->body; else if (frame->type == fURIDs.atomLong) fLastPositionData.frame = ((LV2_Atom_Long*)frame)->body; else d_stderr("Unknown lv2 frame value type"); if (fLastPositionData.frame >= 0) fTimePosition.frame = fLastPositionData.frame; } fTimePosition.bbt.barStartTick = fTimePosition.bbt.ticksPerBeat* fTimePosition.bbt.beatsPerBar* (fTimePosition.bbt.bar-1); fTimePosition.bbt.valid = (fLastPositionData.beatsPerMinute > 0.0 && fLastPositionData.beatUnit > 0 && fLastPositionData.beatsPerBar > 0.0f); fPlugin.setTimePosition(fTimePosition); continue; } # endif } #endif // check for messages from UI #if DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI LV2_ATOM_SEQUENCE_FOREACH(fPortEventsIn, event) { if (event == nullptr) break; if (event->body.type == fURIDs.distrhoState && fWorker != nullptr) { const void* const data((const void*)(event + 1)); // check if this is our special message if (std::strcmp((const char*)data, "__dpf_ui_data__") == 0) { for (uint32_t i=0, count=fPlugin.getStateCount(); i < count; ++i) fNeededUiSends[i] = true; } else // no, send to DSP as usual { fWorker->schedule_work(fWorker->handle, event->body.size, data); } } } #endif // Check for updated parameters float curValue; for (uint32_t i=0, count=fPlugin.getParameterCount(); i < count; ++i) { if (fPortControls[i] == nullptr) continue; curValue = *fPortControls[i]; if (fLastControlValues[i] != curValue && ! fPlugin.isParameterOutput(i)) { fLastControlValues[i] = curValue; fPlugin.setParameterValue(i, curValue); } } // Run plugin if (sampleCount != 0) { #if DISTRHO_PLUGIN_WANT_MIDI_INPUT fPlugin.run(fPortAudioIns, fPortAudioOuts, sampleCount, fMidiEvents, midiEventCount); #else fPlugin.run(fPortAudioIns, fPortAudioOuts, sampleCount); #endif #if DISTRHO_PLUGIN_WANT_TIMEPOS // update timePos for next callback if (d_isNotZero(fLastPositionData.speed)) { if (fLastPositionData.speed > 0.0) { // playing forwards fLastPositionData.frame += sampleCount; } else { // playing backwards fLastPositionData.frame -= sampleCount; if (fLastPositionData.frame < 0) fLastPositionData.frame = 0; } fTimePosition.frame = fLastPositionData.frame; if (fTimePosition.bbt.valid) { const double beatsPerMinute = fLastPositionData.beatsPerMinute * fLastPositionData.speed; const double framesPerBeat = 60.0 * fSampleRate / beatsPerMinute; const double addedBarBeats = double(sampleCount) / framesPerBeat; if (fLastPositionData.barBeat >= 0.0f) { fLastPositionData.barBeat = std::fmod(fLastPositionData.barBeat+addedBarBeats, fLastPositionData.beatsPerBar); const double rest = std::fmod(fLastPositionData.barBeat, 1.0); fTimePosition.bbt.beat = fLastPositionData.barBeat-rest+1.0; fTimePosition.bbt.tick = rest*fTimePosition.bbt.ticksPerBeat+0.5; if (fLastPositionData.bar >= 0) { fLastPositionData.bar += std::floor((fLastPositionData.barBeat+addedBarBeats)/ fLastPositionData.beatsPerBar); if (fLastPositionData.bar < 0) fLastPositionData.bar = 0; fTimePosition.bbt.bar = fLastPositionData.bar + 1; fTimePosition.bbt.barStartTick = fTimePosition.bbt.ticksPerBeat* fTimePosition.bbt.beatsPerBar* (fTimePosition.bbt.bar-1); } } fTimePosition.bbt.beatsPerMinute = std::abs(beatsPerMinute); } } #endif } updateParameterOutputs(); #if DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI const uint32_t capacity = fPortEventsOut->atom.size; bool needsInit = true; uint32_t size, offset = 0; LV2_Atom_Event* aev; // TODO - MIDI Output for (uint32_t i=0, count=fPlugin.getStateCount(); i < count; ++i) { if (! fNeededUiSends[i]) continue; const String& key = fPlugin.getStateKey(i); for (StringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit) { const String& curKey = cit->first; if (curKey != key) continue; const String& value = cit->second; // set msg size (key + value + separator + 2x null terminator) const size_t msgSize(key.length()+value.length()+3); if (sizeof(LV2_Atom_Event) + msgSize > capacity - offset) break; if (needsInit) { fPortEventsOut->atom.size = 0; fPortEventsOut->atom.type = fURIDs.atomSequence; fPortEventsOut->body.unit = 0; fPortEventsOut->body.pad = 0; needsInit = false; } // reserve msg space char msgBuf[msgSize]; std::memset(msgBuf, 0, msgSize); // write key and value in atom bufer std::memcpy(msgBuf, key.buffer(), key.length()); std::memcpy(msgBuf+(key.length()+1), value.buffer(), value.length()); // put data aev = (LV2_Atom_Event*)(LV2_ATOM_CONTENTS(LV2_Atom_Sequence, fPortEventsOut) + offset); aev->time.frames = 0; aev->body.type = fURIDs.distrhoState; aev->body.size = msgSize; std::memcpy(LV2_ATOM_BODY(&aev->body), msgBuf, msgSize-1); size = lv2_atom_pad_size(sizeof(LV2_Atom_Event) + msgSize); offset += size; fPortEventsOut->atom.size += size; fNeededUiSends[i] = false; break; } } #endif }