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.

NotePool.cpp 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436
  1. /*
  2. ZynAddSubFX - a software synthesizer
  3. NotePool.cpp - Pool of Synthesizer Engines And Note Instances
  4. Copyright (C) 2016 Mark McCurry
  5. This program is free software; you can redistribute it and/or
  6. modify it under the terms of the GNU General Public License
  7. as published by the Free Software Foundation; either version 2
  8. of the License, or (at your option) any later version.
  9. */
  10. #include "NotePool.h"
  11. #include "../Misc/Allocator.h"
  12. #include "../Synth/SynthNote.h"
  13. #include <cstring>
  14. #include <cassert>
  15. #include <iostream>
  16. #define SUSTAIN_BIT 0x04
  17. #define NOTE_MASK 0x03
  18. namespace zyncarla {
  19. enum NoteStatus {
  20. KEY_OFF = 0x00,
  21. KEY_PLAYING = 0x01,
  22. KEY_RELEASED_AND_SUSTAINED = 0x02,
  23. KEY_RELEASED = 0x03
  24. };
  25. NotePool::NotePool(void)
  26. :needs_cleaning(0)
  27. {
  28. memset(ndesc, 0, sizeof(ndesc));
  29. memset(sdesc, 0, sizeof(sdesc));
  30. }
  31. bool NotePool::NoteDescriptor::playing(void) const
  32. {
  33. return (status&NOTE_MASK) == KEY_PLAYING;
  34. }
  35. bool NotePool::NoteDescriptor::sustained(void) const
  36. {
  37. return (status&NOTE_MASK) == KEY_RELEASED_AND_SUSTAINED;
  38. }
  39. bool NotePool::NoteDescriptor::released(void) const
  40. {
  41. return (status&NOTE_MASK) == KEY_RELEASED;
  42. }
  43. bool NotePool::NoteDescriptor::off(void) const
  44. {
  45. return (status&NOTE_MASK) == KEY_OFF;
  46. }
  47. void NotePool::NoteDescriptor::setStatus(uint8_t s)
  48. {
  49. status &= ~NOTE_MASK;
  50. status |= (NOTE_MASK&s);
  51. }
  52. void NotePool::NoteDescriptor::doSustain(void)
  53. {
  54. setStatus(KEY_RELEASED_AND_SUSTAINED);
  55. }
  56. bool NotePool::NoteDescriptor::canSustain(void) const
  57. {
  58. return !(status & SUSTAIN_BIT);
  59. }
  60. void NotePool::NoteDescriptor::makeUnsustainable(void)
  61. {
  62. status |= SUSTAIN_BIT;
  63. }
  64. NotePool::activeNotesIter NotePool::activeNotes(NoteDescriptor &n)
  65. {
  66. const int off_d1 = &n-ndesc;
  67. int off_d2 = 0;
  68. assert(off_d1 <= POLYPHONY);
  69. for(int i=0; i<off_d1; ++i)
  70. off_d2 += ndesc[i].size;
  71. return NotePool::activeNotesIter{sdesc+off_d2,sdesc+off_d2+n.size};
  72. }
  73. bool NotePool::NoteDescriptor::operator==(NoteDescriptor nd)
  74. {
  75. return age == nd.age && note == nd.note && sendto == nd.sendto && size == nd.size && status == nd.status;
  76. }
  77. //return either the first unused descriptor or the last valid descriptor which
  78. //matches note/sendto
  79. static int getMergeableDescriptor(uint8_t note, uint8_t sendto, bool legato,
  80. NotePool::NoteDescriptor *ndesc)
  81. {
  82. int desc_id = 0;
  83. for(int i=0; i<POLYPHONY; ++i, ++desc_id)
  84. if(ndesc[desc_id].off())
  85. break;
  86. if(desc_id != 0) {
  87. auto &nd = ndesc[desc_id-1];
  88. if(nd.age == 0 && nd.note == note && nd.sendto == sendto
  89. && nd.playing() && nd.legatoMirror == legato && nd.canSustain())
  90. return desc_id-1;
  91. }
  92. //Out of free descriptors
  93. if(desc_id >= POLYPHONY || !ndesc[desc_id].off()) {
  94. return -1;
  95. }
  96. return desc_id;
  97. }
  98. NotePool::activeDescIter NotePool::activeDesc(void)
  99. {
  100. cleanup();
  101. return activeDescIter{*this};
  102. }
  103. NotePool::constActiveDescIter NotePool::activeDesc(void) const
  104. {
  105. const_cast<NotePool*>(this)->cleanup();
  106. return constActiveDescIter{*this};
  107. }
  108. int NotePool::usedNoteDesc(void) const
  109. {
  110. if(needs_cleaning)
  111. const_cast<NotePool*>(this)->cleanup();
  112. int cnt = 0;
  113. for(int i=0; i<POLYPHONY; ++i)
  114. cnt += (ndesc[i].size != 0);
  115. return cnt;
  116. }
  117. int NotePool::usedSynthDesc(void) const
  118. {
  119. if(needs_cleaning)
  120. const_cast<NotePool*>(this)->cleanup();
  121. int cnt = 0;
  122. for(int i=0; i<POLYPHONY*EXPECTED_USAGE; ++i)
  123. cnt += (bool)sdesc[i].note;
  124. return cnt;
  125. }
  126. void NotePool::insertNote(uint8_t note, uint8_t sendto, SynthDescriptor desc, bool legato)
  127. {
  128. //Get first free note descriptor
  129. int desc_id = getMergeableDescriptor(note, sendto, legato, ndesc);
  130. assert(desc_id != -1);
  131. ndesc[desc_id].note = note;
  132. ndesc[desc_id].sendto = sendto;
  133. ndesc[desc_id].size += 1;
  134. ndesc[desc_id].status = KEY_PLAYING;
  135. ndesc[desc_id].legatoMirror = legato;
  136. //Get first free synth descriptor
  137. int sdesc_id = 0;
  138. while(sdesc[sdesc_id].note && sdesc_id < POLYPHONY*EXPECTED_USAGE)
  139. sdesc_id++;
  140. assert(sdesc_id < POLYPHONY*EXPECTED_USAGE);
  141. sdesc[sdesc_id] = desc;
  142. };
  143. void NotePool::upgradeToLegato(void)
  144. {
  145. for(auto &d:activeDesc())
  146. if(d.playing())
  147. for(auto &s:activeNotes(d))
  148. insertLegatoNote(d.note, d.sendto, s);
  149. }
  150. void NotePool::insertLegatoNote(uint8_t note, uint8_t sendto, SynthDescriptor desc)
  151. {
  152. assert(desc.note);
  153. try {
  154. desc.note = desc.note->cloneLegato();
  155. insertNote(note, sendto, desc, true);
  156. } catch (std::bad_alloc &ba) {
  157. std::cerr << "failed to insert legato note: " << ba.what() << std::endl;
  158. }
  159. };
  160. //There should only be one pair of notes which are still playing
  161. void NotePool::applyLegato(LegatoParams &par)
  162. {
  163. for(auto &desc:activeDesc()) {
  164. desc.note = par.midinote;
  165. for(auto &synth:activeNotes(desc))
  166. try {
  167. synth.note->legatonote(par);
  168. } catch (std::bad_alloc& ba) {
  169. std::cerr << "failed to create legato note: " << ba.what() << std::endl;
  170. }
  171. }
  172. }
  173. void NotePool::makeUnsustainable(uint8_t note)
  174. {
  175. for(auto &desc:activeDesc()) {
  176. if(desc.note == note) {
  177. desc.makeUnsustainable();
  178. if(desc.sustained())
  179. release(desc);
  180. }
  181. }
  182. }
  183. bool NotePool::full(void) const
  184. {
  185. for(int i=0; i<POLYPHONY; ++i)
  186. if(ndesc[i].off())
  187. return false;
  188. return true;
  189. }
  190. bool NotePool::synthFull(int sdesc_count) const
  191. {
  192. int actually_free=sizeof(sdesc)/sizeof(sdesc[0]);
  193. for(const auto &desc:activeDesc()) {
  194. actually_free -= desc.size;
  195. }
  196. return actually_free < sdesc_count;
  197. }
  198. //Note that isn't KEY_PLAYING or KEY_RELASED_AND_SUSTAINING
  199. bool NotePool::existsRunningNote(void) const
  200. {
  201. //printf("runing note # =%d\n", getRunningNotes());
  202. return getRunningNotes();
  203. }
  204. int NotePool::getRunningNotes(void) const
  205. {
  206. bool running[256] = {0};
  207. for(auto &desc:activeDesc()) {
  208. //printf("note!(%d)\n", desc.note);
  209. if(desc.playing() || desc.sustained())
  210. running[desc.note] = true;
  211. }
  212. int running_count = 0;
  213. for(int i=0; i<256; ++i)
  214. running_count += running[i];
  215. return running_count;
  216. }
  217. void NotePool::enforceKeyLimit(int limit)
  218. {
  219. int notes_to_kill = getRunningNotes() - limit;
  220. if(notes_to_kill <= 0)
  221. return;
  222. NoteDescriptor *to_kill = NULL;
  223. unsigned oldest = 0;
  224. for(auto &nd : activeDesc()) {
  225. if(to_kill == NULL) {
  226. //There must be something to kill
  227. oldest = nd.age;
  228. to_kill = &nd;
  229. } else if(to_kill->released() && nd.playing()) {
  230. //Prefer to kill off a running note
  231. oldest = nd.age;
  232. to_kill = &nd;
  233. } else if(nd.age > oldest && !(to_kill->playing() && nd.released())) {
  234. //Get an older note when it doesn't move from running to released
  235. oldest = nd.age;
  236. to_kill = &nd;
  237. }
  238. }
  239. if(to_kill) {
  240. auto &tk = *to_kill;
  241. if(tk.released() || tk.sustained())
  242. kill(*to_kill);
  243. else
  244. entomb(*to_kill);
  245. }
  246. }
  247. void NotePool::releasePlayingNotes(void)
  248. {
  249. for(auto &d:activeDesc()) {
  250. if(d.playing() || d.sustained()) {
  251. d.setStatus(KEY_RELEASED);
  252. for(auto s:activeNotes(d))
  253. s.note->releasekey();
  254. }
  255. }
  256. }
  257. void NotePool::release(NoteDescriptor &d)
  258. {
  259. d.setStatus(KEY_RELEASED);
  260. for(auto s:activeNotes(d))
  261. s.note->releasekey();
  262. }
  263. void NotePool::killAllNotes(void)
  264. {
  265. for(auto &d:activeDesc())
  266. kill(d);
  267. }
  268. void NotePool::killNote(uint8_t note)
  269. {
  270. for(auto &d:activeDesc()) {
  271. if(d.note == note)
  272. kill(d);
  273. }
  274. }
  275. void NotePool::kill(NoteDescriptor &d)
  276. {
  277. d.setStatus(KEY_OFF);
  278. for(auto &s:activeNotes(d))
  279. kill(s);
  280. }
  281. void NotePool::kill(SynthDescriptor &s)
  282. {
  283. //printf("Kill synth...\n");
  284. s.note->memory.dealloc(s.note);
  285. needs_cleaning = true;
  286. }
  287. void NotePool::entomb(NoteDescriptor &d)
  288. {
  289. d.setStatus(KEY_RELEASED);
  290. for(auto &s:activeNotes(d))
  291. s.note->entomb();
  292. }
  293. const char *getStatus(int status_bits)
  294. {
  295. switch(status_bits)
  296. {
  297. case 0: return "OFF ";
  298. case 1: return "PLAY";
  299. case 2: return "SUST";
  300. case 3: return "RELA";
  301. default: return "INVD";
  302. }
  303. }
  304. void NotePool::cleanup(void)
  305. {
  306. if(!needs_cleaning)
  307. return;
  308. needs_cleaning = false;
  309. int new_length[POLYPHONY] = {0};
  310. int cur_length[POLYPHONY] = {0};
  311. //printf("Cleanup Start\n");
  312. //dump();
  313. //Identify the current length of all segments
  314. //and the lengths discarding invalid entries
  315. int last_valid_desc = 0;
  316. for(int i=0; i<POLYPHONY; ++i)
  317. if(!ndesc[i].off())
  318. last_valid_desc = i;
  319. //Find the real numbers of allocated notes
  320. {
  321. int cum_old = 0;
  322. for(int i=0; i<=last_valid_desc; ++i) {
  323. cur_length[i] = ndesc[i].size;
  324. for(int j=0; j<ndesc[i].size; ++j)
  325. new_length[i] += (bool)sdesc[cum_old++].note;
  326. }
  327. }
  328. //Move the note descriptors
  329. {
  330. int cum_new = 0;
  331. for(int i=0; i<=last_valid_desc; ++i) {
  332. ndesc[i].size = new_length[i];
  333. if(new_length[i] != 0)
  334. ndesc[cum_new++] = ndesc[i];
  335. else
  336. ndesc[i].setStatus(KEY_OFF);
  337. }
  338. memset(ndesc+cum_new, 0, sizeof(*ndesc)*(POLYPHONY-cum_new));
  339. }
  340. //Move the synth descriptors
  341. {
  342. int total_notes=0;
  343. for(int i=0; i<=last_valid_desc; ++i)
  344. total_notes+=cur_length[i];
  345. int cum_new = 0;
  346. for(int i=0; i<total_notes; ++i)
  347. if(sdesc[i].note)
  348. sdesc[cum_new++] = sdesc[i];
  349. memset(sdesc+cum_new, 0, sizeof(*sdesc)*(POLYPHONY*EXPECTED_USAGE-cum_new));
  350. }
  351. //printf("Cleanup Done\n");
  352. //dump();
  353. }
  354. void NotePool::dump(void)
  355. {
  356. printf("NotePool::dump<\n");
  357. const char *format =
  358. " Note %d:%d age(%d) note(%d) sendto(%d) status(%s) legato(%d) type(%d) kit(%d) ptr(%p)\n";
  359. int note_id=0;
  360. int descriptor_id=0;
  361. for(auto &d:activeDesc()) {
  362. descriptor_id += 1;
  363. for(auto &s:activeNotes(d)) {
  364. note_id += 1;
  365. printf(format,
  366. note_id, descriptor_id,
  367. d.age, d.note, d.sendto,
  368. getStatus(d.status), d.legatoMirror, s.type, s.kit, s.note);
  369. }
  370. }
  371. printf(">NotePool::dump\n");
  372. }
  373. }