You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

185 lines
4.9KB

  1. #include "MidiLock.h"
  2. #include "MidiPlayer.h"
  3. #include "MidiSong.h"
  4. MidiPlayer::MidiPlayer(std::shared_ptr<IPlayerHost> host, std::shared_ptr<MidiSong> song) :
  5. host(host), song(song), trackPlayer(song->getTrack(0))
  6. {
  7. ++_mdb;
  8. }
  9. void MidiPlayer::timeElapsed(float seconds)
  10. {
  11. curMetricTime += seconds * 120.0f / 60.0f; // fixed at 120 bpm for now
  12. if (!isPlaying) {
  13. return;
  14. }
  15. bool locked = song->lock->playerTryLock();
  16. if (locked) {
  17. if (song->lock->dataModelDirty()) {
  18. trackPlayer.reset();
  19. }
  20. trackPlayer.updateToMetricTime(curMetricTime, host.get());
  21. song->lock->playerUnlock();
  22. } else {
  23. trackPlayer.reset();
  24. host->onLockFailed();
  25. }
  26. }
  27. TrackPlayer::TrackPlayer(MidiTrackPtr track) : track(track)
  28. {
  29. }
  30. TrackPlayer::~TrackPlayer()
  31. {
  32. //curEvent = nullptr;
  33. }
  34. void TrackPlayer::updateToMetricTime(double time, IPlayerHost* host)
  35. {
  36. // If we had a conflict and needed to reset, then
  37. // start all over from beginning
  38. if (isReset) {
  39. curEvent = curEvent = track->begin();
  40. noteOffTime = -1;
  41. isReset = false;
  42. loopStart = 0;
  43. }
  44. // keep processing events until we are caught up
  45. while (playOnce(time, host)) {
  46. }
  47. }
  48. bool TrackPlayer::playOnce(double metricTime, IPlayerHost* host)
  49. {
  50. bool didSomething = false;
  51. if (noteOffTime >= 0 && noteOffTime <= metricTime) {
  52. host->setGate(false);
  53. noteOffTime = -1;
  54. didSomething = true;
  55. }
  56. const double eventStart = (loopStart + curEvent->first);
  57. if (eventStart <= metricTime) {
  58. MidiEventPtr event = curEvent->second;
  59. switch (event->type) {
  60. case MidiEvent::Type::Note:
  61. {
  62. MidiNoteEventPtr note = safe_cast<MidiNoteEvent>(event);
  63. // should now output the note.
  64. host->setGate(true);
  65. host->setCV(note->pitchCV);
  66. // and save off the note-off time.
  67. noteOffTime = note->duration + eventStart;
  68. ++curEvent;
  69. }
  70. break;
  71. case MidiEvent::Type::End:
  72. // for now, should loop.
  73. // uh oh!
  74. // assert(false);
  75. // curMetricTime = 0;
  76. // trackPlayStatus.curEvent = song->getTrack(0)->begin();
  77. loopStart += curEvent->first;
  78. curEvent = track->begin();
  79. break;
  80. default:
  81. assert(false);
  82. }
  83. didSomething = true;
  84. }
  85. return didSomething;
  86. }
  87. #if 0
  88. void MidiPlayer::timeElapsed(float seconds)
  89. {
  90. curMetricTime += seconds * 120.0f / 60.0f; // fixed at 120 bpm for now
  91. bool locked = song->lock->playerTryLock();
  92. if (locked) {
  93. while (playOnce()) {
  94. }
  95. song->lock->playerUnlock();
  96. } else {
  97. trackPlayStatus.reset();
  98. host->onLockFailed();
  99. }
  100. }
  101. bool MidiPlayer::playOnce()
  102. {
  103. if (!isPlaying) {
  104. return false;
  105. }
  106. bool didSomething = false;
  107. // If we had a conflict and needed to reset, then
  108. // seek from the start to where we should be.
  109. if (trackPlayStatus.isReset) {
  110. trackPlayStatus.seekTo(song.get(), curMetricTime, host.get());
  111. return true;
  112. }
  113. if (trackPlayStatus.noteOffTime >= 0 && trackPlayStatus.noteOffTime <= curMetricTime) {
  114. host->setGate(false);
  115. trackPlayStatus.noteOffTime = -1;
  116. didSomething = true;
  117. }
  118. if (trackPlayStatus.curEvent->first <= curMetricTime) {
  119. MidiEventPtr event = trackPlayStatus.curEvent->second;
  120. switch (event->type) {
  121. case MidiEvent::Type::Note:
  122. {
  123. MidiNoteEventPtr note = safe_cast<MidiNoteEvent>(event);
  124. // should now output the note.
  125. host->setGate(true);
  126. host->setCV(note->pitchCV);
  127. // and save off the note-off time.
  128. trackPlayStatus.noteOffTime = note->duration + note->startTime;
  129. ++trackPlayStatus.curEvent;
  130. }
  131. break;
  132. case MidiEvent::Type::End:
  133. // for now, should loop.
  134. curMetricTime = 0;
  135. trackPlayStatus.curEvent = song->getTrack(0)->begin();
  136. break;
  137. default:
  138. assert(false);
  139. }
  140. didSomething = true;
  141. }
  142. return didSomething;
  143. }
  144. void TrackPlayStatus::seekTo(MidiSong* song, float time, IPlayerHost* host)
  145. {
  146. isReset = false;
  147. curEvent = song->getTrack(0)->begin();
  148. while (curEvent->second->startTime < time) {
  149. ++curEvent;
  150. if (curEvent == song->getTrack(0)->end()) {
  151. assert(false);
  152. return;
  153. }
  154. MidiEventPtr evt = curEvent->second;
  155. MidiNoteEventPtr note = safe_cast< MidiNoteEvent>(evt);
  156. assert(note);
  157. noteOffTime = note->startTime + note->duration;
  158. }
  159. }
  160. #endif