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

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