| 38 | } |
| 39 | |
| 40 | void NoteOutput::PlayNoteInternal(double time, int pitch, int velocity, int voiceIdx, ModulationParameters modulation, bool isFromMainThreadAndScheduled) |
| 41 | { |
| 42 | if (!IsAudioThread()) |
| 43 | { |
| 44 | if (!isFromMainThreadAndScheduled) //if we specifically scheduled this ahead of time, there's no need to make adjustments. otherwise, account for immediately requesting a note from the non-audio thread |
| 45 | { |
| 46 | time += TheTransport->GetEventLookaheadMs(); |
| 47 | if (velocity == 0) |
| 48 | time += gBufferSizeMs; //1 buffer later, to make sure notes get cleared |
| 49 | } |
| 50 | TheSynth->GetNoteOutputQueue()->QueuePlayNote(this, time, pitch, velocity, voiceIdx, modulation); |
| 51 | return; |
| 52 | } |
| 53 | |
| 54 | const int kMaxDepth = 100; |
| 55 | if (mStackDepth > kMaxDepth) |
| 56 | { |
| 57 | TheSynth->LogEvent("note chain hit max stack depth", kLogEventType_Error); |
| 58 | return; //avoid stack overflow |
| 59 | } |
| 60 | ++mStackDepth; |
| 61 | |
| 62 | if (pitch >= 0 && pitch <= 127) |
| 63 | { |
| 64 | for (auto noteReceiver : mNoteSource->GetPatchCableSource()->GetNoteReceivers()) |
| 65 | noteReceiver->PlayNote(time, pitch, velocity, voiceIdx, modulation); |
| 66 | |
| 67 | if (velocity > 0) |
| 68 | { |
| 69 | mNoteOnTimes[pitch] = time; |
| 70 | mNotes[pitch] = true; |
| 71 | } |
| 72 | else |
| 73 | { |
| 74 | if (time > mNoteOnTimes[pitch]) |
| 75 | mNotes[pitch] = false; |
| 76 | } |
| 77 | |
| 78 | mNoteSource->GetPatchCableSource()->AddHistoryEvent(time, HasHeldNotes()); |
| 79 | } |
| 80 | } |
| 81 | |
| 82 | void NoteOutput::SendPressure(int pitch, int pressure) |
| 83 | { |
no test coverage detected