From 774815a97901fe9d5ce2767a8c479c52a5ad0ce8 Mon Sep 17 00:00:00 2001 From: - Date: Thu, 9 May 2013 17:54:45 +0200 Subject: Lazy load of audio. Unloads when there's nothing else to do. --- hugin | 2 +- src/audiofile.cc | 120 ++++++++++++++++++++++++++++++++++++++++++++++-- src/audiofile.h | 49 +++++++++++++++++++- src/drumgizmo.cc | 15 ++++-- src/drumkitloader.cc | 126 +++++++++++++++++++++++++++++++++++---------------- src/drumkitloader.h | 7 +++ 6 files changed, 271 insertions(+), 48 deletions(-) diff --git a/hugin b/hugin index 782fe18..2630860 160000 --- a/hugin +++ b/hugin @@ -1 +1 @@ -Subproject commit 782fe184b558070bca926bdeb38c48ea16578544 +Subproject commit 2630860e6bc935c3daacec186e080eddcc79fe3c diff --git a/src/audiofile.cc b/src/audiofile.cc index 5a9cdb5..c9641dc 100644 --- a/src/audiofile.cc +++ b/src/audiofile.cc @@ -33,15 +33,23 @@ #include +#define LAZYLOAD + AudioFile::AudioFile(std::string filename) { is_loaded = false; //printf("new AudioFile %p\n", this); this->filename = filename; + locked = false; data = NULL; size = 0; - +//#ifdef LAZY_LOAD + fh = NULL; + preloaded_data = NULL; + completely_loaded = false; +//#endif/*LAZYLOAD*/ + ref_count = 0; magic = this; //load(); @@ -61,15 +69,116 @@ bool AudioFile::isValid() void AudioFile::unload() { - if(data) { + if(data == preloaded_data) { delete data; data = NULL; size = 0; } + else { + size = 0; + delete data; + data = NULL; + delete preloaded_data; + preloaded_data = NULL; + } + sf_close(this->fh); +} + +#define SIZE 512*4 +void AudioFile::init() { + printf("Initializing %p\n", this); + if(data) { + printf("\t already initialized\n"); + return; + } + + SF_INFO sf_info; + SNDFILE *fh = sf_open(filename.c_str(), SFM_READ, &sf_info); + if(!fh) { + printf("SNDFILE Error (%s): %s\n", filename.c_str(), sf_strerror(fh)); + return; + } + + int size = SIZE; + + sample_t* data = new sample_t[size]; + + size = sf_read_float(fh, data, size); + + printf("Lazy loaded %d samples\n", size); + sf_close(fh); + + mutex.lock(); + this->data = data; + this->size = size; + this->preloaded_data = data; + this->is_loaded = true; + this->fh = fh; +// if(sf_info.frames <= size) { +// printf("Sample completely loaded\n"); +// completely_loaded = true; +// } + mutex.unlock(); +} + +void AudioFile::loadNext() +{ + if(this->data != this->preloaded_data) { + printf("Already completely loaded %p\n", this); + return; + } + + SF_INFO sf_info; + SNDFILE *fh = sf_open(filename.c_str(), SFM_READ, &sf_info); +// SF_INFO sf_info = this->sf_info; +// SNDFILE *fh = this->fh; + if(!fh) { + printf("SNDFILE Error (%s): %s\n", filename.c_str(), sf_strerror(fh)); + return; + } + +// sf_seek(fh, 0, SEEK_SET) ; + + int size = sf_info.frames; + + sample_t* data = new sample_t[size]; + + size = sf_read_float(fh, data, size); + + printf("Finished loading %d samples %p\n", size, this); + sf_close(fh); + + mutex.lock(); + this->data = data; + this->size = size; + mutex.unlock(); +} + +void AudioFile::reset() { + printf("Resetting audio file %p\n", this); + if(this->data == this->preloaded_data) { + printf("\tNot completely loaded - skipping %p\n", this); + return; + } + + mutex.lock(); + sample_t* old_data = data; + this->size = SIZE; + this->data = this->preloaded_data; +// if() { + printf("Deleting data %p\n", this); + delete old_data; +// } + mutex.unlock(); } void AudioFile::load() { +#ifdef LAZYLOAD + init(); + return; +#endif + if(data) return; SF_INFO sf_info; @@ -78,11 +187,14 @@ void AudioFile::load() printf("SNDFILE Error (%s): %s\n", filename.c_str(), sf_strerror(fh)); return; } - + size = sf_info.frames; + data = new sample_t[size]; - sf_read_float(fh, data, size); + size = sf_read_float(fh, data, size); + + printf("Loaded %d samples %p\n", size, this); sf_close(fh); diff --git a/src/audiofile.h b/src/audiofile.h index e4b8410..d203781 100644 --- a/src/audiofile.h +++ b/src/audiofile.h @@ -29,10 +29,44 @@ #include #include +#include + +#include #include "mutex.h" #include "audio.h" +#if 0 + Plan for lazy loading of audio (Brainstorming) + * Encapsulate data array? + - Speed issues? + - Other suggestion + * Trigger on read begin and read done + - readnext(instrument)? + * size_t current latest loaded sample + * run in own thread? threads in drumgizmo?? + - Add soundfile-loader-class which run in its own thread + * Add pre-loading constant + * Pointer to pos in audio stream (maybe just last position read) + * Strategy for how to handle pre-loading of remaining file + - Is it acceptable only to handle sequential reading of data (no random access)? + + Thread A Thread B + + :preload constant (user defined) + :speed modifier constant (in which time must + sample n be loaded relative to trigger time) + ---------- ------ + | Loader | <------- Trigger load of InstrumentSample n --------- | DG | + ---------- ------ + Load (int- right most loaded sample --> If current sample pos loaded + | --------- | | + Wave Into --> | SndFile | <----- Read data (directly from array) + --------- +#endif/*0*/ + +#define LAZYLOAD + class AudioFile { public: AudioFile(std::string filename); @@ -43,12 +77,25 @@ public: bool isLoaded(); - sample_t *data; size_t size; + + sample_t *data; std::string filename; + bool locked; +#ifdef LAZYLOAD + SF_INFO sf_info; + SNDFILE *fh; + bool completely_loaded; + void init(); + void reset(); + void loadNext(); + sample_t* preloaded_data; +#endif/*LAZYLOAD*/ + bool isValid(); + int ref_count; private: void *magic; diff --git a/src/drumgizmo.cc b/src/drumgizmo.cc index 72b3811..df2fd31 100644 --- a/src/drumgizmo.cc +++ b/src/drumgizmo.cc @@ -331,6 +331,10 @@ bool DrumGizmo::run(size_t pos, sample_t *samples, size_t nsamples) while(j != kit.channels.end()) { Channel &ch = *j; AudioFile *af = s->getAudioFile(&ch); + if(af) { + printf("Requesting preparing of audio file\n"); + loader.prepare(af); + } if(af == NULL || !af->isValid()) { //printf("Missing AudioFile.\n"); } else { @@ -364,6 +368,7 @@ bool DrumGizmo::run(size_t pos, sample_t *samples, size_t nsamples) } if(buf) { memset(buf, 0, nsamples * sizeof(sample_t)); + getSamples(c, pos, buf, nsamples); if(!internal) oe->run(c, samples, nsamples); } @@ -426,8 +431,9 @@ void DrumGizmo::getSamples(int ch, int pos, sample_t *s, size_t sz) if(evt->rampdown == NO_RAMPDOWN) { #ifdef SSE - size_t optend = ((end - n) / N) * N + n; - for(; n < optend; n += N) { +// printf("%d\n", evt->t); fflush(stdout); + size_t optend = ((end - n) / N) * N + n; + for(; n < optend; n += N) { *(vNsf*)&(s[n]) += *(vNsf*)&(af->data[evt->t]); evt->t += N; } @@ -446,7 +452,10 @@ void DrumGizmo::getSamples(int ch, int pos, sample_t *s, size_t sz) } - if(evt->t >= af->size) removeevent = true; + if(evt->t >= af->size) { + removeevent = true; + loader.reset(af); + } } break; } diff --git a/src/drumkitloader.cc b/src/drumkitloader.cc index 79d000a..6516c7d 100644 --- a/src/drumkitloader.cc +++ b/src/drumkitloader.cc @@ -82,14 +82,40 @@ void DrumKitLoader::loadKit(DrumKit *kit) semaphore.post(); } +void DrumKitLoader::prepare(AudioFile* af) { + printf("Preparing audiofile %p (%d in queue)\n", af, load_queue.size()); + mutex.lock(); + af->ref_count++; + load_queue.push_back(af); +// if(ref_count.find(af) == ref_count.end()) { +// ref_count[af]++; +// } +// else { +// ref_count[af] = 0; +// } + mutex.unlock(); + semaphore.post(); +} + +void DrumKitLoader::reset(AudioFile* af) { + mutex.lock(); + af->ref_count--; + reset_queue.push_back(af); + mutex.unlock(); + semaphore.post(); +} + void DrumKitLoader::thread_main() { while(1) { DEBUG(loader, "before sem\n"); + semaphore.wait(); + DEBUG(loader, "after sem\n"); fflush(stdout); + if(quitit) return; if(skipit) { @@ -98,66 +124,88 @@ void DrumKitLoader::thread_main() continue; } - unsigned int count = 0; + if(!load_queue.empty()) { + printf("Loading remaining of audio file\n"); + AudioFile* af = load_queue.front(); + mutex.lock(); + load_queue.pop_front(); + mutex.unlock(); + af->loadNext(); + } + else if(!reset_queue.empty()) { + AudioFile* af = reset_queue.front(); + mutex.lock(); + if(af->ref_count <= 0) { + af->reset(); + af->ref_count = 0; + } + reset_queue.pop_front(); + mutex.unlock(); + } + else { // Initialize drum kit + printf("Initializing drum kit\n"); + unsigned int count = 0; - if(kit && !kit->isValid()) goto finish; + if(kit && !kit->isValid()) goto finish; - { // Count total number of files that need loading: - Instruments::iterator i = kit->instruments.begin(); - while(i != kit->instruments.end()) { - Instrument *instr = *i; - if(instr && !instr->isValid()) goto finish; + { // Count total number of files that need loading: + Instruments::iterator i = kit->instruments.begin(); + while(i != kit->instruments.end()) { + Instrument *instr = *i; + if(instr && !instr->isValid()) goto finish; - count += instr->audiofiles.size(); - i++; + count += instr->audiofiles.size(); + i++; + } } - } - { // Now actually load them: - unsigned int loaded = 0; - Instruments::iterator i = kit->instruments.begin(); - while(i != kit->instruments.end()) { - Instrument *instr = *i; + { // Now actually load them: + unsigned int loaded = 0; + Instruments::iterator i = kit->instruments.begin(); + while(i != kit->instruments.end()) { + Instrument *instr = *i; - if(instr && !instr->isValid()) goto finish; + if(instr && !instr->isValid()) goto finish; - std::vector::iterator a = instr->audiofiles.begin(); - while(a != instr->audiofiles.end()) { + std::vector::iterator a = instr->audiofiles.begin(); + while(a != instr->audiofiles.end()) { #if 0 #ifdef WIN32 - SleepEx(5000, FALSE); + SleepEx(5000, FALSE); #else - usleep(5000); + usleep(5000); #endif/*WIN32*/ #endif - AudioFile *af = *a; + AudioFile *af = *a; - if(af && !af->isValid()) goto finish; + if(af && !af->isValid()) goto finish; - af->load(); - loaded++; + af->load(); + + loaded++; - LoadStatusMessage *ls = new LoadStatusMessage(); - ls->number_of_files = count; - ls->numer_of_files_loaded = loaded; - ls->current_file = af->filename; - drumgizmo->sendGUIMessage(ls); + LoadStatusMessage *ls = new LoadStatusMessage(); + ls->number_of_files = count; + ls->numer_of_files_loaded = loaded; + ls->current_file = af->filename; + drumgizmo->sendGUIMessage(ls); - a++; + a++; - if(skipit) goto finish; - } + if(skipit) goto finish; + } - i++; + i++; + } } - } - mutex.lock(); - is_done = true; - mutex.unlock(); + mutex.lock(); + is_done = true; + mutex.unlock(); - finish: - continue; + finish: + continue; + } } } diff --git a/src/drumkitloader.h b/src/drumkitloader.h index 50b8236..9d14638 100644 --- a/src/drumkitloader.h +++ b/src/drumkitloader.h @@ -28,6 +28,7 @@ #define __DRUMGIZMO_DRUMKITLOADER_H__ #include +#include #include "thread.h" #include "semaphore.h" @@ -43,6 +44,9 @@ public: ~DrumKitLoader(); void loadKit(DrumKit *kit); + + void prepare(AudioFile* af); + void reset(AudioFile* af); void thread_main(); @@ -60,6 +64,9 @@ private: Mutex mutex; volatile bool quitit; volatile bool skipit; + std::list load_queue; + std::list reset_queue; + std::map ref_count; }; #endif/*__DRUMGIZMO_DRUMKITLOADER_H__*/ -- cgit v1.2.3