Audio plugin host https://kx.studio/carla
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.

juce_MidiKeyboardState.cpp 5.9KB

9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2015 - ROLI Ltd.
  5. Permission is granted to use this software under the terms of either:
  6. a) the GPL v2 (or any later version)
  7. b) the Affero GPL v3
  8. Details of these licenses can be found at: www.gnu.org/licenses
  9. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  11. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  12. ------------------------------------------------------------------------------
  13. To release a closed-source product which uses JUCE, commercial licenses are
  14. available: visit www.juce.com for more information.
  15. ==============================================================================
  16. */
  17. MidiKeyboardState::MidiKeyboardState()
  18. {
  19. zerostruct (noteStates);
  20. }
  21. MidiKeyboardState::~MidiKeyboardState()
  22. {
  23. }
  24. //==============================================================================
  25. void MidiKeyboardState::reset()
  26. {
  27. const ScopedLock sl (lock);
  28. zerostruct (noteStates);
  29. eventsToAdd.clear();
  30. }
  31. bool MidiKeyboardState::isNoteOn (const int midiChannel, const int n) const noexcept
  32. {
  33. jassert (midiChannel >= 0 && midiChannel <= 16);
  34. return isPositiveAndBelow (n, (int) 128)
  35. && (noteStates[n] & (1 << (midiChannel - 1))) != 0;
  36. }
  37. bool MidiKeyboardState::isNoteOnForChannels (const int midiChannelMask, const int n) const noexcept
  38. {
  39. return isPositiveAndBelow (n, (int) 128)
  40. && (noteStates[n] & midiChannelMask) != 0;
  41. }
  42. void MidiKeyboardState::noteOn (const int midiChannel, const int midiNoteNumber, const float velocity)
  43. {
  44. jassert (midiChannel >= 0 && midiChannel <= 16);
  45. jassert (isPositiveAndBelow (midiNoteNumber, (int) 128));
  46. const ScopedLock sl (lock);
  47. if (isPositiveAndBelow (midiNoteNumber, (int) 128))
  48. {
  49. const int timeNow = (int) Time::getMillisecondCounter();
  50. eventsToAdd.addEvent (MidiMessage::noteOn (midiChannel, midiNoteNumber, velocity), timeNow);
  51. eventsToAdd.clear (0, timeNow - 500);
  52. noteOnInternal (midiChannel, midiNoteNumber, velocity);
  53. }
  54. }
  55. void MidiKeyboardState::noteOnInternal (const int midiChannel, const int midiNoteNumber, const float velocity)
  56. {
  57. if (isPositiveAndBelow (midiNoteNumber, (int) 128))
  58. {
  59. noteStates [midiNoteNumber] |= (1 << (midiChannel - 1));
  60. for (int i = listeners.size(); --i >= 0;)
  61. listeners.getUnchecked(i)->handleNoteOn (this, midiChannel, midiNoteNumber, velocity);
  62. }
  63. }
  64. void MidiKeyboardState::noteOff (const int midiChannel, const int midiNoteNumber, const float velocity)
  65. {
  66. const ScopedLock sl (lock);
  67. if (isNoteOn (midiChannel, midiNoteNumber))
  68. {
  69. const int timeNow = (int) Time::getMillisecondCounter();
  70. eventsToAdd.addEvent (MidiMessage::noteOff (midiChannel, midiNoteNumber), timeNow);
  71. eventsToAdd.clear (0, timeNow - 500);
  72. noteOffInternal (midiChannel, midiNoteNumber, velocity);
  73. }
  74. }
  75. void MidiKeyboardState::noteOffInternal (const int midiChannel, const int midiNoteNumber, const float velocity)
  76. {
  77. if (isNoteOn (midiChannel, midiNoteNumber))
  78. {
  79. noteStates [midiNoteNumber] &= ~(1 << (midiChannel - 1));
  80. for (int i = listeners.size(); --i >= 0;)
  81. listeners.getUnchecked(i)->handleNoteOff (this, midiChannel, midiNoteNumber, velocity);
  82. }
  83. }
  84. void MidiKeyboardState::allNotesOff (const int midiChannel)
  85. {
  86. const ScopedLock sl (lock);
  87. if (midiChannel <= 0)
  88. {
  89. for (int i = 1; i <= 16; ++i)
  90. allNotesOff (i);
  91. }
  92. else
  93. {
  94. for (int i = 0; i < 128; ++i)
  95. noteOff (midiChannel, i, 0.0f);
  96. }
  97. }
  98. void MidiKeyboardState::processNextMidiEvent (const MidiMessage& message)
  99. {
  100. if (message.isNoteOn())
  101. {
  102. noteOnInternal (message.getChannel(), message.getNoteNumber(), message.getFloatVelocity());
  103. }
  104. else if (message.isNoteOff())
  105. {
  106. noteOffInternal (message.getChannel(), message.getNoteNumber(), message.getFloatVelocity());
  107. }
  108. else if (message.isAllNotesOff())
  109. {
  110. for (int i = 0; i < 128; ++i)
  111. noteOffInternal (message.getChannel(), i, 0.0f);
  112. }
  113. }
  114. void MidiKeyboardState::processNextMidiBuffer (MidiBuffer& buffer,
  115. const int startSample,
  116. const int numSamples,
  117. const bool injectIndirectEvents)
  118. {
  119. MidiBuffer::Iterator i (buffer);
  120. MidiMessage message;
  121. int time;
  122. const ScopedLock sl (lock);
  123. while (i.getNextEvent (message, time))
  124. processNextMidiEvent (message);
  125. if (injectIndirectEvents)
  126. {
  127. MidiBuffer::Iterator i2 (eventsToAdd);
  128. const int firstEventToAdd = eventsToAdd.getFirstEventTime();
  129. const double scaleFactor = numSamples / (double) (eventsToAdd.getLastEventTime() + 1 - firstEventToAdd);
  130. while (i2.getNextEvent (message, time))
  131. {
  132. const int pos = jlimit (0, numSamples - 1, roundToInt ((time - firstEventToAdd) * scaleFactor));
  133. buffer.addEvent (message, startSample + pos);
  134. }
  135. }
  136. eventsToAdd.clear();
  137. }
  138. //==============================================================================
  139. void MidiKeyboardState::addListener (MidiKeyboardStateListener* const listener)
  140. {
  141. const ScopedLock sl (lock);
  142. listeners.addIfNotAlreadyThere (listener);
  143. }
  144. void MidiKeyboardState::removeListener (MidiKeyboardStateListener* const listener)
  145. {
  146. const ScopedLock sl (lock);
  147. listeners.removeFirstMatchingValue (listener);
  148. }