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.

422 lines
10KB

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