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.

303 lines
11KB

  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. namespace
  18. {
  19. void checkAndLimitZoneParameters (int minValue,
  20. int maxValue,
  21. int& valueToCheckAndLimit) noexcept
  22. {
  23. if (valueToCheckAndLimit < minValue || valueToCheckAndLimit > maxValue)
  24. {
  25. // if you hit this, one of the parameters you supplied for MPEZone
  26. // was not within the allowed range!
  27. // we fit this back into the allowed range here to maintain a valid
  28. // state for the zone, but probably the resulting zone is not what you
  29. //wanted it to be!
  30. jassertfalse;
  31. valueToCheckAndLimit = jlimit (minValue, maxValue, valueToCheckAndLimit);
  32. }
  33. }
  34. }
  35. //==============================================================================
  36. MPEZone::MPEZone (int masterChannel_,
  37. int numNoteChannels_,
  38. int perNotePitchbendRange_,
  39. int masterPitchbendRange_) noexcept
  40. : masterChannel (masterChannel_),
  41. numNoteChannels (numNoteChannels_),
  42. perNotePitchbendRange (perNotePitchbendRange_),
  43. masterPitchbendRange (masterPitchbendRange_)
  44. {
  45. checkAndLimitZoneParameters (1, 15, masterChannel);
  46. checkAndLimitZoneParameters (1, 16 - masterChannel, numNoteChannels);
  47. checkAndLimitZoneParameters (0, 96, perNotePitchbendRange);
  48. checkAndLimitZoneParameters (0, 96, masterPitchbendRange);
  49. }
  50. //==============================================================================
  51. int MPEZone::getMasterChannel() const noexcept
  52. {
  53. return masterChannel;
  54. }
  55. int MPEZone::getNumNoteChannels() const noexcept
  56. {
  57. return numNoteChannels;
  58. }
  59. int MPEZone::getFirstNoteChannel() const noexcept
  60. {
  61. return masterChannel + 1;
  62. }
  63. int MPEZone::getLastNoteChannel() const noexcept
  64. {
  65. return masterChannel + numNoteChannels;
  66. }
  67. Range<int> MPEZone::getNoteChannelRange() const noexcept
  68. {
  69. return Range<int>::withStartAndLength (getFirstNoteChannel(), getNumNoteChannels());
  70. }
  71. bool MPEZone::isUsingChannel (int channel) const noexcept
  72. {
  73. jassert (channel > 0 && channel <= 16);
  74. return channel >= masterChannel && channel <= masterChannel + numNoteChannels;
  75. }
  76. bool MPEZone::isUsingChannelAsNoteChannel (int channel) const noexcept
  77. {
  78. jassert (channel > 0 && channel <= 16);
  79. return channel > masterChannel && channel <= masterChannel + numNoteChannels;
  80. }
  81. int MPEZone::getPerNotePitchbendRange() const noexcept
  82. {
  83. return perNotePitchbendRange;
  84. }
  85. int MPEZone::getMasterPitchbendRange() const noexcept
  86. {
  87. return masterPitchbendRange;
  88. }
  89. void MPEZone::setPerNotePitchbendRange (int rangeInSemitones) noexcept
  90. {
  91. checkAndLimitZoneParameters (0, 96, rangeInSemitones);
  92. perNotePitchbendRange = rangeInSemitones;
  93. }
  94. void MPEZone::setMasterPitchbendRange (int rangeInSemitones) noexcept
  95. {
  96. checkAndLimitZoneParameters (0, 96, rangeInSemitones);
  97. masterPitchbendRange = rangeInSemitones;
  98. }
  99. //==============================================================================
  100. bool MPEZone::overlapsWith (MPEZone other) const noexcept
  101. {
  102. if (masterChannel == other.masterChannel)
  103. return true;
  104. if (masterChannel > other.masterChannel)
  105. return other.overlapsWith (*this);
  106. return masterChannel + numNoteChannels >= other.masterChannel;
  107. }
  108. //==============================================================================
  109. bool MPEZone::truncateToFit (MPEZone other) noexcept
  110. {
  111. const int masterChannelDiff = other.masterChannel - masterChannel;
  112. // we need at least 2 channels to be left after truncation:
  113. // 1 master channel and 1 note channel. otherwise we can't truncate.
  114. if (masterChannelDiff < 2)
  115. return false;
  116. numNoteChannels = jmin (numNoteChannels, masterChannelDiff - 1);
  117. return true;
  118. }
  119. //==============================================================================
  120. //==============================================================================
  121. #if JUCE_UNIT_TESTS
  122. class MPEZoneTests : public UnitTest
  123. {
  124. public:
  125. MPEZoneTests() : UnitTest ("MPEZone class") {}
  126. void runTest() override
  127. {
  128. beginTest ("initialisation");
  129. {
  130. {
  131. MPEZone zone (1, 10);
  132. expectEquals (zone.getMasterChannel(), 1);
  133. expectEquals (zone.getNumNoteChannels(), 10);
  134. expectEquals (zone.getFirstNoteChannel(), 2);
  135. expectEquals (zone.getLastNoteChannel(), 11);
  136. expectEquals (zone.getPerNotePitchbendRange(), 48);
  137. expectEquals (zone.getMasterPitchbendRange(), 2);
  138. expect (zone.isUsingChannel (1));
  139. expect (zone.isUsingChannel (2));
  140. expect (zone.isUsingChannel (10));
  141. expect (zone.isUsingChannel (11));
  142. expect (! zone.isUsingChannel (12));
  143. expect (! zone.isUsingChannel (16));
  144. expect (! zone.isUsingChannelAsNoteChannel (1));
  145. expect (zone.isUsingChannelAsNoteChannel (2));
  146. expect (zone.isUsingChannelAsNoteChannel (10));
  147. expect (zone.isUsingChannelAsNoteChannel (11));
  148. expect (! zone.isUsingChannelAsNoteChannel (12));
  149. expect (! zone.isUsingChannelAsNoteChannel (16));
  150. }
  151. {
  152. MPEZone zone (5, 4);
  153. expectEquals (zone.getMasterChannel(), 5);
  154. expectEquals (zone.getNumNoteChannels(), 4);
  155. expectEquals (zone.getFirstNoteChannel(), 6);
  156. expectEquals (zone.getLastNoteChannel(), 9);
  157. expectEquals (zone.getPerNotePitchbendRange(), 48);
  158. expectEquals (zone.getMasterPitchbendRange(), 2);
  159. expect (! zone.isUsingChannel (1));
  160. expect (! zone.isUsingChannel (4));
  161. expect (zone.isUsingChannel (5));
  162. expect (zone.isUsingChannel (6));
  163. expect (zone.isUsingChannel (8));
  164. expect (zone.isUsingChannel (9));
  165. expect (! zone.isUsingChannel (10));
  166. expect (! zone.isUsingChannel (16));
  167. expect (! zone.isUsingChannelAsNoteChannel (5));
  168. expect (zone.isUsingChannelAsNoteChannel (6));
  169. expect (zone.isUsingChannelAsNoteChannel (8));
  170. expect (zone.isUsingChannelAsNoteChannel (9));
  171. expect (! zone.isUsingChannelAsNoteChannel (10));
  172. }
  173. }
  174. beginTest ("getNoteChannelRange");
  175. {
  176. MPEZone zone (2, 10);
  177. Range<int> noteChannelRange = zone.getNoteChannelRange();
  178. expectEquals (noteChannelRange.getStart(), 3);
  179. expectEquals (noteChannelRange.getEnd(), 13);
  180. }
  181. beginTest ("setting master pitchbend range");
  182. {
  183. MPEZone zone (1, 10);
  184. zone.setMasterPitchbendRange (96);
  185. expectEquals (zone.getMasterPitchbendRange(), 96);
  186. zone.setMasterPitchbendRange (0);
  187. expectEquals (zone.getMasterPitchbendRange(), 0);
  188. expectEquals (zone.getPerNotePitchbendRange(), 48);
  189. }
  190. beginTest ("setting per-note pitchbend range");
  191. {
  192. MPEZone zone (1, 10);
  193. zone.setPerNotePitchbendRange (96);
  194. expectEquals (zone.getPerNotePitchbendRange(), 96);
  195. zone.setPerNotePitchbendRange (0);
  196. expectEquals (zone.getPerNotePitchbendRange(), 0);
  197. expectEquals (zone.getMasterPitchbendRange(), 2);
  198. }
  199. beginTest ("checking overlap");
  200. {
  201. testOverlapsWith (1, 10, 1, 10, true);
  202. testOverlapsWith (1, 4, 6, 3, false);
  203. testOverlapsWith (1, 4, 8, 3, false);
  204. testOverlapsWith (2, 10, 2, 8, true);
  205. testOverlapsWith (1, 10, 3, 2, true);
  206. testOverlapsWith (3, 10, 5, 9, true);
  207. }
  208. beginTest ("truncating");
  209. {
  210. testTruncateToFit (1, 10, 3, 10, true, 1, 1);
  211. testTruncateToFit (3, 10, 1, 10, false, 3, 10);
  212. testTruncateToFit (1, 10, 5, 8, true, 1, 3);
  213. testTruncateToFit (5, 8, 1, 10, false, 5, 8);
  214. testTruncateToFit (1, 10, 4, 3, true, 1, 2);
  215. testTruncateToFit (4, 3, 1, 10, false, 4, 3);
  216. testTruncateToFit (1, 3, 5, 3, true, 1, 3);
  217. testTruncateToFit (5, 3, 1, 3, false, 5, 3);
  218. testTruncateToFit (1, 3, 7, 3, true, 1, 3);
  219. testTruncateToFit (7, 3, 1, 3, false, 7, 3);
  220. testTruncateToFit (1, 10, 2, 10, false, 1, 10);
  221. testTruncateToFit (2, 10, 1, 10, false, 2, 10);
  222. }
  223. }
  224. private:
  225. //==========================================================================
  226. void testOverlapsWith (int masterChannelFirst, int numNoteChannelsFirst,
  227. int masterChannelSecond, int numNoteChannelsSecond,
  228. bool expectedRetVal)
  229. {
  230. MPEZone first (masterChannelFirst, numNoteChannelsFirst);
  231. MPEZone second (masterChannelSecond, numNoteChannelsSecond);
  232. expect (first.overlapsWith (second) == expectedRetVal);
  233. expect (second.overlapsWith (first) == expectedRetVal);
  234. }
  235. //==========================================================================
  236. void testTruncateToFit (int masterChannelFirst, int numNoteChannelsFirst,
  237. int masterChannelSecond, int numNoteChannelsSecond,
  238. bool expectedRetVal,
  239. int masterChannelFirstAfter, int numNoteChannelsFirstAfter)
  240. {
  241. MPEZone first (masterChannelFirst, numNoteChannelsFirst);
  242. MPEZone second (masterChannelSecond, numNoteChannelsSecond);
  243. expect (first.truncateToFit (second) == expectedRetVal);
  244. expectEquals (first.getMasterChannel(), masterChannelFirstAfter);
  245. expectEquals (first.getNumNoteChannels(), numNoteChannelsFirstAfter);
  246. }
  247. };
  248. static MPEZoneTests MPEZoneUnitTests;
  249. #endif // JUCE_UNIT_TESTS