From 4544b290af48de07ca0bacc6f56f5a05ba67ac18 Mon Sep 17 00:00:00 2001 From: angel Date: Sun, 17 Oct 2004 10:50:55 +0000 Subject: [PATCH] Generator code uses queues instead of linear searches (Closes: #1001). git-svn-id: file:///home/angel/tmp/svn-triptico/ahxm/trunk@402 c87de0a0-a11c-0410-a1e5-866214bc28b2 --- TODO | 5 ++- midiin.c | 2 +- ss_gen.c | 155 ++++++++++++++++++++++++++++++++------------------------------- ss_gen.h | 17 ++++--- ss_ins.c | 49 +++++++++++++++++--- ss_ins.h | 6 ++- wav.c | 9 ++-- 7 files changed, 147 insertions(+), 96 deletions(-) diff --git a/TODO b/TODO index 9ac3a27..82b8135 100644 --- a/TODO +++ b/TODO @@ -4,10 +4,11 @@ Ann Hell Ex Machina TODO / Bug List Open Bugs --------- + * 1017: mp_doccer documentation is severely outdated. + Pending Enhancements -------------------- - * 1001: Generator should use queues of active / free generators. * 1002: Build an audio filtering tool to test effects. * 1003: There should exist 'some kind' of effect for note volumes to add a random variation, to add 'humanity'. This cannot @@ -47,5 +48,7 @@ Closed * 1015: Upgrade build system (new config.sh, makefile.in, etc.). (Thu, 09 Sep 2004 18:56:29 +0200). * 1016: Integrate the new compiler (Sun, 12 Sep 2004 16:13:11 +0200). + * 1001: Generator should use queues of active / free generators. + (Sun, 17 Oct 2004 12:50:10 +0200). Email bugs to angel@triptico.com diff --git a/midiin.c b/midiin.c index 1d162a5..cdea807 100644 --- a/midiin.c +++ b/midiin.c @@ -79,7 +79,7 @@ void process_MIDI(void) midimsg[0] &= 0xf0; if(midimsg[0] == MIDI_NOTE_OFF) - ss_ins_note_off(midimsg[1]); + ss_ins_note_off(&i, midimsg[1]); else if(midimsg[0] == MIDI_NOTE_ON) ss_ins_note_on(&i, midimsg[1], diff --git a/ss_gen.c b/ss_gen.c index cbbe9d2..6a8873a 100644 --- a/ss_gen.c +++ b/ss_gen.c @@ -43,11 +43,52 @@ int _ss_gen_num=SS_GEN_NUM; /* generator pool */ struct ss_gen * _ss_gen_pool=NULL; +/* free generator queue */ +struct ss_gen * _ss_gen_free=NULL; + /******************* Code ********************/ +void ss_gen_enqueue(struct ss_gen ** q, struct ss_gen * g) +{ + g->prev=NULL; + g->next=*q; + + if(*q != NULL) + (*q)->prev=g; + + *q=g; +} + + +void ss_gen_dequeue(struct ss_gen ** q, struct ss_gen * g) +{ + if(g->prev != NULL) + g->prev->next=g->next; + else + *q=g->next; + + if(g->next != NULL) + g->next->prev=g->prev; +} + + +struct ss_gen * ss_gen_dequeue_first(struct ss_gen ** q) +{ + struct ss_gen * g=NULL; + + if(*q != NULL) + { + g=*q; + ss_gen_dequeue(q, g); + } + + return(g); +} + + struct ss_gen * _ss_gen_get_free(void) { int n; @@ -58,17 +99,15 @@ struct ss_gen * _ss_gen_get_free(void) _ss_gen_pool=(struct ss_gen *) malloc(_ss_gen_num * sizeof(struct ss_gen)); - memset(_ss_gen_pool, '\0', _ss_gen_num * sizeof(struct ss_gen)); - } + memset(_ss_gen_pool, '\0', + _ss_gen_num * sizeof(struct ss_gen)); - /* find one in SS_GEN_FREE mode */ - for(n=0;n < _ss_gen_num;n++) - { - if(_ss_gen_pool[n].mode == SS_GEN_FREE) - return(&_ss_gen_pool[n]); + /* enqueue all into the free generator queue */ + for(n=0;n < _ss_gen_num;n++) + ss_gen_enqueue(&_ss_gen_free, &_ss_gen_pool[n]); } - return(NULL); + return(ss_gen_dequeue_first(&_ss_gen_free)); } @@ -97,19 +136,13 @@ struct ss_gen * _ss_gen_get_free(void) * This function returns -1 if the pool went out of generators, or * 0 if everything is OK and the generator entered GEN_MODE_PLAYING mode. */ -int ss_gen_play(int note_id, int trk_id, double freq, float vol[], +int ss_gen_play(struct ss_gen * g, int note_id, double freq, float vol[], struct ss_wave * w) { - struct ss_gen * g; int n; - /* find a free generator or fail */ - if((g=_ss_gen_get_free()) == NULL) - return(-1); - g->mode=SS_GEN_PLAYING; g->note_id=note_id; - g->trk_id=trk_id; memcpy(&g->w, w, sizeof(struct ss_wave)); @@ -135,12 +168,14 @@ int ss_gen_play(int note_id, int trk_id, double freq, float vol[], /* TEST: vibrato */ /* good freq: 6 Hz */ /* good depth: 1/6 semitone */ +#ifdef QQ if(trk_id == 2) { g->vib_depth=30; /* 20 */ g->vib_inc=( 6.28 * 6.0 ) / (double)_frequency; /* 0.001 */ } else +#endif g->vib_inc=0.0; return(0); @@ -157,52 +192,48 @@ int ss_gen_play(int note_id, int trk_id, double freq, float vol[], * * Returns the number of released generators. */ -int ss_gen_release(int note_id) +int ss_gen_release(struct ss_gen * g) { - struct ss_gen * g; - int n, m; - int notes=0; - - for(n=0;n < _ss_gen_num;n++) - { - g=&_ss_gen_pool[n]; - - if(g->note_id != note_id) - continue; - - /* note needs not be tracked anymore */ - g->note_id=-1; + int n; - /* generator is released */ - g->mode=SS_GEN_RELEASED; + /* note needs not be tracked anymore */ + g->note_id=-1; - /* calculates delta volume values */ - for(m=0;m < CHANNELS;m++) - { - if(g->w.wave[m]) - g->dvol[m]=g->vol[m] / (float) g->sustain; - else - g->dvol[m]=0.0; - } + /* generator is released */ + g->mode=SS_GEN_RELEASED; - notes++; + /* calculates delta volume values */ + for(n=0;n < CHANNELS;n++) + { + if(g->w.wave[n]) + g->dvol[n]=g->vol[n] / (float) g->sustain; + else + g->dvol[n]=0.0; } - return(notes); + return(1); } -int _ss_gen_frame(struct ss_gen * g, float frame[]) +/** + * ss_gen_frame - Generates a frame of samples. + * @trk_id: track id + * @frame: array where the output samples will be stored + * + * Generates a frame of samples for the track @trk_id, that will be stored + * in the @sample array. If the generator is in GEN_MODE_RELEASED mode, + * the sound should keep fading-out until the sustain time is exhausted and + * then moved to GEN_MODE_FREE mode; if the generator is playing and + * a non-looped sound reaches the end, it's immediately stopped. + * It also processes portamento. + */ +int ss_gen_frame(struct ss_gen * g, float frame[]) { float s; int n; int to_free=0; double v; - /* return if generator is not active */ - if(g->mode == SS_GEN_FREE) - return(0); - /* process vibrato */ if(g->vib_inc) { @@ -256,37 +287,7 @@ int _ss_gen_frame(struct ss_gen * g, float frame[]) g->inc += g->dinc; } - if(to_free) - g->mode=SS_GEN_FREE; - - return(1); -} - - -/** - * ss_gen_frame - Generates a frame of samples. - * @trk_id: track id - * @frame: array where the output samples will be stored - * - * Generates a frame of samples for the track @trk_id, that will be stored - * in the @sample array. If the generator is in GEN_MODE_RELEASED mode, - * the sound should keep fading-out until the sustain time is exhausted and - * then moved to GEN_MODE_FREE mode; if the generator is playing and - * a non-looped sound reaches the end, it's immediately stopped. - * It also processes portamento. - */ -void ss_gen_frame(int trk_id, float frame[]) -{ - struct ss_gen * g; - int n; - - for(n=0;n < _ss_gen_num;n++) - { - g=&_ss_gen_pool[n]; - - if(g->trk_id == trk_id) - _ss_gen_frame(g, frame); - } + return(to_free); } diff --git a/ss_gen.h b/ss_gen.h index f7fc312..2c3643c 100644 --- a/ss_gen.h +++ b/ss_gen.h @@ -34,7 +34,6 @@ struct ss_gen int mode; /* SS_GEN_* */ int note_id; /* note ID */ - int trk_id; /* track ID */ struct ss_wave w; /* the wave data */ float vol[CHANNELS]; /* the volumes */ @@ -52,16 +51,22 @@ struct ss_gen double vibrato; double vib_depth; double vib_inc; + + struct ss_gen * next; + struct ss_gen * prev; }; +extern struct ss_gen * _ss_gen_free; -int ss_gen_play(int note_id, int trk_id, double freq, float vol[], - struct ss_wave * w); +void ss_gen_enqueue(struct ss_gen ** q, struct ss_gen * g); +void ss_gen_dequeue(struct ss_gen ** q, struct ss_gen * g); +struct ss_gen * _ss_gen_get_free(void); -int ss_gen_release(int note_id); +int ss_gen_play(struct ss_gen * g, int note_id, double freq, float vol[], + struct ss_wave * w); -int _ss_gen_frame(struct ss_gen * g, float frame[]); +int ss_gen_release(struct ss_gen * g); -void ss_gen_frame(int trk_id, float frame[]); +int ss_gen_frame(struct ss_gen * g, float frame[]); int ss_gen_portamento(struct ss_gen * g, int portamento, double dest_inc); diff --git a/ss_ins.c b/ss_ins.c index 6d7afc6..72b1b8b 100644 --- a/ss_ins.c +++ b/ss_ins.c @@ -164,6 +164,7 @@ int ss_ins_note_on(struct ss_ins * i, int note, float vol, int note_id) float vols[CHANNELS]; double note_freq; int notes=0; + struct ss_gen * g; note_freq=note_frequency(note); @@ -175,6 +176,13 @@ int ss_ins_note_on(struct ss_ins * i, int note, float vol, int note_id) if(note_freq < l->min_freq || note_freq > l->max_freq) continue; + /* get a free generator, or fail */ + if((g=_ss_gen_get_free()) == NULL) + break; + + /* enqueue the generator to this ins. queue */ + ss_gen_enqueue(&i->gens, g); + memcpy(&w, l, sizeof(struct ss_wave)); /* assign the channels and their volumes */ @@ -194,7 +202,7 @@ int ss_ins_note_on(struct ss_ins * i, int note, float vol, int note_id) } /* start the generator */ - ss_gen_play(note_id, i->trk_id, note_freq, vols, &w); + ss_gen_play(g, note_id, note_freq, vols, &w); notes++; } @@ -210,9 +218,16 @@ int ss_ins_note_on(struct ss_ins * i, int note, float vol, int note_id) * * Releases a note. The generators associated to it will enter release mode. */ -void ss_ins_note_off(int note_id) +void ss_ins_note_off(struct ss_ins * i, int note_id) { - ss_gen_release(note_id); + struct ss_gen * g; + + /* releases all generators with that note_id */ + for(g=i->gens;g != NULL;g=g->next) + { + if(g->note_id == note_id) + ss_gen_release(g); + } } @@ -224,7 +239,31 @@ void ss_ins_note_off(int note_id) * Generates a frame of samples mixing all the active generators * of a track. */ -void ss_ins_frame(int trk_id, float frame[]) +void ss_ins_frame(struct ss_ins * i, float frame[]) { - ss_gen_frame(trk_id, frame); + struct ss_gen * g; + + for(g=i->gens;g != NULL;) + { + if(ss_gen_frame(g, frame)) + { + struct ss_gen * t; + + /* generator has been freed */ + + /* get pointer to next before being + destroyed by requeueing */ + t=g->next; + + /* generator has been freed; dequeue */ + ss_gen_dequeue(&i->gens, g); + + /* requeue back to free pool */ + ss_gen_enqueue(&_ss_gen_free, g); + + g=t; + } + else + g=g->next; + } } diff --git a/ss_ins.h b/ss_ins.h index d03f6b7..addf3c2 100644 --- a/ss_ins.h +++ b/ss_ins.h @@ -27,6 +27,8 @@ struct ss_ins struct ss_wave * layers; /* layers */ int n_layers; /* # of layers */ + struct ss_gen * gens; /* generator queue */ + float vol[CHANNELS]; /* channel map */ int sustain; /* sustain */ }; @@ -43,6 +45,6 @@ void ss_ins_set_sustain(struct ss_ins * i, int sustain); int ss_ins_note_on(struct ss_ins * i, int note, float vol, int note_id); -void ss_ins_note_off(int note_id); +void ss_ins_note_off(struct ss_ins * i, int note_id); -void ss_ins_frame(int trk_id, float frame[]); +void ss_ins_frame(struct ss_ins * i, float frame[]); diff --git a/wav.c b/wav.c index 497ecac..14aec65 100644 --- a/wav.c +++ b/wav.c @@ -276,7 +276,8 @@ int main(void) e2->note_on.note_id); else if(e2->generic.type == EV2_NOTE_OFF) - ss_ins_note_off(e2->note_off.note_id); + ss_ins_note_off(&i[e2->note_off.trk_id], + e2->note_off.note_id); else if(e2->generic.type == EV2_END) goon=0; @@ -286,9 +287,9 @@ int main(void) output_init_frame(output); - ss_ins_frame(0, output); - ss_ins_frame(1, output); - ss_ins_frame(2, output); + ss_ins_frame(&i[0], output); + ss_ins_frame(&i[1], output); + ss_ins_frame(&i[2], output); #ifdef QQ if(n < TIME2SAMPLES(13)) -- 2.11.4.GIT