| 305 | } |
| 306 | |
| 307 | void MidiController::OnTransportAdvanced(float amount) |
| 308 | { |
| 309 | PROFILER(MidiController); |
| 310 | |
| 311 | mQueuedMessageMutex.lock(); |
| 312 | |
| 313 | double firstNoteTimestampMs = -1; |
| 314 | double lastPlayTime = -1; |
| 315 | for (auto note = mQueuedNotes.begin(); note != mQueuedNotes.end(); ++note) |
| 316 | { |
| 317 | int voiceIdx = -1; |
| 318 | |
| 319 | if (mUseChannelAsVoice) |
| 320 | voiceIdx = note->mChannel - 1; |
| 321 | |
| 322 | //TODO(Ryan) how can I use note->mTimestamp to get more accurate timing for midi input? |
| 323 | //this here is not accurate, but prevents notes played within the same buffer from having the exact same time |
| 324 | double playTime; |
| 325 | if (firstNoteTimestampMs == -1) //this is the first note |
| 326 | { |
| 327 | firstNoteTimestampMs = note->mTimestampMs; |
| 328 | playTime = gTime; |
| 329 | } |
| 330 | else |
| 331 | { |
| 332 | playTime = gTime + (note->mTimestampMs - firstNoteTimestampMs); |
| 333 | if (playTime <= lastPlayTime) |
| 334 | playTime += .01; //hack to handle note on/off in the same frame |
| 335 | } |
| 336 | lastPlayTime = playTime; |
| 337 | PlayNoteOutput(playTime, note->mPitch + mNoteOffset, MIN(127, note->mVelocity * mVelocityMult), voiceIdx, ModulationParameters(mModulation.GetPitchBend(voiceIdx), mModulation.GetModWheel(voiceIdx), mModulation.GetPressure(voiceIdx), 0)); |
| 338 | |
| 339 | for (auto i = mListeners[mControllerPage].begin(); i != mListeners[mControllerPage].end(); ++i) |
| 340 | (*i)->OnMidiNote(*note); |
| 341 | } |
| 342 | mQueuedNotes.clear(); |
| 343 | |
| 344 | for (auto ctrl = mQueuedControls.begin(); ctrl != mQueuedControls.end(); ++ctrl) |
| 345 | { |
| 346 | if (mSendCCOutput) |
| 347 | { |
| 348 | int voiceIdx = -1; |
| 349 | |
| 350 | if (mUseChannelAsVoice) |
| 351 | voiceIdx = ctrl->mChannel - 1; |
| 352 | |
| 353 | SendCCOutput(ctrl->mControl, ctrl->mValue, voiceIdx); |
| 354 | } |
| 355 | |
| 356 | for (auto i = mListeners[mControllerPage].begin(); i != mListeners[mControllerPage].end(); ++i) |
| 357 | (*i)->OnMidiControl(*ctrl); |
| 358 | } |
| 359 | mQueuedControls.clear(); |
| 360 | |
| 361 | for (auto note = mQueuedProgramChanges.begin(); note != mQueuedProgramChanges.end(); ++note) |
| 362 | { |
| 363 | for (auto i = mListeners[mControllerPage].begin(); i != mListeners[mControllerPage].end(); ++i) |
| 364 | (*i)->OnMidiProgramChange(*note); |
nothing calls this directly
no test coverage detected