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++; }
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; } // A key pressed later overrides any previously pressed key: if (noteNumber != mLastNoteNumber) { mLastNoteNumber = noteNumber; mLastFrequency = noteNumberToFrequency(mLastNoteNumber); mLastVelocity = velocity; } } else { if (mKeyStatus[noteNumber] == true) { mKeyStatus[noteNumber] = false; mNumKeys -= 1; } // If the last note was released, nothing should play: if (noteNumber == mLastNoteNumber) { mLastNoteNumber = -1; mLastFrequency = -1; mLastVelocity = 0; } } mMidiQueue.Remove(); } mOffset++; }
void IPlugInstrument::ProcessDoubleReplacing(double** inputs, double** outputs, int nFrames) { double* output = outputs[0]; for (int offset = 0; offset < nFrames; ++offset) { // Handle any MIDI messages in the queue. while (!mMidiQueue.Empty()) { IMidiMsg* pMsg = mMidiQueue.Peek(); // Stop when we've reached the current sample frame (offset). if (pMsg->mOffset > offset) break; // Handle the MIDI message. 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.); mGain = velocity / 127.; } // Note Off else // if (status == IMidiMsg::kNoteOff || !velocity) { if (pMsg->NoteNumber() == mNote) mNote = NONE; } break; } case IMidiMsg::kControlChange: switch (pMsg->ControlChangeIdx()) { case IMidiMsg::kChannelVolume: mVolume = pMsg->ControlChange(IMidiMsg::kChannelVolume); break; case IMidiMsg::kAllNotesOff: if (mNote != NONE || mPhase != 0.) { mNote = NONE; mPhase = 0.; } break; } break; } // Delete the MIDI message we've just handled from the queue. mMidiQueue.Remove(); } // Now that the MIDI messages have been handled we are ready to // generate a sample of audio. if (mNote == NONE) { *output++ = 0.; } else // if (mNote != NONE) { double gain = mVolume; if (mVelocity) gain *= mGain; // Output a (non-band-limited) square wave. double phase = mPhase * mFreq; if (phase - floor(phase) < 0.50) // 50% duty cycle *output++ = +gain; else *output++ = -gain; } mPhase += mSamplePeriod; } // Try to keep the phase below 1. if (mNote == NONE && mPhase >= 1.) mPhase -= floor(mPhase); // Update the offsets of any MIDI messages still in the queue. mMidiQueue.Flush(nFrames); }
void Sequence::rebuild() { int held = keymap_.held(); playLength_ = held * octaves_; if (arpMode_ == kUpDown && (held*octaves_ > 2)) { playLength_ += playLength_ - 2; } if (insertMode_ == kInsertLow || insertMode_ == kInsertHi) { playLength_ *= 2; } if (playLength_ > length()) { sequence.resize(playLength_); } // clear all notes, reset position if none held if (held == 0) { for (int i=0; i < length(); ++i) { get(i)->MakeNoteOffMsg(0, 0); } pos = 0; } else { std::vector<IMidiMsg> input = keymap_.sortedEvents(); IMidiMsg loNote = input.front(); IMidiMsg hiNote = input.back(); hiNote.MakeNoteOnMsg(hiNote.NoteNumber() + 12*(octaves_-1), hiNote.Velocity(), hiNote.mOffset); if (arpMode_ == kUp || arpMode_ == kDown || arpMode_ == kUpDown) { if (arpMode_ == kDown) { std::reverse(input.begin(), input.end()); } } else { // default others to manual for now input = keymap_.events; } int iLast; for (int oct=0; oct < octaves_; ++oct) { int noteOffset = (arpMode_ == kDown) ? ((octaves_-1)*12 - oct*12) : oct*12; for (int i=0; i < held; ++i) { IMidiMsg* inp = &(input[i % held]); iLast = i + oct*held; get(iLast)->MakeNoteOnMsg(inp->NoteNumber() + noteOffset, inp->Velocity(), inp->mOffset); } } // Mirror the ascending sequence to produce an up/down sequence int iNext = iLast+1; if (arpMode_ == kUpDown) { while (--iLast > 0) { IMidiMsg* lastMsg = get(iLast); get(iNext++)->MakeNoteOnMsg(lastMsg->NoteNumber(), lastMsg->Velocity(), lastMsg->mOffset); } } if (insertMode_ == kInsertLow || insertMode_ == kInsertHi) { IMidiMsg& insertNote = (insertMode_ == kInsertLow) ? loNote : hiNote; // XXX change to using a member buffer instead of instantiating every time std::vector<IMidiMsg> seqcopy = sequence; int idx = 0; std::vector<IMidiMsg>::iterator prev = seqcopy.begin() + (playLength_/2 - 1); for (std::vector<IMidiMsg>::iterator it = seqcopy.begin(); it != seqcopy.begin() + (playLength_/2); ++it) { if (it->NoteNumber() != insertNote.NoteNumber() && prev->NoteNumber() != insertNote.NoteNumber()) { sequence[idx++] = insertNote; } sequence[idx++] = *it; prev = it; } playLength_ = idx; } } }
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); }