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.

191 lines
6.1KB

  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. BEGIN_JUCE_NAMESPACE
  19. //==============================================================================
  20. MidiKeyboardState::MidiKeyboardState()
  21. {
  22. zerostruct (noteStates);
  23. }
  24. MidiKeyboardState::~MidiKeyboardState()
  25. {
  26. }
  27. //==============================================================================
  28. void MidiKeyboardState::reset()
  29. {
  30. const ScopedLock sl (lock);
  31. zerostruct (noteStates);
  32. eventsToAdd.clear();
  33. }
  34. bool MidiKeyboardState::isNoteOn (const int midiChannel, const int n) const noexcept
  35. {
  36. jassert (midiChannel >= 0 && midiChannel <= 16);
  37. return isPositiveAndBelow (n, (int) 128)
  38. && (noteStates[n] & (1 << (midiChannel - 1))) != 0;
  39. }
  40. bool MidiKeyboardState::isNoteOnForChannels (const int midiChannelMask, const int n) const noexcept
  41. {
  42. return isPositiveAndBelow (n, (int) 128)
  43. && (noteStates[n] & midiChannelMask) != 0;
  44. }
  45. void MidiKeyboardState::noteOn (const int midiChannel, const int midiNoteNumber, const float velocity)
  46. {
  47. jassert (midiChannel >= 0 && midiChannel <= 16);
  48. jassert (isPositiveAndBelow (midiNoteNumber, (int) 128));
  49. const ScopedLock sl (lock);
  50. if (isPositiveAndBelow (midiNoteNumber, (int) 128))
  51. {
  52. const int timeNow = (int) Time::getMillisecondCounter();
  53. eventsToAdd.addEvent (MidiMessage::noteOn (midiChannel, midiNoteNumber, velocity), timeNow);
  54. eventsToAdd.clear (0, timeNow - 500);
  55. noteOnInternal (midiChannel, midiNoteNumber, velocity);
  56. }
  57. }
  58. void MidiKeyboardState::noteOnInternal (const int midiChannel, const int midiNoteNumber, const float velocity)
  59. {
  60. if (isPositiveAndBelow (midiNoteNumber, (int) 128))
  61. {
  62. noteStates [midiNoteNumber] |= (1 << (midiChannel - 1));
  63. for (int i = listeners.size(); --i >= 0;)
  64. listeners.getUnchecked(i)->handleNoteOn (this, midiChannel, midiNoteNumber, velocity);
  65. }
  66. }
  67. void MidiKeyboardState::noteOff (const int midiChannel, const int midiNoteNumber)
  68. {
  69. const ScopedLock sl (lock);
  70. if (isNoteOn (midiChannel, midiNoteNumber))
  71. {
  72. const int timeNow = (int) Time::getMillisecondCounter();
  73. eventsToAdd.addEvent (MidiMessage::noteOff (midiChannel, midiNoteNumber), timeNow);
  74. eventsToAdd.clear (0, timeNow - 500);
  75. noteOffInternal (midiChannel, midiNoteNumber);
  76. }
  77. }
  78. void MidiKeyboardState::noteOffInternal (const int midiChannel, const int midiNoteNumber)
  79. {
  80. if (isNoteOn (midiChannel, midiNoteNumber))
  81. {
  82. noteStates [midiNoteNumber] &= ~(1 << (midiChannel - 1));
  83. for (int i = listeners.size(); --i >= 0;)
  84. listeners.getUnchecked(i)->handleNoteOff (this, midiChannel, midiNoteNumber);
  85. }
  86. }
  87. void MidiKeyboardState::allNotesOff (const int midiChannel)
  88. {
  89. const ScopedLock sl (lock);
  90. if (midiChannel <= 0)
  91. {
  92. for (int i = 1; i <= 16; ++i)
  93. allNotesOff (i);
  94. }
  95. else
  96. {
  97. for (int i = 0; i < 128; ++i)
  98. noteOff (midiChannel, i);
  99. }
  100. }
  101. void MidiKeyboardState::processNextMidiEvent (const MidiMessage& message)
  102. {
  103. if (message.isNoteOn())
  104. {
  105. noteOnInternal (message.getChannel(), message.getNoteNumber(), message.getFloatVelocity());
  106. }
  107. else if (message.isNoteOff())
  108. {
  109. noteOffInternal (message.getChannel(), message.getNoteNumber());
  110. }
  111. else if (message.isAllNotesOff())
  112. {
  113. for (int i = 0; i < 128; ++i)
  114. noteOffInternal (message.getChannel(), i);
  115. }
  116. }
  117. void MidiKeyboardState::processNextMidiBuffer (MidiBuffer& buffer,
  118. const int startSample,
  119. const int numSamples,
  120. const bool injectIndirectEvents)
  121. {
  122. MidiBuffer::Iterator i (buffer);
  123. MidiMessage message (0xf4, 0.0);
  124. int time;
  125. const ScopedLock sl (lock);
  126. while (i.getNextEvent (message, time))
  127. processNextMidiEvent (message);
  128. if (injectIndirectEvents)
  129. {
  130. MidiBuffer::Iterator i2 (eventsToAdd);
  131. const int firstEventToAdd = eventsToAdd.getFirstEventTime();
  132. const double scaleFactor = numSamples / (double) (eventsToAdd.getLastEventTime() + 1 - firstEventToAdd);
  133. while (i2.getNextEvent (message, time))
  134. {
  135. const int pos = jlimit (0, numSamples - 1, roundToInt ((time - firstEventToAdd) * scaleFactor));
  136. buffer.addEvent (message, startSample + pos);
  137. }
  138. }
  139. eventsToAdd.clear();
  140. }
  141. //==============================================================================
  142. void MidiKeyboardState::addListener (MidiKeyboardStateListener* const listener)
  143. {
  144. const ScopedLock sl (lock);
  145. listeners.addIfNotAlreadyThere (listener);
  146. }
  147. void MidiKeyboardState::removeListener (MidiKeyboardStateListener* const listener)
  148. {
  149. const ScopedLock sl (lock);
  150. listeners.removeValue (listener);
  151. }
  152. END_JUCE_NAMESPACE