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 8.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. #include "NotePool.h"
  2. //XXX eliminate dependence on Part.h
  3. #include "../Misc/Part.h"
  4. #include "../Misc/Allocator.h"
  5. #include "../Synth/SynthNote.h"
  6. #include <cstring>
  7. #include <cassert>
  8. #include <iostream>
  9. NotePool::NotePool(void)
  10. :needs_cleaning(0)
  11. {
  12. memset(ndesc, 0, sizeof(ndesc));
  13. memset(sdesc, 0, sizeof(sdesc));
  14. }
  15. NotePool::activeNotesIter NotePool::activeNotes(NoteDescriptor &n)
  16. {
  17. const int off_d1 = &n-ndesc;
  18. int off_d2 = 0;
  19. assert(off_d1 <= POLYPHONY);
  20. for(int i=0; i<off_d1; ++i)
  21. off_d2 += ndesc[i].size;
  22. return NotePool::activeNotesIter{sdesc+off_d2,sdesc+off_d2+n.size};
  23. }
  24. bool NotePool::NoteDescriptor::operator==(NoteDescriptor nd)
  25. {
  26. return age == nd.age && note == nd.note && sendto == nd.sendto && size == nd.size && status == nd.status;
  27. }
  28. //return either the first unused descriptor or the last valid descriptor which
  29. //matches note/sendto
  30. static int getMergeableDescriptor(uint8_t note, uint8_t sendto, bool legato,
  31. NotePool::NoteDescriptor *ndesc)
  32. {
  33. int desc_id = 0;
  34. for(int i=0; i<POLYPHONY; ++i, ++desc_id)
  35. if(ndesc[desc_id].status == Part::KEY_OFF)
  36. break;
  37. if(desc_id != 0) {
  38. auto &nd = ndesc[desc_id-1];
  39. if(nd.age == 0 && nd.note == note && nd.sendto == sendto
  40. && nd.status == Part::KEY_PLAYING && nd.legatoMirror == legato)
  41. return desc_id-1;
  42. }
  43. //Out of free descriptors
  44. if(desc_id >= POLYPHONY || ndesc[desc_id].status != Part::KEY_OFF) {
  45. return -1;
  46. }
  47. return desc_id;
  48. }
  49. NotePool::activeDescIter NotePool::activeDesc(void)
  50. {
  51. cleanup();
  52. return activeDescIter{*this};
  53. }
  54. NotePool::constActiveDescIter NotePool::activeDesc(void) const
  55. {
  56. const_cast<NotePool*>(this)->cleanup();
  57. return constActiveDescIter{*this};
  58. }
  59. void NotePool::insertNote(uint8_t note, uint8_t sendto, SynthDescriptor desc, bool legato)
  60. {
  61. //Get first free note descriptor
  62. int desc_id = getMergeableDescriptor(note, sendto, legato, ndesc);
  63. assert(desc_id != -1);
  64. ndesc[desc_id].note = note;
  65. ndesc[desc_id].sendto = sendto;
  66. ndesc[desc_id].size += 1;
  67. ndesc[desc_id].status = Part::KEY_PLAYING;
  68. ndesc[desc_id].legatoMirror = legato;
  69. //Get first free synth descriptor
  70. int sdesc_id = 0;
  71. while(sdesc[sdesc_id].note && sdesc_id < POLYPHONY*EXPECTED_USAGE)
  72. sdesc_id++;
  73. assert(sdesc_id < POLYPHONY*EXPECTED_USAGE);
  74. sdesc[sdesc_id] = desc;
  75. };
  76. void NotePool::upgradeToLegato(void)
  77. {
  78. for(auto &d:activeDesc())
  79. if(d.status == Part::KEY_PLAYING)
  80. for(auto &s:activeNotes(d))
  81. insertLegatoNote(d.note, d.sendto, s);
  82. }
  83. void NotePool::insertLegatoNote(uint8_t note, uint8_t sendto, SynthDescriptor desc)
  84. {
  85. assert(desc.note);
  86. try {
  87. desc.note = desc.note->cloneLegato();
  88. insertNote(note, sendto, desc, true);
  89. } catch (std::bad_alloc &ba) {
  90. std::cerr << "failed to insert legato note: " << ba.what() << std::endl;
  91. }
  92. };
  93. //There should only be one pair of notes which are still playing
  94. void NotePool::applyLegato(LegatoParams &par)
  95. {
  96. for(auto &desc:activeDesc()) {
  97. desc.note = par.midinote;
  98. for(auto &synth:activeNotes(desc))
  99. try {
  100. synth.note->legatonote(par);
  101. } catch (std::bad_alloc& ba) {
  102. std::cerr << "failed to create legato note: " << ba.what() << std::endl;
  103. }
  104. }
  105. };
  106. bool NotePool::full(void) const
  107. {
  108. for(int i=0; i<POLYPHONY; ++i)
  109. if(ndesc[i].status == Part::KEY_OFF)
  110. return false;
  111. return true;
  112. }
  113. bool NotePool::synthFull(int sdesc_count) const
  114. {
  115. int actually_free=sizeof(sdesc)/sizeof(sdesc[0]);
  116. for(const auto &desc:activeDesc()) {
  117. actually_free -= desc.size;
  118. }
  119. return actually_free < sdesc_count;
  120. }
  121. //Note that isn't KEY_PLAYING or KEY_RELASED_AND_SUSTAINING
  122. bool NotePool::existsRunningNote(void) const
  123. {
  124. //printf("runing note # =%d\n", getRunningNotes());
  125. return getRunningNotes();
  126. }
  127. int NotePool::getRunningNotes(void) const
  128. {
  129. bool running[256] = {0};
  130. for(auto &desc:activeDesc()) {
  131. //printf("note!(%d)\n", desc.note);
  132. if(desc.status == Part::KEY_PLAYING ||
  133. desc.status == Part::KEY_RELEASED_AND_SUSTAINED)
  134. running[desc.note] = true;
  135. }
  136. int running_count = 0;
  137. for(int i=0; i<256; ++i)
  138. running_count += running[i];
  139. return running_count;
  140. }
  141. int NotePool::enforceKeyLimit(int limit) const
  142. {
  143. //{
  144. //int oldestnotepos = -1;
  145. //if(notecount > keylimit) //find out the oldest note
  146. // for(int i = 0; i < POLYPHONY; ++i) {
  147. // int maxtime = 0;
  148. // if(((partnote[i].status == KEY_PLAYING) || (partnote[i].status == KEY_RELEASED_AND_SUSTAINED)) && (partnote[i].time > maxtime)) {
  149. // maxtime = partnote[i].time;
  150. // oldestnotepos = i;
  151. // }
  152. // }
  153. //if(oldestnotepos != -1)
  154. // ReleaseNotePos(oldestnotepos);
  155. //}
  156. //printf("Unimplemented enforceKeyLimit()\n");
  157. return -1;
  158. }
  159. void NotePool::releasePlayingNotes(void)
  160. {
  161. for(auto &d:activeDesc()) {
  162. if(d.status == Part::KEY_PLAYING) {
  163. d.status = Part::KEY_RELEASED;
  164. for(auto s:activeNotes(d))
  165. s.note->releasekey();
  166. }
  167. }
  168. }
  169. void NotePool::release(NoteDescriptor &d)
  170. {
  171. d.status = Part::KEY_RELEASED;
  172. for(auto s:activeNotes(d))
  173. s.note->releasekey();
  174. }
  175. void NotePool::killAllNotes(void)
  176. {
  177. for(auto &d:activeDesc())
  178. kill(d);
  179. }
  180. void NotePool::killNote(uint8_t note)
  181. {
  182. for(auto &d:activeDesc()) {
  183. if(d.note == note)
  184. kill(d);
  185. }
  186. }
  187. void NotePool::kill(NoteDescriptor &d)
  188. {
  189. d.status = Part::KEY_OFF;
  190. for(auto &s:activeNotes(d))
  191. kill(s);
  192. }
  193. void NotePool::kill(SynthDescriptor &s)
  194. {
  195. //printf("Kill synth...\n");
  196. s.note->memory.dealloc(s.note);
  197. needs_cleaning = true;
  198. }
  199. const char *getStatus(int status_bits)
  200. {
  201. switch(status_bits)
  202. {
  203. case 0: return "OFF ";
  204. case 1: return "PLAY";
  205. case 2: return "SUST";
  206. case 3: return "RELA";
  207. default: return "INVD";
  208. }
  209. }
  210. void NotePool::cleanup(void)
  211. {
  212. if(!needs_cleaning)
  213. return;
  214. needs_cleaning = false;
  215. int new_length[POLYPHONY] = {0};
  216. int cur_length[POLYPHONY] = {0};
  217. //printf("Cleanup Start\n");
  218. //dump();
  219. //Identify the current length of all segments
  220. //and the lengths discarding invalid entries
  221. int last_valid_desc = 0;
  222. for(int i=0; i<POLYPHONY; ++i)
  223. if(ndesc[i].status != Part::KEY_OFF)
  224. last_valid_desc = i;
  225. //Find the real numbers of allocated notes
  226. {
  227. int cum_old = 0;
  228. for(int i=0; i<=last_valid_desc; ++i) {
  229. cur_length[i] = ndesc[i].size;
  230. for(int j=0; j<ndesc[i].size; ++j)
  231. new_length[i] += (bool)sdesc[cum_old++].note;
  232. }
  233. }
  234. //Move the note descriptors
  235. {
  236. int cum_new = 0;
  237. for(int i=0; i<=last_valid_desc; ++i) {
  238. ndesc[i].size = new_length[i];
  239. if(new_length[i] != 0)
  240. ndesc[cum_new++] = ndesc[i];
  241. else
  242. ndesc[i].status = Part::KEY_OFF;
  243. }
  244. memset(ndesc+cum_new, 0, sizeof(*ndesc)*(POLYPHONY-cum_new));
  245. }
  246. //Move the synth descriptors
  247. {
  248. int total_notes=0;
  249. for(int i=0; i<=last_valid_desc; ++i)
  250. total_notes+=cur_length[i];
  251. int cum_new = 0;
  252. for(int i=0; i<total_notes; ++i)
  253. if(sdesc[i].note)
  254. sdesc[cum_new++] = sdesc[i];
  255. memset(sdesc+cum_new, 0, sizeof(*sdesc)*(POLYPHONY*EXPECTED_USAGE-cum_new));
  256. }
  257. //printf("Cleanup Done\n");
  258. //dump();
  259. }
  260. void NotePool::dump(void)
  261. {
  262. printf("NotePool::dump<\n");
  263. const char *format =
  264. " Note %d:%d age(%d) note(%d) sendto(%d) status(%s) legato(%d) type(%d) kit(%d) ptr(%p)\n";
  265. int note_id=0;
  266. int descriptor_id=0;
  267. for(auto &d:activeDesc()) {
  268. descriptor_id += 1;
  269. for(auto &s:activeNotes(d)) {
  270. note_id += 1;
  271. printf(format,
  272. note_id, descriptor_id,
  273. d.age, d.note, d.sendto,
  274. getStatus(d.status), d.legatoMirror, s.type, s.kit, s.note);
  275. }
  276. }
  277. printf(">NotePool::dump\n");
  278. }