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.

169 lines
4.0KB

  1. #include "MidiEditorContext.h"
  2. #include "MidiSelectionModel.h"
  3. #include "MidiSong.h"
  4. #include "TimeUtils.h"
  5. extern int _mdb;
  6. MidiEditorContext::MidiEditorContext(MidiSongPtr song) : _song(song)
  7. {
  8. ++_mdb;
  9. }
  10. MidiEditorContext::~MidiEditorContext()
  11. {
  12. --_mdb;
  13. }
  14. void MidiEditorContext::scrollViewportToCursorPitch()
  15. {
  16. while (m_cursorPitch < pitchLow()) {
  17. scrollVertically(-1 * PitchUtils::octave);
  18. }
  19. while (m_cursorPitch > pitchHi()) {
  20. scrollVertically(1 * PitchUtils::octave);
  21. }
  22. }
  23. void MidiEditorContext::assertCursorInViewport() const
  24. {
  25. assertGE(m_cursorTime, m_startTime);
  26. assertLT(m_cursorTime, m_endTime);
  27. assertGE(m_cursorPitch, m_pitchLow);
  28. assertLE(m_cursorPitch, m_pitchHi);
  29. }
  30. void MidiEditorContext::assertValid() const
  31. {
  32. assert(m_endTime > m_startTime);
  33. assert(m_pitchHi >= m_pitchLow);
  34. //assert(getSong());
  35. assertGE(m_cursorTime, 0);
  36. assertLT(m_cursorPitch, 10); // just for now
  37. assertGT(m_cursorPitch, -10);
  38. assertCursorInViewport();
  39. }
  40. void MidiEditorContext::scrollVertically(float pitchCV)
  41. {
  42. m_pitchHi += pitchCV;
  43. m_pitchLow += pitchCV;
  44. }
  45. MidiSongPtr MidiEditorContext::getSong() const
  46. {
  47. return _song.lock();
  48. }
  49. MidiEditorContext::iterator_pair MidiEditorContext::getEvents() const
  50. {
  51. iterator::filter_func lambda = [this](MidiTrack::const_iterator ii) {
  52. const MidiEventPtr me = ii->second;
  53. bool ret = false;
  54. MidiNoteEventPtr note = safe_cast<MidiNoteEvent>(me);
  55. if (note) {
  56. ret = note->pitchCV >= m_pitchLow && note->pitchCV <= m_pitchHi;
  57. }
  58. if (ret) {
  59. ret = me->startTime < this->m_endTime;
  60. }
  61. return ret;
  62. };
  63. const auto song = getSong();
  64. const auto track = song->getTrack(this->track);
  65. // raw will be pair of track::const_iterator
  66. const auto rawIterators = track->timeRange(this->m_startTime, this->m_endTime);
  67. return iterator_pair(iterator(rawIterators.first, rawIterators.second, lambda),
  68. iterator(rawIterators.second, rawIterators.second, lambda));
  69. }
  70. bool MidiEditorContext::cursorInViewport() const
  71. {
  72. if (m_cursorTime < m_startTime) {
  73. return false;
  74. }
  75. if (m_cursorTime >= m_endTime) {
  76. return false;
  77. }
  78. if (m_cursorPitch > m_pitchHi) {
  79. return false;
  80. }
  81. if (m_cursorPitch < m_pitchLow) {
  82. return false;
  83. }
  84. return true;
  85. }
  86. bool MidiEditorContext::cursorInViewportTime() const
  87. {
  88. if (m_cursorTime < m_startTime) {
  89. return false;
  90. }
  91. if (m_cursorTime >= m_endTime) {
  92. return false;
  93. }
  94. return true;
  95. }
  96. void MidiEditorContext::adjustViewportForCursor()
  97. {
  98. if (!cursorInViewportTime()) {
  99. float minimumAdvance = 0;
  100. if (m_cursorTime >= m_endTime) {
  101. minimumAdvance = m_cursorTime - m_endTime;
  102. } else if (m_cursorTime < m_startTime) {
  103. minimumAdvance = m_cursorTime - m_startTime;
  104. }
  105. // figure what fraction of 2 bars this is
  106. float advanceBars = minimumAdvance / TimeUtils::barToTime(2);
  107. advanceBars += (minimumAdvance < 0) ? -2 : 2;
  108. float x = std::round(advanceBars / 2.f);
  109. float finalAdvanceTime = x * TimeUtils::barToTime(2);
  110. m_startTime += finalAdvanceTime;
  111. m_endTime = m_startTime + TimeUtils::barToTime(2);
  112. assert(m_startTime >= 0);
  113. }
  114. // and to the pitch
  115. scrollViewportToCursorPitch();
  116. }
  117. MidiTrackPtr MidiEditorContext::getTrack()
  118. {
  119. MidiSongPtr song = getSong();
  120. assert(song);
  121. return song->getTrack(trackNumber);
  122. }
  123. void MidiEditorContext::setCursorToNote(MidiNoteEventPtrC note)
  124. {
  125. m_cursorTime = note->startTime;
  126. m_cursorPitch = note->pitchCV;
  127. adjustViewportForCursor();
  128. }
  129. void MidiEditorContext::setCursorToSelection(MidiSelectionModelPtr selection)
  130. {
  131. // could be wrong for multi-select
  132. if (!selection->empty()) {
  133. MidiEventPtr ev = *selection->begin();
  134. MidiNoteEventPtr note = safe_cast<MidiNoteEvent>(ev);
  135. assert(note);
  136. if (note) {
  137. setCursorToNote(note);
  138. }
  139. }
  140. }