LMMS
Loading...
Searching...
No Matches
NotePool.cpp
Go to the documentation of this file.
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/SynthNote.h"
15#include <cstring>
16#include <cassert>
17#include <iostream>
18
19#define SUSTAIN_BIT 0x04
20#define NOTE_MASK 0x03
21
22namespace zyncarla {
23
30
31
34{
35 memset(ndesc, 0, sizeof(ndesc));
36 memset(sdesc, 0, sizeof(sdesc));
37}
38
40{
41 return (status&NOTE_MASK) == KEY_PLAYING;
42}
43
48
50{
51 return (status&NOTE_MASK) == KEY_RELEASED;
52}
53
55{
56 return (status&NOTE_MASK) == KEY_OFF;
57}
58
64
69
71{
72 return !(status & SUSTAIN_BIT);
73}
74
79
81{
82 const int off_d1 = &n-ndesc;
83 int off_d2 = 0;
84 assert(off_d1 <= POLYPHONY);
85 for(int i=0; i<off_d1; ++i)
86 off_d2 += ndesc[i].size;
87 return NotePool::activeNotesIter{sdesc+off_d2,sdesc+off_d2+n.size};
88}
89
91{
92 return age == nd.age && note == nd.note && sendto == nd.sendto && size == nd.size && status == nd.status;
93}
94
95//return either the first unused descriptor or the last valid descriptor which
96//matches note/sendto
97static int getMergeableDescriptor(uint8_t note, uint8_t sendto, bool legato,
99{
100 int desc_id = 0;
101 for(int i=0; i<POLYPHONY; ++i, ++desc_id)
102 if(ndesc[desc_id].off())
103 break;
104
105 if(desc_id != 0) {
106 auto &nd = ndesc[desc_id-1];
107 if(nd.age == 0 && nd.note == note && nd.sendto == sendto
108 && nd.playing() && nd.legatoMirror == legato && nd.canSustain())
109 return desc_id-1;
110 }
111
112 //Out of free descriptors
113 if(desc_id >= POLYPHONY || !ndesc[desc_id].off()) {
114 return -1;
115 }
116
117 return desc_id;
118}
119
121{
122 cleanup();
123 return activeDescIter{*this};
124}
125
127{
128 const_cast<NotePool*>(this)->cleanup();
129 return constActiveDescIter{*this};
130}
131
133{
135 const_cast<NotePool*>(this)->cleanup();
136
137 int cnt = 0;
138 for(int i=0; i<POLYPHONY; ++i)
139 cnt += (ndesc[i].size != 0);
140 return cnt;
141}
142
144{
146 const_cast<NotePool*>(this)->cleanup();
147
148 int cnt = 0;
149 for(int i=0; i<POLYPHONY*EXPECTED_USAGE; ++i)
150 cnt += (bool)sdesc[i].note;
151 return cnt;
152}
153
154void NotePool::insertNote(uint8_t note, uint8_t sendto, SynthDescriptor desc, bool legato)
155{
156 //Get first free note descriptor
157 int desc_id = getMergeableDescriptor(note, sendto, legato, ndesc);
158 assert(desc_id != -1);
159
160 ndesc[desc_id].note = note;
161 ndesc[desc_id].sendto = sendto;
162 ndesc[desc_id].size += 1;
163 ndesc[desc_id].status = KEY_PLAYING;
164 ndesc[desc_id].legatoMirror = legato;
165
166 //Get first free synth descriptor
167 int sdesc_id = 0;
168 while(sdesc[sdesc_id].note && sdesc_id < POLYPHONY*EXPECTED_USAGE)
169 sdesc_id++;
170
171 assert(sdesc_id < POLYPHONY*EXPECTED_USAGE);
172
173 sdesc[sdesc_id] = desc;
174};
175
177{
178 for(auto &d:activeDesc())
179 if(d.playing())
180 for(auto &s:activeNotes(d))
181 insertLegatoNote(d.note, d.sendto, s);
182}
183
185{
186 assert(desc.note);
187 try {
188 desc.note = desc.note->cloneLegato();
189 insertNote(note, sendto, desc, true);
190 } catch (std::bad_alloc &ba) {
191 std::cerr << "failed to insert legato note: " << ba.what() << std::endl;
192 }
193};
194
195//There should only be one pair of notes which are still playing
197{
198 for(auto &desc:activeDesc()) {
199 desc.note = par.midinote;
200 for(auto &synth:activeNotes(desc))
201 try {
202 synth.note->legatonote(par);
203 } catch (std::bad_alloc& ba) {
204 std::cerr << "failed to create legato note: " << ba.what() << std::endl;
205 }
206 }
207}
208
210{
211 for(auto &desc:activeDesc()) {
212 if(desc.note == note) {
213 desc.makeUnsustainable();
214 if(desc.sustained())
215 release(desc);
216 }
217 }
218}
219
220bool NotePool::full(void) const
221{
222 for(int i=0; i<POLYPHONY; ++i)
223 if(ndesc[i].off())
224 return false;
225 return true;
226}
227
228bool NotePool::synthFull(int sdesc_count) const
229{
230 int actually_free=sizeof(sdesc)/sizeof(sdesc[0]);
231 for(const auto &desc:activeDesc()) {
232 actually_free -= desc.size;
233 }
234 return actually_free < sdesc_count;
235}
236
237//Note that isn't KEY_PLAYING or KEY_RELASED_AND_SUSTAINING
239{
240 //printf("runing note # =%d\n", getRunningNotes());
241 return getRunningNotes();
242}
243
245{
246 bool running[256] = {0};
247 for(auto &desc:activeDesc()) {
248 //printf("note!(%d)\n", desc.note);
249 if(desc.playing() || desc.sustained())
250 running[desc.note] = true;
251 }
252
253 int running_count = 0;
254 for(int i=0; i<256; ++i)
255 running_count += running[i];
256
257 return running_count;
258}
260{
261 int notes_to_kill = getRunningNotes() - limit;
262 if(notes_to_kill <= 0)
263 return;
264
265 NoteDescriptor *to_kill = NULL;
266 unsigned oldest = 0;
267 for(auto &nd : activeDesc()) {
268 if(to_kill == NULL) {
269 //There must be something to kill
270 oldest = nd.age;
271 to_kill = &nd;
272 } else if(to_kill->released() && nd.playing()) {
273 //Prefer to kill off a running note
274 oldest = nd.age;
275 to_kill = &nd;
276 } else if(nd.age > oldest && !(to_kill->playing() && nd.released())) {
277 //Get an older note when it doesn't move from running to released
278 oldest = nd.age;
279 to_kill = &nd;
280 }
281 }
282
283 if(to_kill) {
284 auto &tk = *to_kill;
285 if(tk.released() || tk.sustained())
286 kill(*to_kill);
287 else
288 entomb(*to_kill);
289 }
290}
291
293{
294 for(auto &d:activeDesc()) {
295 if(d.playing() || d.sustained()) {
296 d.setStatus(KEY_RELEASED);
297 for(auto s:activeNotes(d))
298 s.note->releasekey();
299 }
300 }
301}
302
304{
305 d.setStatus(KEY_RELEASED);
306 for(auto s:activeNotes(d))
307 s.note->releasekey();
308}
309
311{
312 for(auto &d:activeDesc())
313 kill(d);
314}
315
317{
318 for(auto &d:activeDesc()) {
319 if(d.note == note)
320 kill(d);
321 }
322}
323
325{
326 d.setStatus(KEY_OFF);
327 for(auto &s:activeNotes(d))
328 kill(s);
329}
330
332{
333 //printf("Kill synth...\n");
334 s.note->memory.dealloc(s.note);
335 needs_cleaning = true;
336}
337
339{
340 d.setStatus(KEY_RELEASED);
341 for(auto &s:activeNotes(d))
342 s.note->entomb();
343}
344
345const char *getStatus(int status_bits)
346{
347 switch(status_bits)
348 {
349 case 0: return "OFF ";
350 case 1: return "PLAY";
351 case 2: return "SUST";
352 case 3: return "RELA";
353 default: return "INVD";
354 }
355}
356
358{
359 if(!needs_cleaning)
360 return;
361 needs_cleaning = false;
362 int new_length[POLYPHONY] = {0};
363 int cur_length[POLYPHONY] = {0};
364 //printf("Cleanup Start\n");
365 //dump();
366
367 //Identify the current length of all segments
368 //and the lengths discarding invalid entries
369
370 int last_valid_desc = 0;
371 for(int i=0; i<POLYPHONY; ++i)
372 if(!ndesc[i].off())
373 last_valid_desc = i;
374
375 //Find the real numbers of allocated notes
376 {
377 int cum_old = 0;
378
379 for(int i=0; i<=last_valid_desc; ++i) {
380 cur_length[i] = ndesc[i].size;
381 for(int j=0; j<ndesc[i].size; ++j)
382 new_length[i] += (bool)sdesc[cum_old++].note;
383 }
384 }
385
386
387 //Move the note descriptors
388 {
389 int cum_new = 0;
390 for(int i=0; i<=last_valid_desc; ++i) {
391 ndesc[i].size = new_length[i];
392 if(new_length[i] != 0)
393 ndesc[cum_new++] = ndesc[i];
394 else
395 ndesc[i].setStatus(KEY_OFF);
396 }
397 memset(ndesc+cum_new, 0, sizeof(*ndesc)*(POLYPHONY-cum_new));
398 }
399
400 //Move the synth descriptors
401 {
402 int total_notes=0;
403 for(int i=0; i<=last_valid_desc; ++i)
404 total_notes+=cur_length[i];
405
406 int cum_new = 0;
407 for(int i=0; i<total_notes; ++i)
408 if(sdesc[i].note)
409 sdesc[cum_new++] = sdesc[i];
410 memset(sdesc+cum_new, 0, sizeof(*sdesc)*(POLYPHONY*EXPECTED_USAGE-cum_new));
411 }
412 //printf("Cleanup Done\n");
413 //dump();
414}
415
417{
418 printf("NotePool::dump<\n");
419 const char *format =
420 " Note %d:%d age(%d) note(%d) sendto(%d) status(%s) legato(%d) type(%d) kit(%d) ptr(%p)\n";
421 int note_id=0;
422 int descriptor_id=0;
423 for(auto &d:activeDesc()) {
424 descriptor_id += 1;
425 for(auto &s:activeNotes(d)) {
426 note_id += 1;
427 printf(format,
428 note_id, descriptor_id,
429 d.age, d.note, d.sendto,
430 getStatus(d.status), d.legatoMirror, s.type, s.kit, s.note);
431 }
432 }
433 printf(">NotePool::dump\n");
434}
435
436}
#define POLYPHONY
Definition globals.h:114
#define NULL
Definition CarlaBridgeFormat.cpp:30
#define NOTE_MASK
Definition NotePool.cpp:20
#define SUSTAIN_BIT
Definition NotePool.cpp:19
#define EXPECTED_USAGE
Definition NotePool.h:18
assert(0)
int usedSynthDesc(void) const
Definition NotePool.cpp:143
void insertLegatoNote(uint8_t note, uint8_t sendto, SynthDescriptor desc)
Definition NotePool.cpp:184
void enforceKeyLimit(int limit)
Definition NotePool.cpp:259
void applyLegato(LegatoParams &par)
Definition NotePool.cpp:196
SynthDescriptor sdesc[POLYPHONY *EXPECTED_USAGE]
Definition NotePool.h:66
void killNote(note_t note)
Definition NotePool.cpp:316
bool existsRunningNote(void) const
Definition NotePool.cpp:238
bool full(void) const
Definition NotePool.cpp:220
void insertNote(uint8_t note, uint8_t sendto, SynthDescriptor desc, bool legato=false)
Definition NotePool.cpp:154
int getRunningNotes(void) const
Definition NotePool.cpp:244
void entomb(NoteDescriptor &d)
Definition NotePool.cpp:338
NotePool(void)
Definition NotePool.cpp:32
NoteDescriptor ndesc[POLYPHONY]
Definition NotePool.h:65
void dump(void)
Definition NotePool.cpp:416
int usedNoteDesc(void) const
Definition NotePool.cpp:132
void kill(NoteDescriptor &d)
Definition NotePool.cpp:324
activeNotesIter activeNotes(NoteDescriptor &n)
Definition NotePool.cpp:80
void cleanup(void)
Definition NotePool.cpp:357
bool synthFull(int sdesc_count) const
Definition NotePool.cpp:228
bool needs_cleaning
Definition NotePool.h:67
void upgradeToLegato(void)
Definition NotePool.cpp:176
void releasePlayingNotes(void)
Definition NotePool.cpp:292
void killAllNotes(void)
Definition NotePool.cpp:310
void release(NoteDescriptor &d)
Definition NotePool.cpp:303
activeDescIter activeDesc(void)
Definition NotePool.cpp:120
void makeUnsustainable(uint8_t note)
Definition NotePool.cpp:209
virtual SynthNote * cloneLegato(void)=0
register unsigned j
Definition inflate.c:1576
unsigned d
Definition inflate.c:940
register unsigned i
Definition inflate.c:1575
unsigned s
Definition inflate.c:1555
unsigned char uint8_t
Definition mid.cpp:98
Definition zynaddsubfx-src.cpp:569
T limit(T val, T min, T max)
Definition Util.h:85
NoteStatus
Definition NotePool.cpp:24
@ KEY_OFF
Definition NotePool.cpp:25
@ KEY_RELEASED_AND_SUSTAINED
Definition NotePool.cpp:27
@ KEY_RELEASED
Definition NotePool.cpp:28
@ KEY_PLAYING
Definition NotePool.cpp:26
const SYNTH_T & synth
Definition PADnoteParameters.h:210
const char * getStatus(int status_bits)
Definition NotePool.cpp:345
static int getMergeableDescriptor(uint8_t note, uint8_t sendto, bool legato, NotePool::NoteDescriptor *ndesc)
Definition NotePool.cpp:97
Definition SynthNote.h:35
int midinote
Definition SynthNote.h:39
Definition NotePool.h:28
bool off(void) const
Definition NotePool.cpp:54
uint32_t age
Definition NotePool.h:32
bool operator==(NoteDescriptor)
Definition NotePool.cpp:90
bool released(void) const
Definition NotePool.cpp:49
uint8_t size
Definition NotePool.h:36
void doSustain(void)
Definition NotePool.cpp:65
bool playing(void) const
Definition NotePool.cpp:39
bool canSustain(void) const
Definition NotePool.cpp:70
uint8_t status
Definition NotePool.h:37
void setStatus(uint8_t s)
Definition NotePool.cpp:59
void makeUnsustainable(void)
Definition NotePool.cpp:75
bool sustained(void) const
Definition NotePool.cpp:44
uint8_t note
Definition NotePool.h:33
uint8_t sendto
Definition NotePool.h:34
Definition NotePool.h:57
SynthNote * note
Definition NotePool.h:58
Definition NotePool.h:78
Definition NotePool.h:71
int n
Definition crypt.c:458
ulg size
Definition extract.c:2350
_WDL_CSTRING_PREFIX void INT_PTR const char * format
Definition wdlcstring.h:263