The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
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
6.0KB

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