NotePool.cpp (17480B)
1 /* 2 ZynAddSubFX - a software synthesizer 3 4 NotePool.cpp - Pool of Synthesizer Engines And Note Instances 5 Copyright (C) 2016 Mark McCurry 6 7 This program is free software; you can redistribute it and/or 8 modify it under the terms of the GNU General Public License 9 as published by the Free Software Foundation; either version 2 10 of the License, or (at your option) any later version. 11 */ 12 #include "NotePool.h" 13 #include "../Misc/Allocator.h" 14 #include "../Synth/Portamento.h" 15 #include "../Synth/SynthNote.h" 16 #include <cstring> 17 #include <cassert> 18 #include <iostream> 19 20 #define SUSTAIN_BIT 0x08 21 #define NOTE_MASK 0x07 22 23 namespace zyn { 24 25 enum NoteStatus { 26 KEY_OFF = 0x00, 27 KEY_PLAYING = 0x01, 28 KEY_RELEASED_AND_SUSTAINED = 0x02, 29 KEY_RELEASED = 0x03, 30 KEY_ENTOMBED = 0x04, 31 KEY_LATCHED = 0x05 32 }; 33 34 const char *getStatus(int status) 35 { 36 switch((enum NoteStatus)(status&NOTE_MASK)) 37 { 38 case KEY_OFF: return "OFF "; 39 case KEY_PLAYING: return "PLAY"; 40 case KEY_RELEASED_AND_SUSTAINED: return "SUST"; 41 case KEY_RELEASED: return "RELA"; 42 case KEY_ENTOMBED: return "TOMB"; 43 case KEY_LATCHED: return "LTCH"; 44 default: return "INVD"; 45 } 46 } 47 48 NotePool::NotePool(void) 49 :needs_cleaning(0) 50 { 51 memset(ndesc, 0, sizeof(ndesc)); 52 memset(sdesc, 0, sizeof(sdesc)); 53 } 54 55 bool NotePool::NoteDescriptor::playing(void) const 56 { 57 return (status&NOTE_MASK) == KEY_PLAYING; 58 } 59 60 bool NotePool::NoteDescriptor::latched(void) const 61 { 62 return (status&NOTE_MASK) == KEY_LATCHED; 63 } 64 65 bool NotePool::NoteDescriptor::sustained(void) const 66 { 67 return (status&NOTE_MASK) == KEY_RELEASED_AND_SUSTAINED; 68 } 69 70 bool NotePool::NoteDescriptor::released(void) const 71 { 72 return (status&NOTE_MASK) == KEY_RELEASED; 73 } 74 75 bool NotePool::NoteDescriptor::entombed(void) const 76 { 77 return (status&NOTE_MASK) == KEY_ENTOMBED; 78 } 79 80 // Notes that are no longer playing, for whatever reason. 81 bool NotePool::NoteDescriptor::dying(void) const 82 { 83 return (status&NOTE_MASK) == KEY_ENTOMBED || 84 (status&NOTE_MASK) == KEY_RELEASED; 85 } 86 87 bool NotePool::NoteDescriptor::off(void) const 88 { 89 return (status&NOTE_MASK) == KEY_OFF; 90 } 91 92 void NotePool::NoteDescriptor::setStatus(uint8_t s) 93 { 94 status &= ~NOTE_MASK; 95 status |= (NOTE_MASK&s); 96 } 97 98 void NotePool::NoteDescriptor::doSustain(void) 99 { 100 setStatus(KEY_RELEASED_AND_SUSTAINED); 101 } 102 103 bool NotePool::NoteDescriptor::canSustain(void) const 104 { 105 return !(status & SUSTAIN_BIT); 106 } 107 108 void NotePool::NoteDescriptor::makeUnsustainable(void) 109 { 110 status |= SUSTAIN_BIT; 111 } 112 113 NotePool::activeNotesIter NotePool::activeNotes(NoteDescriptor &n) 114 { 115 const int off_d1 = &n-ndesc; 116 int off_d2 = 0; 117 assert(off_d1 <= POLYPHONY); 118 for(int i=0; i<off_d1; ++i) 119 off_d2 += ndesc[i].size; 120 return NotePool::activeNotesIter{sdesc+off_d2,sdesc+off_d2+n.size}; 121 } 122 123 bool NotePool::NoteDescriptor::operator==(NoteDescriptor nd) 124 { 125 return age == nd.age && note == nd.note && sendto == nd.sendto && size == nd.size && status == nd.status; 126 } 127 128 //return either the first unused descriptor or the last valid descriptor which 129 //matches note/sendto 130 static int getMergeableDescriptor(note_t note, uint8_t sendto, bool legato, 131 NotePool::NoteDescriptor *ndesc) 132 { 133 int desc_id; 134 135 for(desc_id = 0; desc_id != POLYPHONY; ++desc_id) { 136 if(ndesc[desc_id].off()) 137 break; 138 } 139 140 if(desc_id != 0) { 141 auto &nd = ndesc[desc_id-1]; 142 if(nd.age == 0 && nd.note == note && nd.sendto == sendto 143 && nd.playing() && nd.legatoMirror == legato && nd.canSustain()) 144 return desc_id-1; 145 } 146 147 //Out of free descriptors 148 if(desc_id == POLYPHONY || !ndesc[desc_id].off()) { 149 return -1; 150 } 151 152 return desc_id; 153 } 154 155 NotePool::activeDescIter NotePool::activeDesc(void) 156 { 157 cleanup(); 158 return activeDescIter{*this}; 159 } 160 161 NotePool::constActiveDescIter NotePool::activeDesc(void) const 162 { 163 const_cast<NotePool*>(this)->cleanup(); 164 return constActiveDescIter{*this}; 165 } 166 167 int NotePool::usedNoteDesc(void) const 168 { 169 if(needs_cleaning) 170 const_cast<NotePool*>(this)->cleanup(); 171 172 int cnt = 0; 173 for(int i=0; i<POLYPHONY; ++i) 174 cnt += (ndesc[i].size != 0); 175 return cnt; 176 } 177 178 int NotePool::usedSynthDesc(void) const 179 { 180 if(needs_cleaning) 181 const_cast<NotePool*>(this)->cleanup(); 182 183 int cnt = 0; 184 for(int i=0; i<POLYPHONY*EXPECTED_USAGE; ++i) 185 cnt += (bool)sdesc[i].note; 186 return cnt; 187 } 188 189 void NotePool::insertNote(note_t note, uint8_t sendto, SynthDescriptor desc, PortamentoRealtime *portamento_realtime, bool legato) 190 { 191 //Get first free note descriptor 192 int desc_id = getMergeableDescriptor(note, sendto, legato, ndesc); 193 int sdesc_id = 0; 194 if(desc_id < 0) 195 goto error; 196 197 //Get first free synth descriptor 198 while(1) { 199 if (sdesc_id == POLYPHONY*EXPECTED_USAGE) 200 goto error; 201 if (sdesc[sdesc_id].note == 0) 202 break; 203 sdesc_id++; 204 } 205 206 ndesc[desc_id].note = note; 207 ndesc[desc_id].sendto = sendto; 208 ndesc[desc_id].size += 1; 209 ndesc[desc_id].status = KEY_PLAYING; 210 ndesc[desc_id].legatoMirror = legato; 211 ndesc[desc_id].portamentoRealtime = portamento_realtime; 212 213 sdesc[sdesc_id] = desc; 214 return; 215 error: 216 //Avoid leaking note 217 desc.note->memory.dealloc(desc.note); 218 //Let caller handle failure 219 throw std::bad_alloc(); 220 }; 221 222 void NotePool::upgradeToLegato(void) 223 { 224 for(auto &d:activeDesc()) 225 if(d.playing()) 226 for(auto &s:activeNotes(d)) 227 insertLegatoNote(d, s); 228 } 229 230 void NotePool::insertLegatoNote(NoteDescriptor desc, SynthDescriptor sdesc) 231 { 232 assert(sdesc.note); 233 try { 234 sdesc.note = sdesc.note->cloneLegato(); 235 // No portamentoRealtime for the legatoMirror descriptor 236 insertNote(desc.note, desc.sendto, sdesc, NULL, true); 237 } catch (std::bad_alloc &ba) { 238 std::cerr << "failed to insert legato note: " << ba.what() << std::endl; 239 } 240 }; 241 242 //There should only be one pair of notes which are still playing. 243 //Note however that there can be releasing legato notes already in the 244 //list when we get called, so need to handle that. 245 void NotePool::applyLegato(note_t note, const LegatoParams &par, PortamentoRealtime *portamento_realtime) 246 { 247 for(auto &desc:activeDesc()) { 248 //Currently, there can actually be more than one legato pair, while a 249 //previous legato pair is releasing and a new one is started, and we 250 //don't want to change anything about notes which are releasing. 251 if (desc.dying()) 252 continue; 253 desc.note = note; 254 // Only set portamentoRealtime for the primary of the two note 255 // descriptors in legato mode, or we'll get two note descriptors 256 // with the same realtime pointer, causing double updateportamento, 257 // and deallocation crashes. 258 if (!desc.legatoMirror) { 259 //If realtime is already set, we mustn't set it to NULL or we'll 260 //leak the old portamento. 261 if (portamento_realtime) 262 desc.portamentoRealtime = portamento_realtime; 263 } 264 for(auto &synth:activeNotes(desc)) 265 try { 266 synth.note->legatonote(par); 267 } catch (std::bad_alloc& ba) { 268 std::cerr << "failed to create legato note: " << ba.what() << std::endl; 269 } 270 } 271 } 272 273 void NotePool::makeUnsustainable(note_t note) 274 { 275 for(auto &desc:activeDesc()) { 276 if(desc.note == note) { 277 desc.makeUnsustainable(); 278 if(desc.sustained()) 279 release(desc); 280 } 281 } 282 } 283 284 bool NotePool::full(void) const 285 { 286 for(int i=0; i<POLYPHONY; ++i) 287 if(ndesc[i].off()) 288 return false; 289 return true; 290 } 291 292 bool NotePool::synthFull(int sdesc_count) const 293 { 294 int actually_free=sizeof(sdesc)/sizeof(sdesc[0]); 295 for(const auto &desc:activeDesc()) { 296 actually_free -= desc.size; 297 } 298 return actually_free < sdesc_count; 299 } 300 301 //Note that isn't KEY_PLAYING or KEY_RELEASED_AND_SUSTAINED 302 bool NotePool::existsRunningNote(void) const 303 { 304 //printf("running note # =%d\n", getRunningNotes()); 305 return getRunningNotes(); 306 } 307 308 int NotePool::getRunningNotes(void) const 309 { 310 bool running[256] = {}; 311 int running_count = 0; 312 313 for(auto &desc:activeDesc()) { 314 if(desc.playing() == false && desc.sustained() == false && desc.latched() == false) 315 continue; 316 if(running[desc.note] != false) 317 continue; 318 running[desc.note] = true; 319 running_count++; 320 } 321 return running_count; 322 } 323 324 void NotePool::enforceKeyLimit(int limit) 325 { 326 int notes_to_kill = getRunningNotes() - limit; 327 if(notes_to_kill <= 0) 328 return; 329 330 NoteDescriptor *to_kill = NULL; 331 unsigned oldest = 0; 332 for(auto &nd : activeDesc()) { 333 if(to_kill == NULL) { 334 //There must be something to kill 335 oldest = nd.age; 336 to_kill = &nd; 337 } else if(to_kill->dying() && nd.playing()) { 338 //Prefer to kill off a running note 339 oldest = nd.age; 340 to_kill = &nd; 341 } else if(nd.age > oldest && !(to_kill->playing() && nd.dying())) { 342 //Get an older note when it doesn't move from running to 343 //released (or entombed) 344 oldest = nd.age; 345 to_kill = &nd; 346 } 347 } 348 349 if(to_kill) { 350 auto &tk = *to_kill; 351 if(tk.dying() || tk.sustained()) 352 kill(*to_kill); 353 else 354 entomb(*to_kill); 355 } 356 } 357 358 int NotePool::getRunningVoices(void) const 359 { 360 int running_count = 0; 361 362 for(auto &desc:activeDesc()) { 363 // We don't count entombed voices as they will soon be dropped 364 if (desc.entombed()) 365 continue; 366 running_count++; 367 } 368 369 return running_count; 370 } 371 372 // Silence one voice, trying to the select the one that will be the least 373 // intrusive, preferably preferred_note if possible.. 374 void NotePool::limitVoice(int preferred_note) 375 { 376 NoteDescriptor *oldest_released = NULL; 377 NoteDescriptor *oldest_released_samenote = NULL; 378 NoteDescriptor *oldest_sustained = NULL; 379 NoteDescriptor *oldest_sustained_samenote = NULL; 380 NoteDescriptor *oldest_latched = NULL; 381 NoteDescriptor *oldest_latched_samenote = NULL; 382 NoteDescriptor *oldest_playing = NULL; 383 NoteDescriptor *oldest_playing_samenote = NULL; 384 385 for(auto &nd : activeDesc()) { 386 // printf("Scanning %d (%s (%d), age %u)\n", nd.note, getStatus(nd.status), nd.status, nd.age); 387 if (nd.released()) { 388 if (!oldest_released || nd.age > oldest_released->age) 389 oldest_released = &nd; 390 if (nd.note == preferred_note && 391 (!oldest_released_samenote || oldest_released_samenote->age)) 392 oldest_released_samenote = &nd; 393 } else if (nd.sustained()) { 394 if (!oldest_sustained || nd.age > oldest_sustained->age) 395 oldest_sustained = &nd; 396 if (nd.note == preferred_note && 397 (!oldest_sustained_samenote || oldest_sustained_samenote->age)) 398 oldest_sustained_samenote = &nd; 399 } else if (nd.latched()) { 400 if (!oldest_latched || nd.age > oldest_latched->age) 401 oldest_latched = &nd; 402 if (nd.note == preferred_note && 403 (!oldest_latched_samenote || oldest_latched_samenote->age)) 404 oldest_latched_samenote = &nd; 405 } else if (nd.playing()) { 406 if (!oldest_playing || nd.age > oldest_playing->age) 407 oldest_playing = &nd; 408 if (nd.note == preferred_note && 409 (!oldest_playing_samenote || oldest_playing_samenote->age)) 410 oldest_playing_samenote = &nd; 411 } 412 } 413 414 // Prioritize which note to kill: if a released note exists, take that, 415 // otherwise sustained, latched or playing, in that order. 416 // Within each category, favour a voice that is already playing the 417 // same note, which minimizes stealing notes that are still playing 418 // something significant, especially when there are a lot of repeated 419 // notes being played. 420 // If we don't have anything to kill, there's a logical error somewhere, 421 // but we can't do anything about it here so just silently return. 422 423 NoteDescriptor *to_kill = NULL; 424 425 if (oldest_released_samenote) 426 to_kill = oldest_released_samenote; 427 else if (oldest_released) 428 to_kill = oldest_released; 429 else if (oldest_sustained_samenote) 430 to_kill = oldest_sustained_samenote; 431 else if (oldest_sustained) 432 to_kill = oldest_sustained; 433 else if (oldest_latched_samenote) 434 to_kill = oldest_latched_samenote; 435 else if (oldest_latched) 436 to_kill = oldest_latched; 437 else if (oldest_playing_samenote) 438 to_kill = oldest_playing_samenote; 439 else if (oldest_playing) 440 to_kill = oldest_playing; 441 442 if (to_kill) { 443 // printf("Will kill %d (age %d)\n", to_kill->note, to_kill->age); 444 entomb(*to_kill); 445 } 446 } 447 448 void NotePool::enforceVoiceLimit(int limit, int preferred_note) 449 { 450 int notes_to_kill = getRunningVoices() - limit; 451 452 while (notes_to_kill-- > 0) 453 limitVoice(preferred_note); 454 } 455 456 457 void NotePool::releasePlayingNotes(void) 458 { 459 for(auto &d:activeDesc()) { 460 if(d.playing() || d.sustained() || d.latched()) { 461 d.setStatus(KEY_RELEASED); 462 for(auto s:activeNotes(d)) 463 s.note->releasekey(); 464 } 465 } 466 } 467 468 void NotePool::releaseSustainingNotes(void) 469 { 470 for(auto &d:activeDesc()) { 471 if(d.sustained()) { 472 d.setStatus(KEY_RELEASED); 473 for(auto s:activeNotes(d)) 474 s.note->releasekey(); 475 } 476 } 477 } 478 479 void NotePool::release(NoteDescriptor &d) 480 { 481 d.setStatus(KEY_RELEASED); 482 for(auto s:activeNotes(d)) 483 s.note->releasekey(); 484 } 485 486 void NotePool::latch(NoteDescriptor &d) 487 { 488 d.setStatus(KEY_LATCHED); 489 } 490 491 void NotePool::releaseLatched() 492 { 493 for(auto &desc:activeDesc()) 494 if(desc.latched()) 495 for(auto s:activeNotes(desc)) 496 s.note->releasekey(); 497 } 498 499 void NotePool::killAllNotes(void) 500 { 501 for(auto &d:activeDesc()) 502 kill(d); 503 } 504 505 void NotePool::killNote(note_t note) 506 { 507 for(auto &d:activeDesc()) { 508 if(d.note == note) 509 kill(d); 510 } 511 } 512 513 void NotePool::kill(NoteDescriptor &d) 514 { 515 d.setStatus(KEY_OFF); 516 for(auto &s:activeNotes(d)) 517 kill(s); 518 if (d.portamentoRealtime) 519 d.portamentoRealtime->memory.dealloc(d.portamentoRealtime); 520 } 521 522 void NotePool::kill(SynthDescriptor &s) 523 { 524 //printf("Kill synth...\n"); 525 s.note->memory.dealloc(s.note); 526 needs_cleaning = true; 527 } 528 529 void NotePool::entomb(NoteDescriptor &d) 530 { 531 d.setStatus(KEY_ENTOMBED); 532 for(auto &s:activeNotes(d)) 533 s.note->entomb(); 534 } 535 536 void NotePool::cleanup(void) 537 { 538 if(!needs_cleaning) 539 return; 540 needs_cleaning = false; 541 int new_length[POLYPHONY] = {}; 542 int cur_length[POLYPHONY] = {}; 543 //printf("Cleanup Start\n"); 544 //dump(); 545 546 //Identify the current length of all segments 547 //and the lengths discarding invalid entries 548 549 int last_valid_desc = 0; 550 for(int i=0; i<POLYPHONY; ++i) 551 if(!ndesc[i].off()) 552 last_valid_desc = i; 553 554 //Find the real numbers of allocated notes 555 { 556 int cum_old = 0; 557 558 for(int i=0; i<=last_valid_desc; ++i) { 559 cur_length[i] = ndesc[i].size; 560 for(int j=0; j<ndesc[i].size; ++j) 561 new_length[i] += (bool)sdesc[cum_old++].note; 562 } 563 } 564 565 566 //Move the note descriptors 567 { 568 int cum_new = 0; 569 for(int i=0; i<=last_valid_desc; ++i) { 570 ndesc[i].size = new_length[i]; 571 if(new_length[i] != 0) 572 ndesc[cum_new++] = ndesc[i]; 573 else { 574 ndesc[i].setStatus(KEY_OFF); 575 if (ndesc[i].portamentoRealtime) 576 ndesc[i].portamentoRealtime->memory.dealloc(ndesc[i].portamentoRealtime); 577 } 578 } 579 memset(ndesc+cum_new, 0, sizeof(*ndesc)*(POLYPHONY-cum_new)); 580 } 581 582 //Move the synth descriptors 583 { 584 int total_notes=0; 585 for(int i=0; i<=last_valid_desc; ++i) 586 total_notes+=cur_length[i]; 587 588 int cum_new = 0; 589 for(int i=0; i<total_notes; ++i) 590 if(sdesc[i].note) 591 sdesc[cum_new++] = sdesc[i]; 592 memset(sdesc+cum_new, 0, sizeof(*sdesc)*(POLYPHONY*EXPECTED_USAGE-cum_new)); 593 } 594 //printf("Cleanup Done\n"); 595 //dump(); 596 } 597 598 void NotePool::dump(void) 599 { 600 printf("NotePool::dump<\n"); 601 const char *format = 602 " Note %d:%d age(%d) note(%d) sendto(%d) status(%s) legato(%d) type(%d) kit(%d) ptr(%p)\n"; 603 int note_id=0; 604 int descriptor_id=0; 605 for(auto &d:activeDesc()) { 606 descriptor_id += 1; 607 for(auto &s:activeNotes(d)) { 608 note_id += 1; 609 printf(format, 610 note_id, descriptor_id, 611 d.age, d.note, d.sendto, 612 getStatus(d.status), d.legatoMirror, s.type, s.kit, s.note); 613 } 614 } 615 printf(">NotePool::dump\n"); 616 } 617 618 }