#include "NotePool.h" //XXX eliminate dependence on Part.h #include "../Misc/Part.h" #include "../Misc/Allocator.h" #include "../Synth/SynthNote.h" #include #include #include NotePool::NotePool(void) :needs_cleaning(0) { memset(ndesc, 0, sizeof(ndesc)); memset(sdesc, 0, sizeof(sdesc)); } NotePool::activeNotesIter NotePool::activeNotes(NoteDescriptor &n) { const int off_d1 = &n-ndesc; int off_d2 = 0; assert(off_d1 <= POLYPHONY); for(int i=0; i= POLYPHONY || ndesc[desc_id].status != Part::KEY_OFF) { return -1; } return desc_id; } NotePool::activeDescIter NotePool::activeDesc(void) { cleanup(); return activeDescIter{*this}; } NotePool::constActiveDescIter NotePool::activeDesc(void) const { const_cast(this)->cleanup(); return constActiveDescIter{*this}; } void NotePool::insertNote(uint8_t note, uint8_t sendto, SynthDescriptor desc, bool legato) { //Get first free note descriptor int desc_id = getMergeableDescriptor(note, sendto, legato, ndesc); assert(desc_id != -1); ndesc[desc_id].note = note; ndesc[desc_id].sendto = sendto; ndesc[desc_id].size += 1; ndesc[desc_id].status = Part::KEY_PLAYING; ndesc[desc_id].legatoMirror = legato; //Get first free synth descriptor int sdesc_id = 0; while(sdesc[sdesc_id].note && sdesc_id < POLYPHONY*EXPECTED_USAGE) sdesc_id++; assert(sdesc_id < POLYPHONY*EXPECTED_USAGE); sdesc[sdesc_id] = desc; }; void NotePool::upgradeToLegato(void) { for(auto &d:activeDesc()) if(d.status == Part::KEY_PLAYING) for(auto &s:activeNotes(d)) insertLegatoNote(d.note, d.sendto, s); } void NotePool::insertLegatoNote(uint8_t note, uint8_t sendto, SynthDescriptor desc) { assert(desc.note); try { desc.note = desc.note->cloneLegato(); insertNote(note, sendto, desc, true); } catch (std::bad_alloc &ba) { std::cerr << "failed to insert legato note: " << ba.what() << std::endl; } }; //There should only be one pair of notes which are still playing void NotePool::applyLegato(LegatoParams &par) { for(auto &desc:activeDesc()) { desc.note = par.midinote; for(auto &synth:activeNotes(desc)) try { synth.note->legatonote(par); } catch (std::bad_alloc& ba) { std::cerr << "failed to create legato note: " << ba.what() << std::endl; } } }; bool NotePool::full(void) const { for(int i=0; i keylimit) //find out the oldest note // for(int i = 0; i < POLYPHONY; ++i) { // int maxtime = 0; // if(((partnote[i].status == KEY_PLAYING) || (partnote[i].status == KEY_RELEASED_AND_SUSTAINED)) && (partnote[i].time > maxtime)) { // maxtime = partnote[i].time; // oldestnotepos = i; // } // } //if(oldestnotepos != -1) // ReleaseNotePos(oldestnotepos); //} //printf("Unimplemented enforceKeyLimit()\n"); return -1; } void NotePool::releasePlayingNotes(void) { for(auto &d:activeDesc()) { if(d.status == Part::KEY_PLAYING) { d.status = Part::KEY_RELEASED; for(auto s:activeNotes(d)) s.note->releasekey(); } } } void NotePool::release(NoteDescriptor &d) { d.status = Part::KEY_RELEASED; for(auto s:activeNotes(d)) s.note->releasekey(); } void NotePool::killAllNotes(void) { for(auto &d:activeDesc()) kill(d); } void NotePool::killNote(uint8_t note) { for(auto &d:activeDesc()) { if(d.note == note) kill(d); } } void NotePool::kill(NoteDescriptor &d) { d.status = Part::KEY_OFF; for(auto &s:activeNotes(d)) kill(s); } void NotePool::kill(SynthDescriptor &s) { //printf("Kill synth...\n"); s.note->memory.dealloc(s.note); needs_cleaning = true; } const char *getStatus(int status_bits) { switch(status_bits) { case 0: return "OFF "; case 1: return "PLAY"; case 2: return "SUST"; case 3: return "RELA"; default: return "INVD"; } } void NotePool::cleanup(void) { if(!needs_cleaning) return; needs_cleaning = false; int new_length[POLYPHONY] = {0}; int cur_length[POLYPHONY] = {0}; //printf("Cleanup Start\n"); //dump(); //Identify the current length of all segments //and the lengths discarding invalid entries int last_valid_desc = 0; for(int i=0; iNotePool::dump\n"); }