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.

322 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. @tweaker falkTX
  23. ==============================================================================
  24. */
  25. #ifndef DISTRHO_VEX_ARP_HEADER_INCLUDED
  26. #define DISTRHO_VEX_ARP_HEADER_INCLUDED
  27. #include "VexArpSettings.h"
  28. #ifndef CARLA_EXPORT
  29. #define CARLA_EXPORT
  30. #endif
  31. #ifdef CARLA_EXPORT
  32. #include "juce_audio_basics.h"
  33. #else
  34. #include "../StandardHeader.h"
  35. #endif
  36. class VexArp
  37. {
  38. public:
  39. static const int kMaxNotes = 10;
  40. VexArp(const VexArpSettings* p)
  41. : arpSet(p),
  42. dead(true),
  43. notesPlaying(false),
  44. doSync(true),
  45. nextStep(0),
  46. sampleCount(0),
  47. sampleRate(44100)
  48. {
  49. meter[0] = 4;
  50. meter[1] = 8;
  51. meter[2] = 16;
  52. meter[3] = 32;
  53. for (int i = 0; i < kMaxNotes; ++i)
  54. {
  55. cKeysDown[i] = 0;
  56. cNotesToKill[i] = 0;
  57. cKeysVelocity[i] = 0;
  58. }
  59. outMidiBuffer.ensureSize(kMaxNotes+128);
  60. }
  61. void addNote(const char note, const char vel)
  62. {
  63. char tmp, tmpNote = note, tmpVel = vel;
  64. for (int i = 0; i < kMaxNotes; ++i)
  65. {
  66. if (note < cKeysDown[i] || cKeysDown[i] == 0)
  67. {
  68. tmp = cKeysDown[i]; cKeysDown[i] = tmpNote; tmpNote = tmp;
  69. tmp = cKeysVelocity[i]; cKeysVelocity[i] = tmpVel; tmpVel = tmp;
  70. }
  71. }
  72. doSync = true;
  73. }
  74. void dropNote(const char note)
  75. {
  76. int i = 0;
  77. for (; i < kMaxNotes; ++i)
  78. {
  79. if (cKeysDown[i] == note)
  80. break;
  81. }
  82. if (i == kMaxNotes)
  83. return;
  84. for (; i < kMaxNotes-1; ++i)
  85. {
  86. cKeysDown[i] = cKeysDown[i+1];
  87. cKeysVelocity[i] = cKeysVelocity[i+1];
  88. }
  89. cKeysDown[kMaxNotes-1] = 0;
  90. cKeysVelocity[kMaxNotes-1] = 0;
  91. }
  92. void killThisNoteLater(const char note)
  93. {
  94. for (int i = 0; i < kMaxNotes; ++i)
  95. {
  96. if (cNotesToKill[i] == note)
  97. break;
  98. if (cNotesToKill[i] == 0)
  99. {
  100. cNotesToKill[i] = note;
  101. break;
  102. }
  103. }
  104. }
  105. void setSampleRate(const int srate)
  106. {
  107. sampleRate = srate;
  108. }
  109. const MidiBuffer& processMidi(MidiBuffer& inMidiBuffer, const bool isPlaying,
  110. const double ppqPosition,
  111. const double ppqPositionOfLastBarStart,
  112. const double bpm,
  113. const int numSamples)
  114. {
  115. const int timeSig = meter[arpSet->timeMode];
  116. // Loop though the midibuffer, take away note on/off, let the rest pass
  117. {
  118. outMidiBuffer.clear();
  119. MidiBuffer::Iterator inBufferIterator(inMidiBuffer);
  120. MidiMessage midiMessage(0xf4);
  121. int samplePosition;
  122. while (inBufferIterator.getNextEvent(midiMessage, samplePosition))
  123. {
  124. if (midiMessage.isNoteOn())
  125. addNote(midiMessage.getNoteNumber(), midiMessage.getVelocity());
  126. else if (midiMessage.isNoteOff())
  127. dropNote(midiMessage.getNoteNumber());
  128. else
  129. outMidiBuffer.addEvent(midiMessage, samplePosition);
  130. }
  131. }
  132. const double beatsPerSec = (60.0 * double(sampleRate)) / bpm;
  133. // BarSync
  134. const unsigned int samplesPerStep = int(beatsPerSec * 4.0) / timeSig;
  135. if (isPlaying && arpSet->syncMode == 2) // bar sync
  136. {
  137. if (doSync)
  138. {
  139. //offset sample count
  140. sampleCount = int((ppqPosition - ppqPositionOfLastBarStart) * beatsPerSec);
  141. //offset step count
  142. nextStep = sampleCount / samplesPerStep;
  143. //Cycle the counts
  144. sampleCount = (sampleCount % samplesPerStep) + samplesPerStep - 10;
  145. nextStep = nextStep % arpSet->length;
  146. doSync = false;
  147. }
  148. }
  149. else
  150. {
  151. doSync = true;
  152. }
  153. //***************************
  154. if (cKeysDown[0])
  155. { // Keys are down
  156. dead = false;
  157. sampleCount += numSamples;
  158. bool repeat = false;
  159. do
  160. {
  161. repeat = false;
  162. //***
  163. if (sampleCount >= samplesPerStep)
  164. { //Play step
  165. int offset = numSamples - (sampleCount - samplesPerStep);
  166. bool doFail = true;
  167. for (int i = 0; i < 5; ++i)
  168. {
  169. if((cKeysDown[i]!= 0) && (arpSet->grid[nextStep*5 + i]))
  170. { // we have a note to play
  171. int vel;
  172. switch (arpSet->velMode)
  173. {
  174. case 1:
  175. vel = roundFloatToInt (arpSet->velocities[nextStep] * 127.0f);
  176. break;
  177. case 2:
  178. vel = (int) cKeysVelocity[i];
  179. break;
  180. case 3:
  181. vel = (int) cKeysVelocity[i] + roundFloatToInt (arpSet->velocities[nextStep] * 127.0f);
  182. break;
  183. default:
  184. vel = 127;
  185. break;
  186. }
  187. doFail = false;
  188. notesPlaying = true;
  189. killThisNoteLater(cKeysDown[i]);
  190. outMidiBuffer.addEvent(MidiMessage::noteOn(1, cKeysDown[i], uint8(vel)), offset);
  191. }
  192. }
  193. if (doFail)
  194. {
  195. switch (arpSet->failMode)
  196. {
  197. case 1: //normal
  198. sampleCount -= samplesPerStep;
  199. nextStep++;
  200. nextStep = nextStep % arpSet->length;
  201. break;
  202. case 2: //skip one
  203. //SampleCount -= SamplesPerStep;
  204. nextStep++;
  205. nextStep = nextStep % arpSet->length;
  206. repeat = true;
  207. break;
  208. case 3: //skip two
  209. //SampleCount -= SamplesPerStep;
  210. nextStep += 2;
  211. nextStep = nextStep % arpSet->length;
  212. repeat = true;
  213. break;
  214. }
  215. }
  216. else
  217. {
  218. sampleCount -= samplesPerStep;
  219. nextStep++;
  220. nextStep = nextStep % arpSet->length; //Cycle the steps over pattern length
  221. }
  222. }
  223. } while (repeat);
  224. //***
  225. unsigned int NoteLength = (samplesPerStep / 4) * 3;
  226. if ((sampleCount >= NoteLength) && notesPlaying)
  227. { //Mute step
  228. int offset = numSamples - (sampleCount - NoteLength);
  229. //***
  230. for(int i = 0; i < kMaxNotes; ++i)
  231. {
  232. if (cNotesToKill[i] != 0)
  233. { //do we have a note to kill?
  234. outMidiBuffer.addEvent(MidiMessage::noteOff(1, cNotesToKill[i]), offset);
  235. cNotesToKill[i] = 0;
  236. }
  237. }
  238. notesPlaying = false;
  239. }
  240. //***
  241. }
  242. else if (! dead)
  243. { //No keys pressed - kill 'em all
  244. for (int i = 0; i < kMaxNotes; ++i)
  245. {
  246. if (cNotesToKill[i] != 0)
  247. { //do we have a note to kill?
  248. outMidiBuffer.addEvent(MidiMessage::noteOff(1, cNotesToKill[i]), 0);
  249. cNotesToKill[i] = 0;
  250. }
  251. }
  252. nextStep = 0;
  253. sampleCount = samplesPerStep;
  254. dead = true;
  255. }
  256. return outMidiBuffer;
  257. }
  258. private:
  259. const VexArpSettings* arpSet;
  260. MidiBuffer outMidiBuffer;
  261. bool dead, notesPlaying, doSync; // doSync used only in bar-sync
  262. unsigned int nextStep;
  263. unsigned int sampleCount, sampleRate;
  264. int meter[4];
  265. char cKeysDown[kMaxNotes];
  266. char cKeysVelocity[kMaxNotes];
  267. char cNotesToKill[kMaxNotes];
  268. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(VexArp)
  269. };
  270. #endif // DISTRHO_VEX_ARP_HEADER_INCLUDED