// We're only ever playing one note (monophonic) void Arponaut::NoteOff() { if (playing_.StatusMsg() != IMidiMsg::kNoteOff) { IMidiMsg offMsg; offMsg.MakeNoteOffMsg(playing_.NoteNumber(), playing_.mOffset); SendMidiMsg(&offMsg); playing_ = offMsg; } }
void IPlugInstrument::ProcessMidiMsg(IMidiMsg* pMsg) { // List all MIDI messages this plugin will handle. switch (pMsg->StatusMsg()) { case IMidiMsg::kNoteOn: case IMidiMsg::kNoteOff: break; case IMidiMsg::kControlChange: switch (pMsg->ControlChangeIdx()) { case IMidiMsg::kChannelVolume: { // Update the volume parameter in the UI only. double volume = pMsg->ControlChange(IMidiMsg::kChannelVolume); if (GetGUI()) GetGUI()->SetParameterFromPlug(kVolume, volume, false); else GetParam(kVolume)->Set(volume); InformHostOfParamChange(kVolume, volume); } break; case IMidiMsg::kAllNotesOff: break; // Discard all other Control Change messages. default: SendMidiMsg(pMsg); return; } break; // Discard all other MIDI messages. default: SendMidiMsg(pMsg); return; } // Don't handle the MIDI message just yet (we'll do that in // ProcessDoubleReplacing), but instead add it to the queue. mMidiQueue.Add(pMsg); }
bool IPlugVST::SendMidiMsgs(WDL_TypedBuf<IMidiMsg>* pMsgs) { // Todo: bundle and SendVSTEvents. bool rc = true; int n = pMsgs->GetSize(); IMidiMsg* pMsg = pMsgs->Get(); for (int i = 0; i < n; ++i, ++pMsg) { rc &= SendMidiMsg(pMsg); } return rc; }
void Arponaut::ProcessDoubleReplacing(double** inputs, double** outputs, int nFrames) { // Mutex is already locked for us. ENoteLength noteLength = (ENoteLength) ((int(GetParam(kNoteLength)->Value())) + 1); EOctaves octaves = (EOctaves) ((int(GetParam(kOctaves)->Value())) + 1); EArpMode arpMode = (EArpMode) (int(GetParam(kArpMode)->Value())); EInsertMode insertMode = (EInsertMode) (int(GetParam(kInsertMode)->Value())); if (GetGUI()) { //GetGUI()->SetControlFromPlug(mMeterIdx_L, peakL); //GetGUI()->SetControlFromPlug(mMeterIdx_R, peakR); } int pos = GetSamplePos(); running_ = (pos != lastPos_); int tnum, tden; GetTimeSig(&tnum, &tden); if (keymap_.held() == 0) { NoteOff(); // only sent if a note is already playing } if (running_ && keymap_.held()) { sequence_->setOctaves(octaves); sequence_->setArpMode(arpMode); sequence_->setInsertMode(insertMode); double perBeat = GetSamplesPerBeat() / noteLength; // trigger? int ibar = static_cast<int>(double(pos) / perBeat); int ilastBar = static_cast<int>(double(lastPos_) / perBeat); if ((pos == 0 && ibar == 0) || (ibar != ilastBar)) { // Log("pos %d pb %f Num %d Den %d ibar %d lastbar %d\n", pos, perBeat, tnum, tden, ibar, ilastBar); NoteOff(); IMidiMsg* next = sequence_->next(); if (next && next->StatusMsg() == IMidiMsg::kNoteOn) { SendMidiMsg(next); playing_ = *next; } matrix->SetDirty(false); } } lastPos_ = pos; }
void IPlugMultiTargets::ProcessDoubleReplacing(double** inputs, double** outputs, int nFrames) { // Mutex is already locked for us. double* in1 = inputs[0]; double* in2 = inputs[1]; double* out1 = outputs[0]; double* out2 = outputs[1]; double peakL = 0.0, peakR = 0.0; GetTime(&mTimeInfo); IKeyboardControl* pKeyboard = (IKeyboardControl*) mKeyboard; if (pKeyboard->GetKey() != mKey) { IMidiMsg msg; if (mKey >= 0) { msg.MakeNoteOffMsg(mKey + 48, 0, 0); mMidiQueue.Add(&msg); } mKey = pKeyboard->GetKey(); if (mKey >= 0) { msg.MakeNoteOnMsg(mKey + 48, pKeyboard->GetVelocity(), 0, 0); mMidiQueue.Add(&msg); } } for (int offset = 0; offset < nFrames; ++offset, ++in1, ++in2, ++out1, ++out2) { while (!mMidiQueue.Empty()) { IMidiMsg* pMsg = mMidiQueue.Peek(); if (pMsg->mOffset > offset) break; // TODO: make this work on win sa #if !defined(OS_WIN) && !defined(SA_API) SendMidiMsg(pMsg); #endif int status = pMsg->StatusMsg(); switch (status) { case IMidiMsg::kNoteOn: case IMidiMsg::kNoteOff: { int velocity = pMsg->Velocity(); // Note On if (status == IMidiMsg::kNoteOn && velocity) { mNote = pMsg->NoteNumber(); mFreq = 440. * pow(2., (mNote - 69.) / 12.); mNoteGain = velocity / 127.; } // Note Off else // if (status == IMidiMsg::kNoteOff || !velocity) { if (pMsg->NoteNumber() == mNote) mNote = -1; mNoteGain = 0.; } break; } } mMidiQueue.Remove(); } *out1 = sin( 2. * M_PI * mFreq * mPhase / mSampleRate ) * mGainLSmoother.Process(mGainL * mNoteGain); *out2 = sin( 2. * M_PI * mFreq * 1.01 * (mPhase++) / mSampleRate ) * mGainRSmoother.Process(mGainR * mNoteGain); peakL = IPMAX(peakL, fabs(*out1)); peakR = IPMAX(peakR, fabs(*out2)); } const double METER_ATTACK = 0.6, METER_DECAY = 0.05; double xL = (peakL < mPrevL ? METER_DECAY : METER_ATTACK); double xR = (peakR < mPrevR ? METER_DECAY : METER_ATTACK); peakL = peakL * xL + mPrevL * (1.0 - xL); peakR = peakR * xR + mPrevR * (1.0 - xR); mPrevL = peakL; mPrevR = peakR; if (GetGUI()) { GetGUI()->SetControlFromPlug(mMeterIdx_L, peakL); GetGUI()->SetControlFromPlug(mMeterIdx_R, peakR); } mMidiQueue.Flush(nFrames); }