From 8d573499c306c8546199027e824cf4531fa294fa Mon Sep 17 00:00:00 2001 From: angel Date: Mon, 23 Jan 2006 15:56:15 +0000 Subject: [PATCH] Branch annhell-branch-paged MERGED. git-svn-id: file:///home/angel/tmp/svn-triptico/ahxm/trunk@812 c87de0a0-a11c-0410-a1e5-866214bc28b2 --- RELEASE_NOTES | 7 ++++++ TODO | 6 +++++ VERSION | 2 +- annhell.h | 26 ++++++++++++++++---- main.c | 14 +++++++++++ ss_core.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++------------ ss_eff.c | 5 +++- ss_input.c | 40 +++++++++++++++++++++--------- 8 files changed, 145 insertions(+), 34 deletions(-) diff --git a/RELEASE_NOTES b/RELEASE_NOTES index 532a24a..2a3fdb8 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -1,6 +1,13 @@ Ann Hell Ex Machina Release Notes ================================= +1.0.3 +----- + + * This release allows working with huge wave files, as they are + loaded page by page instead of full in memory (but beware of + bug #1108). + 1.0.2b ------ diff --git a/TODO b/TODO index ee13a2b..bdc9fbe 100644 --- a/TODO +++ b/TODO @@ -26,6 +26,12 @@ Open Bugs configurable via the configuration file (needs #1074 closed). * 1098: Immediate volumes are not implemented. * 1097: Dotted notes are broken when more than one is used. + * 1108: Sometimes wave paging hangs. It seems to be related to generators + simultaneously using offsets far from each other, so the loaded page + keeps bouncing. Setting the page size to a big number (like the actual + default, 441000) seems to avoid it, as huge files are not usually used + more than once. If you are bit by this bug, set the page size to -1 with + the -b command line option. Pending Enhancements -------------------- diff --git a/VERSION b/VERSION index f6d5da7..71e6a1d 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -#define VERSION "1.0.2b" +#define VERSION "1.0.3-cvs" diff --git a/annhell.h b/annhell.h index 9b9ad54..6882e20 100644 --- a/annhell.h +++ b/annhell.h @@ -45,7 +45,8 @@ typedef double sample_t; struct ss_wave { - double size; /* size in frames */ + double size; /* size in frames of full wave */ + int p_size; /* size in frames of the page */ int n_channels; /* # of channels */ sample_t ** wave; /* the PCM waves */ int s_rate; /* original sample rate */ @@ -56,6 +57,12 @@ struct ss_wave double base_freq; /* base frequency */ double min_freq; /* minimum frequency */ double max_freq; /* maximum frequency */ + + char * filename; /* filename (for paged files) */ + long f_pos; /* file position where the PCM files */ + int p_offset; /* offset in frames of the page */ + int bits; /* bits of the PCM wave (8, 16) */ + int sign; /* sign of the PCM wave (1, -1) */ }; /* generators */ @@ -359,6 +366,10 @@ extern int ss_frequency; extern int ss_interpolation; extern int ss_nchannels; +/* in ss_input.c */ + +extern int ss_page_size; + /* in ss_output.c */ extern sample_t ss_master_volume; @@ -371,6 +382,12 @@ extern union song_ev * song; extern int n_song_ev; extern int solo_track; +/* in support.c */ + +extern int debug; +extern int trace; +extern int show_progress; + /* MACROS */ /* milliseconds to frames conversion */ @@ -382,8 +399,9 @@ extern int solo_track; /* in ss_core.c */ double ss_note_frequency(int note); -struct ss_wave * ss_alloc_wave(int size, int n_channels, int s_rate); +struct ss_wave * ss_alloc_wave(int size, int n_channels, int s_rate, int p_size); void ss_free_wave(struct ss_wave * w); +void ss_prepare_wave(struct ss_wave * w); sample_t ss_get_sample(struct ss_wave * w, int channel, double offset); double ss_tempo_from_wave(struct ss_wave * w, int note, double len); double ss_pitch_from_tempo(struct ss_wave * w, double tempo, double len); @@ -424,6 +442,7 @@ void ss_output_close(void); /* in ss_input.c */ +void load_pcm_wave(FILE * f, struct ss_wave * w); struct ss_wave * ss_load_wave_file(char * file, double base_freq, double min_freq, double max_freq, double loop_start, double loop_end); @@ -469,9 +488,6 @@ int compile_ahs(char * file); /* in support.c */ -extern int debug; -extern int trace; -extern int show_progress; void add_to_library_path(char * path, int strip); FILE * path_fopen(char * filename, char * mode); char * locate_file(char * filename); diff --git a/main.c b/main.c index e83d13b..818863c 100644 --- a/main.c +++ b/main.c @@ -28,6 +28,7 @@ #include #include #include +#include #include "annhell.h" @@ -70,6 +71,9 @@ static int main_usage(void) printf("-z {track number} Play track number in a solo\n"); printf("-i {interpolation} Set interpolation algorithm\n"); printf(" (0, none; 1, linear; 2, cubic spline,\n"); + printf("-b {size in frames} Set maximum wave buffer size in frames, so\n"); + printf(" wave files bigger than this will be paged\n"); + printf(" (-1, load full wave in memory) [default: 441000]\n"); printf(" 3, Lagrange) [default: 3]\n"); printf("-P Show progress.\n"); printf("-D Show debugging information.\n"); @@ -219,6 +223,16 @@ static int annhell_main(int argc, char * argv[]) solo_track = atoi(argv[n++]); } else + if(strcmp(opt, "-b") == 0) + { + /* set page size */ + ss_page_size = atoi(argv[n++]); + + /* if it's -1, set as 'no limit' */ + if(ss_page_size < 0) + ss_page_size = INT_MAX; + } + else if(strcmp(opt, "-D") == 0) debug = 1; else diff --git a/ss_core.c b/ss_core.c index 9cabac0..e8d0078 100644 --- a/ss_core.c +++ b/ss_core.c @@ -84,32 +84,29 @@ double ss_note_frequency(int note) * @size: size in frames * @n_channels: number of channels * @s_rate: sampling rate + * @p_size: size of the sound page * - * Allocates a wave structure. + * Allocates a wave structure. If @p_size is -1, it's assumed to be the + * same as @size (so the sound will live entirely in memory). */ -struct ss_wave * ss_alloc_wave(int size, int n_channels, int s_rate) +struct ss_wave * ss_alloc_wave(int size, int n_channels, int s_rate, int p_size) { - struct ss_wave * w; + struct ss_wave * w = NULL; + + if(p_size == -1) p_size = size; if((w = (struct ss_wave *)malloc(sizeof(struct ss_wave))) != NULL) { - int n; - memset(w, '\0', sizeof(struct ss_wave)); w->size = (double) size; + w->p_size = p_size; w->n_channels = n_channels; w->s_rate = s_rate; /* alloc space for the pointers to the waves */ w->wave = (sample_t **)malloc(n_channels * sizeof(sample_t *)); - - /* alloc space for the waves themselves */ - for(n = 0;n < n_channels;n++) - { - w->wave[n] = (sample_t *)malloc(size * sizeof(sample_t)); - memset(w->wave[n], '\0', size * sizeof(sample_t)); - } + memset(w->wave, '\0', n_channels * sizeof(sample_t *)); } return(w); @@ -135,6 +132,9 @@ void ss_free_wave(struct ss_wave * w) /* frees the space for the pointers to the waves */ free(w->wave); + + /* if it has a filename, also free it */ + if(w->filename != NULL) free(w->filename); } /* frees the wave itself */ @@ -142,15 +142,64 @@ void ss_free_wave(struct ss_wave * w) } -sample_t ss_pick_sample(struct ss_wave * w, int channel, double offset) +void ss_prepare_wave(struct ss_wave * w) +/* prepares a wave file for usage (creates the page buffers) */ +{ + int n; + + /* if the buffers exist, do nothing */ + if(w->wave[0] != NULL) + return; + + /* alloc space for the waves themselves */ + for(n = 0;n < w->n_channels;n++) + { + w->wave[n] = (sample_t *)malloc(w->p_size * sizeof(sample_t)); + memset(w->wave[n], '\0', w->p_size * sizeof(sample_t)); + } +} + + +static void ss_load_page(struct ss_wave * w, int offset) +/* loads a page from a wave file into memory */ +{ + FILE * f; + int s; + + ss_prepare_wave(w); + + /* read the page from disk */ + f = fopen(w->filename, "r"); + + /* calculate the frame size */ + w->p_offset = offset; + s = offset * (w->bits / 8) * w->n_channels; + + /* move there */ + fseek(f, w->f_pos + s, SEEK_SET); + + /* fill the page */ + load_pcm_wave(f, w); + + fclose(f); +} + + +static sample_t ss_pick_sample(struct ss_wave * w, int channel, double offset) +/* picks a sample from a ss_wave, forcing a call to ss_load_page() if + the wanted sample is not in memory */ { int o; sample_t * wave; o = (int) offset; - wave = w->wave[channel]; - return(wave[o]); + /* is the wanted sample not in memory? */ + if(o < w->p_offset || o > w->p_offset + w->p_size) + ss_load_page(w, o); + + wave = w->wave[channel]; + return(wave[o - w->p_offset]); } diff --git a/ss_eff.c b/ss_eff.c index d7a0aef..d63c3cd 100644 --- a/ss_eff.c +++ b/ss_eff.c @@ -70,7 +70,10 @@ static struct ss_eff * ss_eff_add(struct ss_eff ** ec, double size, /* add buffer */ if(size > 0) - e->wave = ss_alloc_wave((int) size, 1, ss_frequency); + { + e->wave = ss_alloc_wave((int) size, 1, ss_frequency, -1); + ss_prepare_wave(e->wave); + } e->gain = gain; e->func = func; diff --git a/ss_input.c b/ss_input.c index 44000a0..6ed117b 100644 --- a/ss_input.c +++ b/ss_input.c @@ -39,6 +39,9 @@ Data ********************/ +/* maximum page size */ +int ss_page_size = 441000; + /******************* Code ********************/ @@ -74,7 +77,8 @@ static sample_t load_sample(FILE * f, int bits, int sign) { int s; - /* Caution: no error condition is checked */ + /* if on eof, return silence */ + if(feof(f)) return(0); if(bits == 8) { @@ -93,19 +97,16 @@ static sample_t load_sample(FILE * f, int bits, int sign) } -static void load_pcm_wave(FILE * f, int bits, int sign, struct ss_wave * w) +void load_pcm_wave(FILE * f, struct ss_wave * w) /* loads an interleaved stream from a file */ { - int n, i; - double m; + int n, m; /* fills the channels */ - for(m = 0;m < w->size;m++) + for(m = 0;m < w->p_size;m++) { - i = (int) m; - for(n = 0;n < w->n_channels;n++) - w->wave[n][i] = load_sample(f, bits, sign); + w->wave[n][m] = load_sample(f, w->bits, w->sign); } } @@ -133,6 +134,7 @@ struct ss_wave * ss_load_wav_file(char * file, double size; int s_rate, bits; struct ss_wave * w; + int p; if((f = path_fopen(file, "r")) == NULL) return(NULL); @@ -178,7 +180,9 @@ struct ss_wave * ss_load_wav_file(char * file, if(bits == 16) size /= 2; size /= (double) n_channels; - if((w = ss_alloc_wave(size, n_channels, s_rate)) != NULL) + p = size > ss_page_size ? ss_page_size : size; + + if((w = ss_alloc_wave(size, n_channels, s_rate, p)) != NULL) { w->base_freq = base_freq; w->min_freq = min_freq; @@ -191,7 +195,15 @@ struct ss_wave * ss_load_wav_file(char * file, else w->loop_end = loop_end; - load_pcm_wave(f, bits, 1, w); + /* fill the info needed for paging */ + w->filename = strdup(file); + w->f_pos = ftell(f); + w->bits = bits; + w->sign = 1; + + /* set the page offset further the end, to + force a page reading the first time it's used */ + w->p_offset = (int) size; } fclose(f); @@ -425,7 +437,7 @@ int ss_load_pat_file(struct ss_ins * i, char * file) /* skip reserved */ fread(buffer, 36, 1, f); - if((w = ss_alloc_wave(size, 1, s_rate)) == NULL) + if((w = ss_alloc_wave(size, 1, s_rate, -1)) == NULL) break; /* set the rest of values */ @@ -434,9 +446,12 @@ int ss_load_pat_file(struct ss_ins * i, char * file) w->base_freq = base_freq; w->min_freq = min_freq; w->max_freq = max_freq; + w->bits = bits; + w->sign = sign; /* load the wave */ - load_pcm_wave(f, bits, sign, w); + ss_prepare_wave(w); + load_pcm_wave(f, w); if(pingpong && loop) { @@ -464,6 +479,7 @@ int ss_load_pat_file(struct ss_ins * i, char * file) w->loop_end += (double) loop_size; w->size += (double) loop_size; + w->p_size += loop_size; /* free and swap */ free(w->wave[0]); -- 2.11.4.GIT