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.

314 lines
10KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCETICE project - Copyright 2008 by Lucio Asnaghi.
  4. JUCETICE is based around the JUCE library - "Jules' Utility Class Extensions"
  5. Copyright 2008 by Julian Storer.
  6. ------------------------------------------------------------------------------
  7. JUCE and JUCETICE can be redistributed and/or modified under the terms of
  8. the GNU Lesser General Public License, as published by the Free Software
  9. Foundation; either version 2 of the License, or (at your option) any later
  10. version.
  11. JUCE and JUCETICE are distributed in the hope that they will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. GNU General Public License for more details.
  15. You should have received a copy of the GNU Lesser General Public License
  16. along with JUCE and JUCETICE; if not, visit www.gnu.org/licenses or write to
  17. Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  18. Boston, MA 02111-1307 USA
  19. ==============================================================================
  20. @author rockhardbuns
  21. @tweaker Lucio Asnaghi
  22. ==============================================================================
  23. */
  24. #ifndef __JUCETICE_VEXCARP_HEADER__
  25. #define __JUCETICE_VEXCARP_HEADER__
  26. #include "cArpSettings.h"
  27. #ifdef CARLA_EXPORT
  28. #include "juce_audio_basics.h"
  29. #else
  30. #include "../StandardHeader.h"
  31. #endif
  32. class VexArp
  33. {
  34. public:
  35. static const int kMaxNotes = 10;
  36. VexArp(const VexArpSettings* p)
  37. : arpSet(p),
  38. dead(true),
  39. notesPlaying(false),
  40. doSync(true),
  41. nextStep(0),
  42. sampleCount(0),
  43. sampleRate(44100)
  44. {
  45. meter[0] = 4;
  46. meter[1] = 8;
  47. meter[2] = 16;
  48. meter[3] = 32;
  49. for (int i = 0; i < kMaxNotes; ++i)
  50. {
  51. cKeysDown[i] = 0;
  52. cNotesToKill[i] = 0;
  53. cKeysVelocity[i] = 0;
  54. }
  55. outMidiBuffer.ensureSize(kMaxNotes+128);
  56. }
  57. void addNote(const char note, const char vel)
  58. {
  59. char tmp, tmpNote = note, tmpVel = vel;
  60. for (int i = 0; i < kMaxNotes; ++i)
  61. {
  62. if (note < cKeysDown[i] || cKeysDown[i] == 0)
  63. {
  64. tmp = cKeysDown[i]; cKeysDown[i] = tmpNote; tmpNote = tmp;
  65. tmp = cKeysVelocity[i]; cKeysVelocity[i] = tmpVel; tmpVel = tmp;
  66. }
  67. }
  68. doSync = true;
  69. }
  70. void dropNote(const char note)
  71. {
  72. int i = 0;
  73. for (; i < kMaxNotes; ++i)
  74. {
  75. if (cKeysDown[i] == note)
  76. break;
  77. }
  78. if (i == kMaxNotes)
  79. return;
  80. for (; i < kMaxNotes-1; ++i)
  81. {
  82. cKeysDown[i] = cKeysDown[i+1];
  83. cKeysVelocity[i] = cKeysVelocity[i+1];
  84. }
  85. cKeysDown[kMaxNotes-1] = 0;
  86. cKeysVelocity[kMaxNotes-1] = 0;
  87. }
  88. void killThisNoteLater(const char note)
  89. {
  90. for (int i = 0; i < kMaxNotes; ++i)
  91. {
  92. if (cNotesToKill[i] == note)
  93. break;
  94. if (cNotesToKill[i] == 0)
  95. {
  96. cNotesToKill[i] = note;
  97. break;
  98. }
  99. }
  100. }
  101. void setSampleRate(const int srate)
  102. {
  103. sampleRate = srate;
  104. }
  105. const MidiBuffer& processMidi(MidiBuffer& inMidiBuffer, const bool isPlaying,
  106. const double ppqPosition,
  107. const double ppqPositionOfLastBarStart,
  108. const double bpm,
  109. const int numSamples)
  110. {
  111. const int timeSig = meter[arpSet->timeMode];
  112. // Loop though the midibuffer, take away note on/off, let the rest pass
  113. {
  114. outMidiBuffer.clear();
  115. MidiBuffer::Iterator inBufferIterator(inMidiBuffer);
  116. MidiMessage midiMessage(0xf4);
  117. int sampleNumber;
  118. while (inBufferIterator.getNextEvent(midiMessage, sampleNumber))
  119. {
  120. if (midiMessage.isNoteOn())
  121. addNote(midiMessage.getNoteNumber(), midiMessage.getVelocity());
  122. else if(midiMessage.isNoteOff())
  123. dropNote(midiMessage.getNoteNumber());
  124. else
  125. outMidiBuffer.addEvent(midiMessage, sampleNumber);
  126. }
  127. }
  128. // BarSync
  129. const unsigned int samplesPerStep = int((60.0 / bpm) * sampleRate * 4) / timeSig;
  130. if (isPlaying && arpSet->syncMode == 2)
  131. {
  132. if (doSync)
  133. {
  134. //offset sample count
  135. sampleCount = int((ppqPosition - ppqPositionOfLastBarStart) * ((60 / bpm) * sampleRate));
  136. //offset step count
  137. nextStep = sampleCount / samplesPerStep;
  138. //Cycle the counts
  139. sampleCount = (sampleCount % samplesPerStep) + samplesPerStep - 10;
  140. nextStep = nextStep % arpSet->length;
  141. }
  142. doSync = false;
  143. }
  144. else
  145. {
  146. doSync = true;
  147. }
  148. //***************************
  149. if (cKeysDown[0])
  150. { //Keys are down
  151. dead = false;
  152. sampleCount += numSamples;
  153. bool repeat = false;
  154. do
  155. {
  156. repeat = false;
  157. //***
  158. if (sampleCount >= samplesPerStep)
  159. { //Play step
  160. int offset = numSamples - (sampleCount - samplesPerStep);
  161. bool doFail = true;
  162. for (int i = 0; i < 5; ++i)
  163. {
  164. if((cKeysDown[i]!= 0) && (arpSet->grid[nextStep*5 + i]))
  165. { //we have a note to play
  166. int vel;
  167. switch (arpSet->velMode)
  168. {
  169. case 1:
  170. vel = roundFloatToInt (arpSet->velocities[nextStep] * 127.0f);
  171. break;
  172. case 2:
  173. vel = (int) cKeysVelocity[i];
  174. break;
  175. case 3:
  176. vel = (int) cKeysVelocity[i] + roundFloatToInt (arpSet->velocities[nextStep] * 127.0f);
  177. break;
  178. default:
  179. vel = 127;
  180. break;
  181. }
  182. doFail = false;
  183. notesPlaying = true;
  184. killThisNoteLater(cKeysDown[i]);
  185. outMidiBuffer.addEvent(MidiMessage::noteOn(1, cKeysDown[i], uint8(vel)), offset);
  186. }
  187. }
  188. if (doFail)
  189. {
  190. switch (arpSet->failMode)
  191. {
  192. case 1: //normal
  193. sampleCount -= samplesPerStep;
  194. nextStep++;
  195. nextStep = nextStep % arpSet->length;
  196. break;
  197. case 2: //skip one
  198. //SampleCount -= SamplesPerStep;
  199. nextStep++;
  200. nextStep = nextStep % arpSet->length;
  201. repeat = true;
  202. break;
  203. case 3: //skip two
  204. //SampleCount -= SamplesPerStep;
  205. nextStep += 2;
  206. nextStep = nextStep % arpSet->length;
  207. repeat = true;
  208. break;
  209. }
  210. }
  211. else
  212. {
  213. sampleCount -= samplesPerStep;
  214. nextStep++;
  215. nextStep = nextStep % arpSet->length; //Cycle the steps over pattern length
  216. }
  217. }
  218. } while (repeat);
  219. //***
  220. unsigned int NoteLength = (samplesPerStep / 4) * 3;
  221. if ((sampleCount >= NoteLength) && notesPlaying)
  222. { //Mute step
  223. int offset = numSamples - (sampleCount - NoteLength);
  224. //***
  225. for(int i = 0; i < kMaxNotes; ++i)
  226. {
  227. if (cNotesToKill[i] != 0)
  228. { //do we have a note to kill?
  229. outMidiBuffer.addEvent(MidiMessage::noteOff(1, cNotesToKill[i]), offset);
  230. cNotesToKill[i] = 0;
  231. }
  232. }
  233. notesPlaying = false;
  234. }
  235. //***
  236. }
  237. else if (! dead)
  238. { //No keys pressed - kill 'em all
  239. for (int i = 0; i < kMaxNotes; ++i)
  240. {
  241. if (cNotesToKill[i] != 0)
  242. { //do we have a note to kill?
  243. outMidiBuffer.addEvent(MidiMessage::noteOff(1, cNotesToKill[i]), 0);
  244. cNotesToKill[i] = 0;
  245. }
  246. }
  247. nextStep = 0;
  248. sampleCount = samplesPerStep;
  249. dead = true;
  250. }
  251. return outMidiBuffer;
  252. }
  253. private:
  254. const VexArpSettings* arpSet;
  255. MidiBuffer outMidiBuffer;
  256. bool dead, notesPlaying, doSync;
  257. unsigned int nextStep;
  258. unsigned int sampleCount, sampleRate;
  259. int meter[4];
  260. char cKeysDown[kMaxNotes];
  261. char cKeysVelocity[kMaxNotes];
  262. char cNotesToKill[kMaxNotes];
  263. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(VexArp)
  264. };
  265. #endif