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.

317 lines
12KB

  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. bool MPEZone::operator== (const MPEZone& other) const noexcept
  121. {
  122. return masterChannel == other.masterChannel
  123. && numNoteChannels == other.numNoteChannels
  124. && perNotePitchbendRange == other.perNotePitchbendRange
  125. && masterPitchbendRange == other.masterPitchbendRange;
  126. }
  127. bool MPEZone::operator!= (const MPEZone& other) const noexcept
  128. {
  129. return ! operator== (other);
  130. }
  131. //==============================================================================
  132. //==============================================================================
  133. #if JUCE_UNIT_TESTS
  134. class MPEZoneTests : public UnitTest
  135. {
  136. public:
  137. MPEZoneTests() : UnitTest ("MPEZone class") {}
  138. void runTest() override
  139. {
  140. beginTest ("initialisation");
  141. {
  142. {
  143. MPEZone zone (1, 10);
  144. expectEquals (zone.getMasterChannel(), 1);
  145. expectEquals (zone.getNumNoteChannels(), 10);
  146. expectEquals (zone.getFirstNoteChannel(), 2);
  147. expectEquals (zone.getLastNoteChannel(), 11);
  148. expectEquals (zone.getPerNotePitchbendRange(), 48);
  149. expectEquals (zone.getMasterPitchbendRange(), 2);
  150. expect (zone.isUsingChannel (1));
  151. expect (zone.isUsingChannel (2));
  152. expect (zone.isUsingChannel (10));
  153. expect (zone.isUsingChannel (11));
  154. expect (! zone.isUsingChannel (12));
  155. expect (! zone.isUsingChannel (16));
  156. expect (! zone.isUsingChannelAsNoteChannel (1));
  157. expect (zone.isUsingChannelAsNoteChannel (2));
  158. expect (zone.isUsingChannelAsNoteChannel (10));
  159. expect (zone.isUsingChannelAsNoteChannel (11));
  160. expect (! zone.isUsingChannelAsNoteChannel (12));
  161. expect (! zone.isUsingChannelAsNoteChannel (16));
  162. }
  163. {
  164. MPEZone zone (5, 4);
  165. expectEquals (zone.getMasterChannel(), 5);
  166. expectEquals (zone.getNumNoteChannels(), 4);
  167. expectEquals (zone.getFirstNoteChannel(), 6);
  168. expectEquals (zone.getLastNoteChannel(), 9);
  169. expectEquals (zone.getPerNotePitchbendRange(), 48);
  170. expectEquals (zone.getMasterPitchbendRange(), 2);
  171. expect (! zone.isUsingChannel (1));
  172. expect (! zone.isUsingChannel (4));
  173. expect (zone.isUsingChannel (5));
  174. expect (zone.isUsingChannel (6));
  175. expect (zone.isUsingChannel (8));
  176. expect (zone.isUsingChannel (9));
  177. expect (! zone.isUsingChannel (10));
  178. expect (! zone.isUsingChannel (16));
  179. expect (! zone.isUsingChannelAsNoteChannel (5));
  180. expect (zone.isUsingChannelAsNoteChannel (6));
  181. expect (zone.isUsingChannelAsNoteChannel (8));
  182. expect (zone.isUsingChannelAsNoteChannel (9));
  183. expect (! zone.isUsingChannelAsNoteChannel (10));
  184. }
  185. }
  186. beginTest ("getNoteChannelRange");
  187. {
  188. MPEZone zone (2, 10);
  189. Range<int> noteChannelRange = zone.getNoteChannelRange();
  190. expectEquals (noteChannelRange.getStart(), 3);
  191. expectEquals (noteChannelRange.getEnd(), 13);
  192. }
  193. beginTest ("setting master pitchbend range");
  194. {
  195. MPEZone zone (1, 10);
  196. zone.setMasterPitchbendRange (96);
  197. expectEquals (zone.getMasterPitchbendRange(), 96);
  198. zone.setMasterPitchbendRange (0);
  199. expectEquals (zone.getMasterPitchbendRange(), 0);
  200. expectEquals (zone.getPerNotePitchbendRange(), 48);
  201. }
  202. beginTest ("setting per-note pitchbend range");
  203. {
  204. MPEZone zone (1, 10);
  205. zone.setPerNotePitchbendRange (96);
  206. expectEquals (zone.getPerNotePitchbendRange(), 96);
  207. zone.setPerNotePitchbendRange (0);
  208. expectEquals (zone.getPerNotePitchbendRange(), 0);
  209. expectEquals (zone.getMasterPitchbendRange(), 2);
  210. }
  211. beginTest ("checking overlap");
  212. {
  213. testOverlapsWith (1, 10, 1, 10, true);
  214. testOverlapsWith (1, 4, 6, 3, false);
  215. testOverlapsWith (1, 4, 8, 3, false);
  216. testOverlapsWith (2, 10, 2, 8, true);
  217. testOverlapsWith (1, 10, 3, 2, true);
  218. testOverlapsWith (3, 10, 5, 9, true);
  219. }
  220. beginTest ("truncating");
  221. {
  222. testTruncateToFit (1, 10, 3, 10, true, 1, 1);
  223. testTruncateToFit (3, 10, 1, 10, false, 3, 10);
  224. testTruncateToFit (1, 10, 5, 8, true, 1, 3);
  225. testTruncateToFit (5, 8, 1, 10, false, 5, 8);
  226. testTruncateToFit (1, 10, 4, 3, true, 1, 2);
  227. testTruncateToFit (4, 3, 1, 10, false, 4, 3);
  228. testTruncateToFit (1, 3, 5, 3, true, 1, 3);
  229. testTruncateToFit (5, 3, 1, 3, false, 5, 3);
  230. testTruncateToFit (1, 3, 7, 3, true, 1, 3);
  231. testTruncateToFit (7, 3, 1, 3, false, 7, 3);
  232. testTruncateToFit (1, 10, 2, 10, false, 1, 10);
  233. testTruncateToFit (2, 10, 1, 10, false, 2, 10);
  234. }
  235. }
  236. private:
  237. //==============================================================================
  238. void testOverlapsWith (int masterChannelFirst, int numNoteChannelsFirst,
  239. int masterChannelSecond, int numNoteChannelsSecond,
  240. bool expectedRetVal)
  241. {
  242. MPEZone first (masterChannelFirst, numNoteChannelsFirst);
  243. MPEZone second (masterChannelSecond, numNoteChannelsSecond);
  244. expect (first.overlapsWith (second) == expectedRetVal);
  245. expect (second.overlapsWith (first) == expectedRetVal);
  246. }
  247. //==============================================================================
  248. void testTruncateToFit (int masterChannelFirst, int numNoteChannelsFirst,
  249. int masterChannelSecond, int numNoteChannelsSecond,
  250. bool expectedRetVal,
  251. int masterChannelFirstAfter, int numNoteChannelsFirstAfter)
  252. {
  253. MPEZone first (masterChannelFirst, numNoteChannelsFirst);
  254. MPEZone second (masterChannelSecond, numNoteChannelsSecond);
  255. expect (first.truncateToFit (second) == expectedRetVal);
  256. expectEquals (first.getMasterChannel(), masterChannelFirstAfter);
  257. expectEquals (first.getNumNoteChannels(), numNoteChannelsFirstAfter);
  258. }
  259. };
  260. static MPEZoneTests MPEZoneUnitTests;
  261. #endif // JUCE_UNIT_TESTS