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.

VexArp.h 10KB

11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  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