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.

160 lines
5.6KB

  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. MidiMessageCollector::MidiMessageCollector()
  21. : lastCallbackTime (0),
  22. sampleRate (44100.0001)
  23. {
  24. }
  25. MidiMessageCollector::~MidiMessageCollector()
  26. {
  27. }
  28. //==============================================================================
  29. void MidiMessageCollector::reset (const double sampleRate_)
  30. {
  31. jassert (sampleRate_ > 0);
  32. const ScopedLock sl (midiCallbackLock);
  33. sampleRate = sampleRate_;
  34. incomingMessages.clear();
  35. lastCallbackTime = Time::getMillisecondCounterHiRes();
  36. }
  37. void MidiMessageCollector::addMessageToQueue (const MidiMessage& message)
  38. {
  39. // you need to call reset() to set the correct sample rate before using this object
  40. jassert (sampleRate != 44100.0001);
  41. // the messages that come in here need to be time-stamped correctly - see MidiInput
  42. // for details of what the number should be.
  43. jassert (message.getTimeStamp() != 0);
  44. const ScopedLock sl (midiCallbackLock);
  45. const int sampleNumber
  46. = (int) ((message.getTimeStamp() - 0.001 * lastCallbackTime) * sampleRate);
  47. incomingMessages.addEvent (message, sampleNumber);
  48. // if the messages don't get used for over a second, we'd better
  49. // get rid of any old ones to avoid the queue getting too big
  50. if (sampleNumber > sampleRate)
  51. incomingMessages.clear (0, sampleNumber - (int) sampleRate);
  52. }
  53. void MidiMessageCollector::removeNextBlockOfMessages (MidiBuffer& destBuffer,
  54. const int numSamples)
  55. {
  56. // you need to call reset() to set the correct sample rate before using this object
  57. jassert (sampleRate != 44100.0001);
  58. const double timeNow = Time::getMillisecondCounterHiRes();
  59. const double msElapsed = timeNow - lastCallbackTime;
  60. const ScopedLock sl (midiCallbackLock);
  61. lastCallbackTime = timeNow;
  62. if (! incomingMessages.isEmpty())
  63. {
  64. int numSourceSamples = jmax (1, roundToInt (msElapsed * 0.001 * sampleRate));
  65. int startSample = 0;
  66. int scale = 1 << 16;
  67. const uint8* midiData;
  68. int numBytes, samplePosition;
  69. MidiBuffer::Iterator iter (incomingMessages);
  70. if (numSourceSamples > numSamples)
  71. {
  72. // if our list of events is longer than the buffer we're being
  73. // asked for, scale them down to squeeze them all in..
  74. const int maxBlockLengthToUse = numSamples << 5;
  75. if (numSourceSamples > maxBlockLengthToUse)
  76. {
  77. startSample = numSourceSamples - maxBlockLengthToUse;
  78. numSourceSamples = maxBlockLengthToUse;
  79. iter.setNextSamplePosition (startSample);
  80. }
  81. scale = (numSamples << 10) / numSourceSamples;
  82. while (iter.getNextEvent (midiData, numBytes, samplePosition))
  83. {
  84. samplePosition = ((samplePosition - startSample) * scale) >> 10;
  85. destBuffer.addEvent (midiData, numBytes,
  86. jlimit (0, numSamples - 1, samplePosition));
  87. }
  88. }
  89. else
  90. {
  91. // if our event list is shorter than the number we need, put them
  92. // towards the end of the buffer
  93. startSample = numSamples - numSourceSamples;
  94. while (iter.getNextEvent (midiData, numBytes, samplePosition))
  95. {
  96. destBuffer.addEvent (midiData, numBytes,
  97. jlimit (0, numSamples - 1, samplePosition + startSample));
  98. }
  99. }
  100. incomingMessages.clear();
  101. }
  102. }
  103. //==============================================================================
  104. void MidiMessageCollector::handleNoteOn (MidiKeyboardState*, int midiChannel, int midiNoteNumber, float velocity)
  105. {
  106. MidiMessage m (MidiMessage::noteOn (midiChannel, midiNoteNumber, velocity));
  107. m.setTimeStamp (Time::getMillisecondCounterHiRes() * 0.001);
  108. addMessageToQueue (m);
  109. }
  110. void MidiMessageCollector::handleNoteOff (MidiKeyboardState*, int midiChannel, int midiNoteNumber)
  111. {
  112. MidiMessage m (MidiMessage::noteOff (midiChannel, midiNoteNumber));
  113. m.setTimeStamp (Time::getMillisecondCounterHiRes() * 0.001);
  114. addMessageToQueue (m);
  115. }
  116. void MidiMessageCollector::handleIncomingMidiMessage (MidiInput*, const MidiMessage& message)
  117. {
  118. addMessageToQueue (message);
  119. }
  120. END_JUCE_NAMESPACE