diff options
author | Bent Bisballe Nyeng <deva@aasimon.org> | 2016-01-28 14:58:41 +0100 |
---|---|---|
committer | Bent Bisballe Nyeng <deva@aasimon.org> | 2016-01-28 14:58:41 +0100 |
commit | 413c0703722835e48b98b85b8ded32f1f43555bb (patch) | |
tree | 9d195d00c020ed96e1a5ad2a10ed8e044d7623a9 /src | |
parent | 2087facd3727c52069ad65c5b791f24cba3101a2 (diff) |
Style fixes
Diffstat (limited to 'src')
-rw-r--r-- | src/audiofile.cc | 279 | ||||
-rw-r--r-- | src/audiofile.h | 74 | ||||
-rw-r--r-- | src/drumgizmo.cc | 1264 | ||||
-rw-r--r-- | src/drumgizmo.h | 62 | ||||
-rw-r--r-- | src/drumkitloader.cc | 231 | ||||
-rw-r--r-- | src/drumkitloader.h | 87 |
6 files changed, 879 insertions, 1118 deletions
diff --git a/src/audiofile.cc b/src/audiofile.cc index 5ceff59..e9b5976 100644 --- a/src/audiofile.cc +++ b/src/audiofile.cc @@ -38,225 +38,116 @@ #include "configuration.h" -AudioFile::AudioFile(std::string filename, int filechannel) +AudioFile::AudioFile(const std::string& filename, int filechannel) { - is_loaded = false; - this->filename = filename; - this->filechannel = filechannel; + is_loaded = false; + this->filename = filename; + this->filechannel = filechannel; - data = NULL; - size = 0; + data = nullptr; + size = 0; -#ifdef LAZYLOAD - preloaded_data = NULL; -#endif/*LAZYLOAD*/ - - magic = this; + magic = this; } AudioFile::~AudioFile() { - magic = NULL; - unload(); + magic = nullptr; + unload(); } bool AudioFile::isValid() { - return this == magic; + return this == magic; } void AudioFile::unload() { - // Make sure we don't unload the object while loading it... - MutexAutolock l(mutex); + // Make sure we don't unload the object while loading it... + MutexAutolock l(mutex); - is_loaded = false; + is_loaded = false; -#ifdef LAZYLOAD - if(data == preloaded_data) { - delete[] data; - data = NULL; - size = 0; - } else { - size = 0; - delete[] data; - data = NULL; - delete preloaded_data; - preloaded_data = NULL; - } -#else - delete[] data; - data = NULL; - size = 0; -#endif/*LAZYLOAD*/ + delete[] data; + data = nullptr; + size = 0; } #define BUFFER_SIZE 4092 void AudioFile::load(int num_samples) { - // Make sure we don't unload the object while loading it... - MutexAutolock l(mutex); - - /* - Lazy load of drum kits - init(); - return; - */ - - if(data) return; - - SF_INFO sf_info; - SNDFILE *fh = sf_open(filename.c_str(), SFM_READ, &sf_info); - if(!fh) { - ERR(audiofile,"SNDFILE Error (%s): %s\n", - filename.c_str(), sf_strerror(fh)); - return; - } - - if(num_samples == ALL_SAMPLES) { - num_samples = sf_info.frames; - } - - size = sf_info.frames; - preloadedsize = sf_info.frames; - - if(preloadedsize > (size_t)num_samples) { - preloadedsize = num_samples; - } - - sample_t* data = new sample_t[preloadedsize]; - if(sf_info.channels == 1) { - preloadedsize = sf_read_float(fh, data, preloadedsize); - } else { - // check filechannel exists - if(filechannel >= sf_info.channels) { - filechannel = sf_info.channels - 1; - } - sample_t buffer[BUFFER_SIZE]; - int readsize = BUFFER_SIZE / sf_info.channels; - int totalread = 0; - int read; - do { - read = sf_readf_float(fh, buffer, readsize); - for (int i = 0; (i < read) && (totalread < num_samples); i++) { - data[totalread++] = buffer[i * sf_info.channels + filechannel]; - } - } while( (read > 0) && - (totalread < (int)preloadedsize) && - (totalread < num_samples) ); - // set data size to total bytes read - preloadedsize = totalread; - } - - DEBUG(audiofile,"Loaded %d samples %p\n", (int)preloadedsize, this); - - sf_close(fh); - - this->data = data; - is_loaded = true; - - //DEBUG(audiofile, "Loading of %s completed.\n", filename.c_str()); + // Make sure we don't unload the object while loading it... + MutexAutolock l(mutex); + + if(data) + { + return; + } + + SF_INFO sf_info; + SNDFILE *fh = sf_open(filename.c_str(), SFM_READ, &sf_info); + if(!fh) + { + ERR(audiofile,"SNDFILE Error (%s): %s\n", + filename.c_str(), sf_strerror(fh)); + return; + } + + if(num_samples == ALL_SAMPLES) + { + num_samples = sf_info.frames; + } + + size = sf_info.frames; + preloadedsize = sf_info.frames; + + if(preloadedsize > (size_t)num_samples) + { + preloadedsize = num_samples; + } + + sample_t* data = new sample_t[preloadedsize]; + if(sf_info.channels == 1) + { + preloadedsize = sf_read_float(fh, data, preloadedsize); + } + else + { + // check filechannel exists + if(filechannel >= sf_info.channels) + { + filechannel = sf_info.channels - 1; + } + + sample_t buffer[BUFFER_SIZE]; + int readsize = BUFFER_SIZE / sf_info.channels; + int totalread = 0; + int read; + + do + { + read = sf_readf_float(fh, buffer, readsize); + for(int i = 0; (i < read) && (totalread < num_samples); ++i) + { + data[totalread++] = buffer[i * sf_info.channels + filechannel]; + } + } + while( (read > 0) && + (totalread < (int)preloadedsize) && + (totalread < num_samples) ); + + // set data size to total bytes read + preloadedsize = totalread; + } + + sf_close(fh); + + this->data = data; + is_loaded = true; } bool AudioFile::isLoaded() { - return is_loaded; -} - -#ifdef LAZYLOAD -#define SIZE 512*4 -void AudioFile::init() -{ - //DEBUG(audiofile,"Initializing %p\n", this); - if(data) { - //DEBUG(audiofile,"\t already initialized\n"); - return; - } - - SF_INFO sf_info; - SNDFILE *fh = sf_open(filename.c_str(), SFM_READ, &sf_info); - if(!fh) { - ERR(audiofile,"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); - - //DEBUG(audiofile,"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; - mutex.unlock(); -} - -void AudioFile::loadNext() -{ - if(this->data != this->preloaded_data) { - //DEBUG(audiofile,"Already completely loaded %p\n", this); - return; - } - - SF_INFO sf_info; - SNDFILE *fh = sf_open(filename.c_str(), SFM_READ, &sf_info); - if(!fh) { - ERR(audiofile,"SNDFILE Error (%s): %s\n", - filename.c_str(), sf_strerror(fh)); - return; - } - - int r; -// int size_accum = 0; - sample_t* data = new sample_t[sf_info.frames]; - memcpy(data, this->preloaded_data, this->size * sizeof(sample_t)); - this->data = data; - sf_seek(fh, this->size, SEEK_SET); -// sample_t* data_buf = new sample_t[SIZE]; - while(this->size < sf_info.frames) { - //DEBUG(audiofile,"Accumulated %d of %llu\n", size_accum, sf_info.frames); - //if( (r = sf_read_float(fh, data_buf, SIZE)) < 0) { - if( (r = sf_read_float(fh, &data[this->size], SIZE)) < 0) { - ERR(audiofile,"Error reading sound file\n"); - break; - } - //size_accum += r; - //memcpy(data+size_accum, data_buf, sizeof(sample_t) * r); - this->size += r; - } - //delete data_buf; - - //DEBUG(audiofile,"Finished loading %d samples %p\n", size, this); - sf_close(fh); - - //mutex.lock(); - //this->data = data; - //this->size = size; - //mutex.unlock(); -} - -void AudioFile::reset() -{ - //DEBUG(audiofile,"Resetting audio file %p\n", this); - if(this->data == this->preloaded_data) { - //DEBUG(audiofile,"\tNot completely loaded - skipping %p\n", this); - return; - } - - mutex.lock(); - volatile sample_t* old_data = data; - this->size = SIZE; - this->data = this->preloaded_data; - //DEBUG(audiofile,"Deleting data %p\n", this); - delete old_data; - mutex.unlock(); + return is_loaded; } -#endif diff --git a/src/audiofile.h b/src/audiofile.h index aefb8d6..3ca8b97 100644 --- a/src/audiofile.h +++ b/src/audiofile.h @@ -24,8 +24,7 @@ * along with DrumGizmo; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -#ifndef __DRUMGIZMO_AUDIOFILE_H__ -#define __DRUMGIZMO_AUDIOFILE_H__ +#pragma once #include <string> #include <map> @@ -36,74 +35,31 @@ #include "mutex.h" #include "audio.h" -/* - 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) - --------- -*/ - -//#define LAZYLOAD - #define ALL_SAMPLES -1 class AudioFile { public: - AudioFile(std::string filename, int filechannel); - ~AudioFile(); - - void load(int num_samples = ALL_SAMPLES); - void unload(); + AudioFile(const std::string& filename, int filechannel); + ~AudioFile(); - bool isLoaded(); + void load(int num_samples = ALL_SAMPLES); + void unload(); - volatile size_t size; // Full size of the file - volatile size_t preloadedsize; // Number of samples preloaded (in data) - sample_t *data; + bool isLoaded(); - std::string filename; + volatile size_t size{0}; // Full size of the file + volatile size_t preloadedsize{0}; // Number of samples preloaded (in data) + sample_t *data{nullptr}; -#ifdef LAZYLOAD -// SF_INFO sf_info; -// SNDFILE *fh; -// bool completely_loaded; - void init(); - void reset(); - void loadNext(); - sample_t* preloaded_data; -#endif/*LAZYLOAD*/ + std::string filename; - bool isValid(); + bool isValid(); - Mutex mutex; + Mutex mutex; - int filechannel; + int filechannel; private: - void *magic; - volatile bool is_loaded; + void *magic; + volatile bool is_loaded; }; - -#endif/*__DRUMGIZMO_AUDIOFILE_H__*/ diff --git a/src/drumgizmo.cc b/src/drumgizmo.cc index 3dc1306..26b8e65 100644 --- a/src/drumgizmo.cc +++ b/src/drumgizmo.cc @@ -46,346 +46,403 @@ #include "nolocale.h" DrumGizmo::DrumGizmo(AudioOutputEngine *o, AudioInputEngine *i) - : MessageReceiver(MSGRCV_ENGINE) - , loader() - , oe(o) - , ie(i) - , framesize(0) - , freewheel(false) + : MessageReceiver(MSGRCV_ENGINE) + , loader() + , oe(o) + , ie(i) + , framesize(0) + , freewheel(false) { - is_stopping = false; - audioCache.init(1000); // start thread + is_stopping = false; + audioCache.init(1000); // start thread } DrumGizmo::~DrumGizmo() { - audioCache.deinit(); // stop thread + audioCache.deinit(); // stop thread } bool DrumGizmo::loadkit(std::string file) { - if(file == "") return 1; + if(file == "") + { + return 1; + } - DEBUG(drumgizmo, "loadkit(%s)\n", file.c_str()); + DEBUG(drumgizmo, "loadkit(%s)\n", file.c_str()); - // Remove all queue AudioFiles from loader before we actually delete them. - loader.skip(); + // Remove all queue AudioFiles from loader before we actually delete them. + loader.skip(); - // Delete all Channels, Instruments, Samples and AudioFiles. - kit.clear(); + // Delete all Channels, Instruments, Samples and AudioFiles. + kit.clear(); - DrumKitParser parser(file, kit); - if(parser.parse()) { - ERR(drumgizmo, "Drumkit parser failed: %s\n", file.c_str()); - return false; - } + DrumKitParser parser(file, kit); + if(parser.parse()) + { + ERR(drumgizmo, "Drumkit parser failed: %s\n", file.c_str()); + return false; + } - loader.loadKit(&kit); + loader.loadKit(&kit); #ifdef WITH_RESAMPLER - for(int i = 0; i < MAX_NUM_CHANNELS; i++) { - resampler[i].setup(kit.samplerate(), Conf::samplerate); - } + for(int i = 0; i < MAX_NUM_CHANNELS; ++i) + { + resampler[i].setup(kit.samplerate(), Conf::samplerate); + } #endif/*WITH_RESAMPLER*/ - DEBUG(loadkit, "loadkit: Success\n"); + DEBUG(loadkit, "loadkit: Success\n"); - return true; + return true; } bool DrumGizmo::init() { - if(!ie->init(kit.instruments)) return false; - if(!oe->init(kit.channels)) return false; + if(!ie->init(kit.instruments)) + { + return false; + } - return true; + if(!oe->init(kit.channels)) + { + return false; + } + + return true; } void DrumGizmo::handleMessage(Message *msg) { - DEBUG(msg, "got message."); - switch(msg->type()) { - case Message::LoadDrumKit: - { - DEBUG(msg, "got LoadDrumKitMessage message."); - LoadDrumKitMessage *m = (LoadDrumKitMessage*)msg; - loadkit(m->drumkitfile); - //init(true); - } - break; - case Message::LoadMidimap: - DEBUG(msg, "got LoadMidimapMessage message."); - if(!ie->isMidiEngine()) break; - { - AudioInputEngineMidi *aim = (AudioInputEngineMidi*)ie; - LoadMidimapMessage *m = (LoadMidimapMessage*)msg; - bool ret = aim->loadMidiMap(m->midimapfile, kit.instruments); - - LoadStatusMessageMidimap *ls = new LoadStatusMessageMidimap(); - ls->success = ret; - msghandler.sendMessage(MSGRCV_UI, ls); - } - break; - case Message::EngineSettingsMessage: - { - bool mmap_loaded = false; - std::string mmapfile; - if(ie->isMidiEngine()) { - AudioInputEngineMidi *aim = (AudioInputEngineMidi*)ie; - mmapfile = aim->midimapFile(); - mmap_loaded = aim->isValid(); - } - - EngineSettingsMessage *msg = new EngineSettingsMessage(); - msg->midimapfile = mmapfile; - msg->midimap_loaded = mmap_loaded; - msg->drumkitfile = kit.file(); - msg->drumkit_loaded = loader.isDone(); - msg->enable_velocity_modifier = Conf::enable_velocity_modifier; - msg->velocity_modifier_falloff = Conf::velocity_modifier_falloff; - msg->velocity_modifier_weight = Conf::velocity_modifier_weight; - msg->enable_velocity_randomiser = Conf::enable_velocity_randomiser; - msg->velocity_randomiser_weight = Conf::velocity_randomiser_weight; - msghandler.sendMessage(MSGRCV_UI, msg); - } - break; - case Message::ChangeSettingMessage: - { - ChangeSettingMessage *ch = (ChangeSettingMessage*)msg; - switch(ch->name) { - case ChangeSettingMessage::enable_velocity_modifier: - Conf::enable_velocity_modifier = ch->value; - break; - case ChangeSettingMessage::velocity_modifier_weight: - Conf::velocity_modifier_weight = ch->value; - break; - case ChangeSettingMessage::velocity_modifier_falloff: - Conf::velocity_modifier_falloff = ch->value; - break; - } - } - break; - default: - break; - } + DEBUG(msg, "got message."); + switch(msg->type()) { + case Message::LoadDrumKit: + { + DEBUG(msg, "got LoadDrumKitMessage message."); + LoadDrumKitMessage *m = (LoadDrumKitMessage*)msg; + loadkit(m->drumkitfile); + //init(true); + } + break; + case Message::LoadMidimap: + DEBUG(msg, "got LoadMidimapMessage message."); + if(!ie->isMidiEngine()) + { + break; + } + { + AudioInputEngineMidi *aim = (AudioInputEngineMidi*)ie; + LoadMidimapMessage *m = (LoadMidimapMessage*)msg; + bool ret = aim->loadMidiMap(m->midimapfile, kit.instruments); + + LoadStatusMessageMidimap *ls = new LoadStatusMessageMidimap(); + ls->success = ret; + msghandler.sendMessage(MSGRCV_UI, ls); + } + break; + case Message::EngineSettingsMessage: + { + bool mmap_loaded = false; + std::string mmapfile; + if(ie->isMidiEngine()) + { + AudioInputEngineMidi *aim = (AudioInputEngineMidi*)ie; + mmapfile = aim->midimapFile(); + mmap_loaded = aim->isValid(); + } + + EngineSettingsMessage *msg = new EngineSettingsMessage(); + msg->midimapfile = mmapfile; + msg->midimap_loaded = mmap_loaded; + msg->drumkitfile = kit.file(); + msg->drumkit_loaded = loader.isDone(); + msg->enable_velocity_modifier = Conf::enable_velocity_modifier; + msg->velocity_modifier_falloff = Conf::velocity_modifier_falloff; + msg->velocity_modifier_weight = Conf::velocity_modifier_weight; + msg->enable_velocity_randomiser = Conf::enable_velocity_randomiser; + msg->velocity_randomiser_weight = Conf::velocity_randomiser_weight; + msghandler.sendMessage(MSGRCV_UI, msg); + } + break; + case Message::ChangeSettingMessage: + { + ChangeSettingMessage *ch = (ChangeSettingMessage*)msg; + switch(ch->name) { + case ChangeSettingMessage::enable_velocity_modifier: + Conf::enable_velocity_modifier = ch->value; + break; + case ChangeSettingMessage::velocity_modifier_weight: + Conf::velocity_modifier_weight = ch->value; + break; + case ChangeSettingMessage::velocity_modifier_falloff: + Conf::velocity_modifier_falloff = ch->value; + break; + } + } + break; + default: + break; + } } void DrumGizmo::setFrameSize(size_t framesize) { - // If we are resampling override the frame size. - if(resampler[0].ratio() != 1) { - framesize = RESAMPLER_INPUT_BUFFER; - } - - if(this->framesize != framesize) { - DEBUG(drumgizmo, "New framesize: %d\n", (int)framesize); - - this->framesize = framesize; - - // Update framesize in drumkitloader and cachemanager: - loader.setFrameSize(framesize); - audioCache.setFrameSize(framesize); - } + // If we are resampling override the frame size. + if(resampler[0].ratio() != 1) + { + framesize = RESAMPLER_INPUT_BUFFER; + } + + if(this->framesize != framesize) + { + DEBUG(drumgizmo, "New framesize: %d\n", (int)framesize); + + this->framesize = framesize; + + // Update framesize in drumkitloader and cachemanager: + loader.setFrameSize(framesize); + audioCache.setFrameSize(framesize); + } } void DrumGizmo::setFreeWheel(bool freewheel) { - // Freewheel = true means that we are bouncing and therefore running faster - // than realtime. - if(freewheel != this->freewheel) { - this->freewheel = freewheel; - audioCache.setAsyncMode(!freewheel); - } + // Freewheel = true means that we are bouncing and therefore running faster + // than realtime. + if(freewheel != this->freewheel) + { + this->freewheel = freewheel; + audioCache.setAsyncMode(!freewheel); + } } bool DrumGizmo::run(size_t pos, sample_t *samples, size_t nsamples) { - setFrameSize(nsamples); - - // Handle engine messages, at most one in each iteration: - handleMessages(1); - - ie->pre(); - oe->pre(nsamples); - - // - // Read new events - // - - //DEBUG(engine, "Number of active events: %d\n", activeevents[0].size()); - - size_t nev; - event_t *evs = ie->run(pos, nsamples, &nev); - - for(size_t e = 0; e < nev; e++) { - if(evs[e].type == TYPE_ONSET) { - Instrument *i = NULL; - int d = evs[e].instrument; - /* - Instruments::iterator it = kit.instruments.begin(); - while(d-- && it != kit.instruments.end()) { - i = &(it->second); - it++; - } - */ - - if(!kit.isValid()) continue; - - if(d < (int)kit.instruments.size()) { - i = kit.instruments[d]; - } - - if(i == NULL || !i->isValid()) { - ERR(drumgizmo, "Missing Instrument %d.\n", evs[e].instrument); - continue; - } - - if(i->group() != "") { - // Add event to ramp down all existing events with the same groupname. - Channels::iterator j = kit.channels.begin(); - while(j != kit.channels.end()) { - Channel &ch = *j; - std::list< Event* >::iterator evs = activeevents[ch.num].begin(); - while(evs != activeevents[ch.num].end()) { - Event *ev = *evs; - if(ev->type() == Event::sample) { - EventSample *sev = (EventSample*)ev; - if(sev->group == i->group() && sev->instrument != i) { - sev->rampdown = 3000; // Ramp down 3000 samples - // TODO: This must be configurable at some point... - // ... perhaps even by instrument (ie. in the xml file) - sev->ramp_start = sev->rampdown; - } - } - evs++; - } - j++; - } - } - - Sample *s = i->sample(evs[e].velocity, evs[e].offset + pos); - - if(s == NULL) { - ERR(drumgizmo, "Missing Sample.\n"); - continue; - } - - Channels::iterator j = kit.channels.begin(); - while(j != kit.channels.end()) { - Channel &ch = *j; - AudioFile *af = s->getAudioFile(&ch); - if(af) { - // LAZYLOAD: - // DEBUG(drumgizmo,"Requesting preparing of audio file\n"); - // loader.prepare(af); - } - if(af == NULL || !af->isValid()) { - //DEBUG(drumgizmo,"Missing AudioFile.\n"); - } else { - //DEBUG(drumgizmo, "Adding event %d.\n", evs[e].offset); - Event *evt = new EventSample(ch.num, 1.0, af, i->group(), i); - evt->offset = (evs[e].offset + pos) * resampler[0].ratio(); - activeevents[ch.num].push_back(evt); - } - j++; - } - } - - if(evs[e].type == TYPE_STOP) { - is_stopping = true; - } - - if(is_stopping) { - // Count the number of active events. - int num_active_events = 0; - Channels::iterator j = kit.channels.begin(); - while(j != kit.channels.end()) { - Channel &ch = *j; - num_active_events += activeevents[ch.num].size(); - j++; - } - - if(num_active_events == 0) { - // No more active events - now we can stop the engine. - return false; - } - } - - } - - free(evs); - - // - // Write audio - // + setFrameSize(nsamples); + + // Handle engine messages, at most one in each iteration: + handleMessages(1); + + ie->pre(); + oe->pre(nsamples); + + // + // Read new events + // + + //DEBUG(engine, "Number of active events: %d\n", activeevents[0].size()); + + size_t nev; + event_t *evs = ie->run(pos, nsamples, &nev); + + for(size_t e = 0; e < nev; ++e) + { + if(evs[e].type == TYPE_ONSET) + { + Instrument *i = nullptr; + int d = evs[e].instrument; + /* + Instruments::iterator it = kit.instruments.begin(); + while(d-- && it != kit.instruments.end()) + { + i = &(it->second); + ++it; + } + */ + + if(!kit.isValid()) + { + continue; + } + + if(d < (int)kit.instruments.size()) + { + i = kit.instruments[d]; + } + + if(i == nullptr || !i->isValid()) + { + ERR(drumgizmo, "Missing Instrument %d.\n", evs[e].instrument); + continue; + } + + if(i->group() != "") + { + // Add event to ramp down all existing events with the same groupname. + Channels::iterator j = kit.channels.begin(); + while(j != kit.channels.end()) + { + Channel &ch = *j; + std::list< Event* >::iterator evs = activeevents[ch.num].begin(); + while(evs != activeevents[ch.num].end()) + { + Event *ev = *evs; + if(ev->type() == Event::sample) + { + EventSample *sev = (EventSample*)ev; + if(sev->group == i->group() && sev->instrument != i) + { + sev->rampdown = 3000; // Ramp down 3000 samples + // TODO: This must be configurable at some point... + // ... perhaps even by instrument (ie. in the xml file) + sev->ramp_start = sev->rampdown; + } + } + ++evs; + } + ++j; + } + } + + Sample *s = i->sample(evs[e].velocity, evs[e].offset + pos); + + if(s == nullptr) + { + ERR(drumgizmo, "Missing Sample.\n"); + continue; + } + + Channels::iterator j = kit.channels.begin(); + while(j != kit.channels.end()) + { + Channel &ch = *j; + AudioFile *af = s->getAudioFile(&ch); + if(af) + { + // LAZYLOAD: + // DEBUG(drumgizmo,"Requesting preparing of audio file\n"); + // loader.prepare(af); + } + if(af == nullptr || !af->isValid()) + { + //DEBUG(drumgizmo,"Missing AudioFile.\n"); + } + else + { + //DEBUG(drumgizmo, "Adding event %d.\n", evs[e].offset); + Event *evt = new EventSample(ch.num, 1.0, af, i->group(), i); + evt->offset = (evs[e].offset + pos) * resampler[0].ratio(); + activeevents[ch.num].push_back(evt); + } + ++j; + } + } + + if(evs[e].type == TYPE_STOP) + { + is_stopping = true; + } + + if(is_stopping) + { + // Count the number of active events. + int num_active_events = 0; + Channels::iterator j = kit.channels.begin(); + while(j != kit.channels.end()) + { + Channel &ch = *j; + num_active_events += activeevents[ch.num].size(); + ++j; + } + + if(num_active_events == 0) + { + // No more active events - now we can stop the engine. + return false; + } + } + + } + + free(evs); + + // + // Write audio + // #ifdef WITH_RESAMPLER - if(Conf::enable_resampling == false || - resampler[0].ratio() == 1.0) { // No resampling needed + if((Conf::enable_resampling == false) || + (resampler[0].ratio() == 1.0)) // No resampling needed + { #endif - for(size_t c = 0; c < kit.channels.size(); c++) { - sample_t *buf = samples; - bool internal = false; - if(oe->getBuffer(c)) { - buf = oe->getBuffer(c); - internal = true; - } - if(buf) { - memset(buf, 0, nsamples * sizeof(sample_t)); - - getSamples(c, pos, buf, nsamples); - - if(!internal) oe->run(c, samples, nsamples); - } - } + for(size_t c = 0; c < kit.channels.size(); ++c) + { + sample_t *buf = samples; + bool internal = false; + if(oe->getBuffer(c)) + { + buf = oe->getBuffer(c); + internal = true; + } + + if(buf) + { + memset(buf, 0, nsamples * sizeof(sample_t)); + + getSamples(c, pos, buf, nsamples); + + if(!internal) + { + oe->run(c, samples, nsamples); + } + } + } #ifdef WITH_RESAMPLER - } else { - // Resampling needed - - // - // NOTE: Channels must be processed one buffer at a time on all channels in - // parallel - NOT all buffers on one channel and then all buffer on the next - // one since this would mess up the event queue (it would jump back and forth - // in time) - // - - // Prepare output buffer - for(size_t c = 0; c < kit.channels.size(); c++) { - resampler[c].setOutputSamples(resampler_output_buffer[c], nsamples); - } - - // Process channel data - size_t kitpos = pos * resampler[0].ratio(); - size_t insize = sizeof(resampler_input_buffer[0]) / sizeof(sample_t); - - while(resampler[0].getOutputSampleCount() > 0) { - for(size_t c = 0; c < kit.channels.size(); c++) { - if(resampler[c].getInputSampleCount() == 0) { - sample_t *sin = resampler_input_buffer[c]; - memset(resampler_input_buffer[c], 0, - sizeof(resampler_input_buffer[c])); - getSamples(c, kitpos, sin, insize); - - resampler[c].setInputSamples(sin, insize); - } - resampler[c].process(); - } - kitpos += insize; - } - - // Write output data to output engine. - for(size_t c = 0; c < kit.channels.size(); c++) { - oe->run(c, resampler_output_buffer[c], nsamples); - } - - } + } + else + { + // Resampling needed + + // + // NOTE: Channels must be processed one buffer at a time on all channels in + // parallel - NOT all buffers on one channel and then all buffer on the next + // one since this would mess up the event queue (it would jump back and + // forth in time) + // + + // Prepare output buffer + for(size_t c = 0; c < kit.channels.size(); ++c) + { + resampler[c].setOutputSamples(resampler_output_buffer[c], nsamples); + } + + // Process channel data + size_t kitpos = pos * resampler[0].ratio(); + size_t insize = sizeof(resampler_input_buffer[0]) / sizeof(sample_t); + + while(resampler[0].getOutputSampleCount() > 0) + { + for(size_t c = 0; c < kit.channels.size(); ++c) + { + if(resampler[c].getInputSampleCount() == 0) + { + sample_t *sin = resampler_input_buffer[c]; + memset(resampler_input_buffer[c], 0, + sizeof(resampler_input_buffer[c])); + getSamples(c, kitpos, sin, insize); + + resampler[c].setInputSamples(sin, insize); + } + resampler[c].process(); + } + kitpos += insize; + } + + // Write output data to output engine. + for(size_t c = 0; c < kit.channels.size(); ++c) + { + oe->run(c, resampler_output_buffer[c], nsamples); + } + + } #endif/*WITH_RESAMPLER*/ - - ie->post(); - oe->post(nsamples); - - pos += nsamples; - return true; + ie->post(); + oe->post(nsamples); + + pos += nsamples; + + return true; } #undef SSE // SSE broken for now ... so disable it. @@ -396,423 +453,278 @@ typedef float vNsf __attribute__ ((vector_size(sizeof(sample_t)*N))); void DrumGizmo::getSamples(int ch, int pos, sample_t *s, size_t sz) { - std::list< Event* >::iterator i = activeevents[ch].begin(); - for(; i != activeevents[ch].end(); ++i) { - bool removeevent = false; - - Event *event = *i; - - Event::type_t type = event->type(); - switch(type) { - case Event::sample: - { - EventSample *evt = (EventSample *)event; - AudioFile *af = evt->file; - - if(!af->isLoaded() || !af->isValid() || s == NULL) { - removeevent = true; - break; - } - - // Don't handle event now is is scheduled for a future iteration? - if(evt->offset > (pos + sz)) { - continue; - } - - if(evt->cache_id == CACHE_NOID) { - size_t initial_chunksize = (pos + sz) - evt->offset; - evt->buffer = audioCache.open(af, initial_chunksize, - af->filechannel, evt->cache_id); - evt->buffer_size = initial_chunksize; - } - - { - MutexAutolock l(af->mutex); - - size_t n = 0; // default start point is 0. - - // If we are not at offset 0 in current buffer: - if(evt->offset > (size_t)pos) { - n = evt->offset - pos; - } - - size_t end = sz; // default end point is the end of the buffer. - - // Find the end point intra-buffer - if((evt->t + end - n) > af->size) { - end = af->size - evt->t + n; - } - - // This should not be necessary but make absolutely sure that we do - // not write over the end of the buffer. - if(end > sz) { - end = sz; - } - - size_t t = 0; // Internal buffer counter - if(evt->rampdown == NO_RAMPDOWN) { + std::list< Event* >::iterator i = activeevents[ch].begin(); + for(; i != activeevents[ch].end(); ++i) + { + bool removeevent = false; + + Event *event = *i; + + Event::type_t type = event->type(); + switch(type) { + case Event::sample: + { + EventSample *evt = (EventSample *)event; + AudioFile *af = evt->file; + + if(!af->isLoaded() || !af->isValid() || (s == nullptr)) + { + removeevent = true; + break; + } + + // Don't handle event now is is scheduled for a future iteration? + if(evt->offset > (pos + sz)) + { + continue; + } + + if(evt->cache_id == CACHE_NOID) + { + size_t initial_chunksize = (pos + sz) - evt->offset; + evt->buffer = audioCache.open(af, initial_chunksize, + af->filechannel, evt->cache_id); + evt->buffer_size = initial_chunksize; + } + + { + MutexAutolock l(af->mutex); + + size_t n = 0; // default start point is 0. + + // If we are not at offset 0 in current buffer: + if(evt->offset > (size_t)pos) + { + n = evt->offset - pos; + } + + size_t end = sz; // default end point is the end of the buffer. + + // Find the end point intra-buffer + if((evt->t + end - n) > af->size) + { + end = af->size - evt->t + n; + } + + // This should not be necessary but make absolutely sure that we do + // not write over the end of the buffer. + if(end > sz) + { + end = sz; + } + + size_t t = 0; // Internal buffer counter + if(evt->rampdown == NO_RAMPDOWN) + { #ifdef SSE - size_t optend = ((end - n) / N) * N + n; - - // Force source addr to be 16 byte aligned... (might skip 1 or 2 samples) - while((size_t)&evt->buffer[t] % 16) { - ++t; - } - - for(; (n < optend) && (t < evt->buffer_size); n += N) { - *(vNsf*)&(s[n]) += *(vNsf*)&(evt->buffer[t]); - t += N; - } + size_t optend = ((end - n) / N) * N + n; + + // Force source addr to be 16 byte aligned... + // (might skip 1 or 2 samples) + while((size_t)&evt->buffer[t] % 16) + { + ++t; + } + + for(; (n < optend) && (t < evt->buffer_size); n += N) + { + *(vNsf*)&(s[n]) += *(vNsf*)&(evt->buffer[t]); + t += N; + } #endif - for(; (n < end) && (t < evt->buffer_size); n++) { - s[n] += evt->buffer[t]; - t++; - } - } else { // Ramp down in progress. - for(; (n < end) && (t < evt->buffer_size) && evt->rampdown; n++) { - float scale = (float)evt->rampdown/(float)evt->ramp_start; - s[n] += evt->buffer[t] * scale; - t++; - evt->rampdown--; - } - } - - evt->t += evt->buffer_size; // Add internal buffer counter to "global" event counter. - - if((evt->t < af->size) && (evt->rampdown != 0)) { - evt->buffer = audioCache.next(evt->cache_id, evt->buffer_size); - } else { - removeevent = true; - } - - if(removeevent) { - audioCache.close(evt->cache_id); - } - } - } - break; - } - - if(removeevent) { - delete event; - i = activeevents[ch].erase(i); - continue; - } - } + for(; (n < end) && (t < evt->buffer_size); ++n) + { + s[n] += evt->buffer[t]; + ++t; + } + } + else + { // Ramp down in progress. + for(; (n < end) && (t < evt->buffer_size) && evt->rampdown; ++n) + { + float scale = (float)evt->rampdown/(float)evt->ramp_start; + s[n] += evt->buffer[t] * scale; + ++t; + evt->rampdown--; + } + } + + // Add internal buffer counter to "global" event counter. + evt->t += evt->buffer_size; + + if((evt->t < af->size) && (evt->rampdown != 0)) + { + evt->buffer = audioCache.next(evt->cache_id, evt->buffer_size); + } + else + { + removeevent = true; + } + + if(removeevent) + { + audioCache.close(evt->cache_id); + } + } + } + break; + } + + if(removeevent) + { + delete event; + i = activeevents[ch].erase(i); + continue; + } + } } void DrumGizmo::stop() { - // engine.stop(); + // engine.stop(); } int DrumGizmo::samplerate() { - return Conf::samplerate; + return Conf::samplerate; } void DrumGizmo::setSamplerate(int samplerate) { DEBUG(dgeditor, "%s samplerate: %d\n", __PRETTY_FUNCTION__, samplerate); - Conf::samplerate = samplerate; + Conf::samplerate = samplerate; #ifdef WITH_RESAMPLER - for(int i = 0; i < MAX_NUM_CHANNELS; i++) { - resampler[i].setup(kit.samplerate(), Conf::samplerate); - } - if(resampler[0].ratio() != 1) { - setFrameSize(RESAMPLER_INPUT_BUFFER); - } + for(int i = 0; i < MAX_NUM_CHANNELS; ++i) + { + resampler[i].setup(kit.samplerate(), Conf::samplerate); + } + if(resampler[0].ratio() != 1) + { + setFrameSize(RESAMPLER_INPUT_BUFFER); + } #endif/*WITH_RESAMPLER*/ - } std::string float2str(float a) { - char buf[256]; - snprintf_nol(buf, sizeof(buf) - 1, "%f", a); - return buf; + char buf[256]; + snprintf_nol(buf, sizeof(buf) - 1, "%f", a); + return buf; } std::string bool2str(bool a) { - return a?"true":"false"; + return a?"true":"false"; } float str2float(std::string a) { - if(a == "") return 0.0; - return atof_nol(a.c_str()); + if(a == "") + { + return 0.0; + } + + return atof_nol(a.c_str()); } std::string DrumGizmo::configString() { - std::string mmapfile; - if(ie->isMidiEngine()) { - AudioInputEngineMidi *aim = (AudioInputEngineMidi*)ie; - mmapfile = aim->midimapFile(); - } - - return - "<config>\n" - " <value name=\"drumkitfile\">" + kit.file() + "</value>\n" - " <value name=\"midimapfile\">" + mmapfile + "</value>\n" - " <value name=\"enable_velocity_modifier\">" + - bool2str(Conf::enable_velocity_modifier) + "</value>\n" - " <value name=\"velocity_modifier_falloff\">" + - float2str(Conf::velocity_modifier_falloff) + "</value>\n" - " <value name=\"velocity_modifier_weight\">" + - float2str(Conf::velocity_modifier_weight) + "</value>\n" - " <value name=\"enable_velocity_randomiser\">" + - bool2str(Conf::enable_velocity_randomiser) + "</value>\n" - " <value name=\"velocity_randomiser_weight\">" + - float2str(Conf::velocity_randomiser_weight) + "</value>\n" - "</config>"; + std::string mmapfile; + if(ie->isMidiEngine()) + { + AudioInputEngineMidi *aim = (AudioInputEngineMidi*)ie; + mmapfile = aim->midimapFile(); + } + + return + "<config>\n" + " <value name=\"drumkitfile\">" + kit.file() + "</value>\n" + " <value name=\"midimapfile\">" + mmapfile + "</value>\n" + " <value name=\"enable_velocity_modifier\">" + + bool2str(Conf::enable_velocity_modifier) + "</value>\n" + " <value name=\"velocity_modifier_falloff\">" + + float2str(Conf::velocity_modifier_falloff) + "</value>\n" + " <value name=\"velocity_modifier_weight\">" + + float2str(Conf::velocity_modifier_weight) + "</value>\n" + " <value name=\"enable_velocity_randomiser\">" + + bool2str(Conf::enable_velocity_randomiser) + "</value>\n" + " <value name=\"velocity_randomiser_weight\">" + + float2str(Conf::velocity_randomiser_weight) + "</value>\n" + "</config>"; } - bool DrumGizmo::setConfigString(std::string cfg) { - DEBUG(config, "Load config: %s\n", cfg.c_str()); - - std::string dkf; - ConfigParser p; - if(p.parse(cfg)) { - ERR(drumgizmo, "Config parse error.\n"); - return false; - } - - if(p.value("enable_velocity_modifier") != "") { - Conf::enable_velocity_modifier = - p.value("enable_velocity_modifier") == "true"; - } - - if(p.value("velocity_modifier_falloff") != "") { - Conf::velocity_modifier_falloff = - str2float(p.value("velocity_modifier_falloff")); - } - - if(p.value("velocity_modifier_weight") != "") { - Conf::velocity_modifier_weight = - str2float(p.value("velocity_modifier_weight")); - } - - if(p.value("enable_velocity_randomiser") != "") { - Conf::enable_velocity_randomiser = - p.value("enable_velocity_randomiser") == "true"; - } - - if(p.value("velocity_randomiser_weight") != "") { - Conf::velocity_randomiser_weight = - str2float(p.value("velocity_randomiser_weight")); - } - - if(p.value("enable_resampling") != "") { - Conf::enable_resampling = - p.value("enable_resampling") == "true"; - } - - std::string newkit = p.value("drumkitfile"); - if(newkit != "" && kit.file() != newkit) { - /* - if(!loadkit(p.values["drumkitfile"])) return false; - init(true); - */ - LoadDrumKitMessage *msg = new LoadDrumKitMessage(); - msg->drumkitfile = newkit; - msghandler.sendMessage(MSGRCV_ENGINE, msg); - } - - std::string newmidimap = p.value("midimapfile"); - if(newmidimap != "") { - //midimapfile = newmidimap; - LoadMidimapMessage *msg = new LoadMidimapMessage(); - msg->midimapfile = newmidimap; - msghandler.sendMessage(MSGRCV_ENGINE, msg); - } - - return true; -} - -#ifdef TEST_DRUMGIZMO -//deps: instrument.cc sample.cc channel.cc audiofile.cc drumkit.cc drumkitparser.cc configuration.cc saxparser.cc instrumentparser.cc path.cc -//cflags: $(SNDFILE_CFLAGS) $(EXPAT_CFLAGS) -I../include -DSSE -msse -msse2 -msse3 -//libs: $(SNDFILE_LIBS) $(EXPAT_LIBS) -#include "test.h" - -static float f(size_t x) -{ - return x + 1.0; + DEBUG(config, "Load config: %s\n", cfg.c_str()); + + std::string dkf; + ConfigParser p; + if(p.parse(cfg)) + { + ERR(drumgizmo, "Config parse error.\n"); + return false; + } + + if(p.value("enable_velocity_modifier") != "") + { + Conf::enable_velocity_modifier = + p.value("enable_velocity_modifier") == "true"; + } + + if(p.value("velocity_modifier_falloff") != "") + { + Conf::velocity_modifier_falloff = + str2float(p.value("velocity_modifier_falloff")); + } + + if(p.value("velocity_modifier_weight") != "") + { + Conf::velocity_modifier_weight = + str2float(p.value("velocity_modifier_weight")); + } + + if(p.value("enable_velocity_randomiser") != "") + { + Conf::enable_velocity_randomiser = + p.value("enable_velocity_randomiser") == "true"; + } + + if(p.value("velocity_randomiser_weight") != "") + { + Conf::velocity_randomiser_weight = + str2float(p.value("velocity_randomiser_weight")); + } + + if(p.value("enable_resampling") != "") + { + Conf::enable_resampling = + p.value("enable_resampling") == "true"; + } + + std::string newkit = p.value("drumkitfile"); + if(newkit != "" && kit.file() != newkit) + { + /* + if(!loadkit(p.values["drumkitfile"])) + { + return false; + } + init(true); + */ + LoadDrumKitMessage *msg = new LoadDrumKitMessage(); + msg->drumkitfile = newkit; + msghandler.sendMessage(MSGRCV_ENGINE, msg); + } + + std::string newmidimap = p.value("midimapfile"); + if(newmidimap != "") + { + //midimapfile = newmidimap; + LoadMidimapMessage *msg = new LoadMidimapMessage(); + msg->midimapfile = newmidimap; + msghandler.sendMessage(MSGRCV_ENGINE, msg); + } + + return true; } - -class AITest : public AudioInputEngine { -public: - bool init(Instruments &instruments) { return true; } - void setParm(std::string parm, std::string value) {} - bool start() { return true; } - void stop() {} - void pre() {} - event_t *run(size_t pos, size_t len, size_t *nevents) - { - event_t *e = NULL; - *nevents = 0; - - if(pos <= offset && offset < pos + len) { - e = new event_t; - - e->type = TYPE_ONSET; - e->instrument = 0; - e->velocity = 1.0; - e->offset = offset - pos; - - *nevents = 1; - } - return e; - } - void post() {} - size_t offset; -}; - -class AOTest : public AudioOutputEngine { -public: - bool init(Channels channels) { return true; } - void setParm(std::string parm, std::string value) {} - bool start() { return true; } - void stop() {} - void pre(size_t nsamples) {} - void run(int ch, sample_t *samples, size_t nsamples) - { - } - void post(size_t nsamples) {} -}; - -const char xml_kit[] = - "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" - "<drumkit name=\"test\" description=\"\">\n" - " <channels>\n" - " <channel name=\"ch1\"/>\n" - " </channels>\n" - " <instruments>\n" - " <instrument name=\"instr1\" file=\"instr1.xml\">\n" - " <channelmap in=\"ch1\" out=\"ch1\"/>\n" - " </instrument>\n" - " </instruments>\n" - "</drumkit>"; - -const char xml_instr[] = - "<?xml version='1.0' encoding='UTF-8'?>\n" - "<instrument name=\"instr1\">\n" - " <samples>\n" - " <sample name=\"sample1\">\n" - " <audiofile channel=\"ch1\" file=\"instr1.wav\"/>\n" - " </sample>\n" - " </samples>\n" - " <velocities>\n" - " <velocity lower=\"0\" upper=\"1.0\">\n" - " <sampleref name=\"sample1\"/>\n" - " </velocity>\n" - " </velocities>\n" - "</instrument>"; - -#define PCM_SIZE 100 - -void createTestKit() -{ - FILE *fp; - fp = fopen("/tmp/kit.xml", "w"); - fwrite(xml_kit, strlen(xml_kit), 1, fp); - fclose(fp); - - fp = fopen("/tmp/instr1.xml", "w"); - fwrite(xml_instr, strlen(xml_instr), 1, fp); - fclose(fp); - - SF_INFO sf_info; - sf_info.format = SF_FORMAT_WAV | SF_FORMAT_FLOAT; - sf_info.samplerate = 44100; - sf_info.channels = 1; - - SNDFILE *fh = sf_open("/tmp/instr1.wav", SFM_WRITE, &sf_info); - if(!fh) { - printf("Error: %s\n", sf_strerror(fh)); - } - - size_t size = PCM_SIZE; - sample_t samples[size]; - - for(size_t i = 0; i < size; i++) { - samples[i] = f(i);//(float)i / (float)size; - } - - sf_write_float(fh, samples, size); - sf_close(fh); -} - -void deleteTestKit() -{ - unlink("/tmp/kit.xml"); - unlink("/tmp/instr1.xml"); - unlink("/tmp/instr1.wav"); -} - -TEST_BEGIN; - -createTestKit(); - -size_t size = PCM_SIZE; -//for(size_t chunksz = 1; chunksz < size + 1; chunksz++) { -size_t chunksz = 16; { - sample_t samples[chunksz]; - - for(size_t offset = 0; offset < chunksz + size + 1; offset++) { - //size_t offset = 5; { - for(size_t padding = 0; padding < chunksz + size + offset + 1; padding++) { - //size_t padding = 2; { - TEST_MSG("Values (offset %d, padding %d, chunksz %d)", - offset, padding, chunksz); - - AOTest ao; - AITest ai; ai.offset = offset; - DrumGizmo dg(&ao, &ai); - dg.loadkit("/tmp/kit.xml"); - - size_t pos = 0; - // sample_t samples[chunksz]; - while(pos < offset + size + padding) { - dg.run(pos, samples, chunksz); - - float err = 0; - size_t errcnt = 0; - for(size_t i = 0; i < chunksz && pos < offset + size + padding; i++) { - float val = 0.0; - if(pos >= offset && pos < (offset + size)) val = f(pos - offset); - float diff = samples[i] - val; - /* - if(diff != 0.0) { - TEST_EQUAL_FLOAT(samples[i], val, - "samples[%d] ?= val, pos %d", i, pos); - } - */ - if(diff != 0.0) errcnt++; - - err += fabs(diff); - pos++; - } - - TEST_EQUAL_FLOAT(err, 0.0, - "Compare error (offset %d, padding %d, chunksz %d)", - offset, padding, chunksz); - TEST_EQUAL_INT(errcnt, 0, - "Compare count (offset %d, padding %d, chunksz %d)", - offset, padding, chunksz); - } - - } - } -} - -deleteTestKit(); - -TEST_END; - -#endif/*TEST_DRUMGIZMO*/ diff --git a/src/drumgizmo.h b/src/drumgizmo.h index 1e38e08..98cd287 100644 --- a/src/drumgizmo.h +++ b/src/drumgizmo.h @@ -53,52 +53,54 @@ #define REFSFILE "refs.conf" #define RESAMPLER_INPUT_BUFFER 64 -class DrumGizmo : public MessageReceiver { +class DrumGizmo + : public MessageReceiver +{ public: - DrumGizmo(AudioOutputEngine *outputengine, AudioInputEngine *inputengine); - virtual ~DrumGizmo(); + DrumGizmo(AudioOutputEngine *outputengine, AudioInputEngine *inputengine); + virtual ~DrumGizmo(); - bool loadkit(std::string kitfile); + bool loadkit(std::string kitfile); - bool init(); + bool init(); - bool run(size_t pos, sample_t *samples, size_t nsamples); - void stop(); + bool run(size_t pos, sample_t *samples, size_t nsamples); + void stop(); - void getSamples(int ch, int pos, sample_t *s, size_t sz); + void getSamples(int ch, int pos, sample_t *s, size_t sz); - std::string configString(); - bool setConfigString(std::string cfg); + std::string configString(); + bool setConfigString(std::string cfg); - void handleMessage(Message *msg); + void handleMessage(Message *msg); - int samplerate(); - void setSamplerate(int samplerate); + int samplerate(); + void setSamplerate(int samplerate); - void setFrameSize(size_t framesize); + void setFrameSize(size_t framesize); - void setFreeWheel(bool freewheel); + void setFreeWheel(bool freewheel); -private: - DrumKitLoader loader; +protected: + DrumKitLoader loader; - Mutex mutex; - bool is_stopping; ///< Is set to true when a TYPE_STOP event has been seen. + Mutex mutex; + bool is_stopping; ///< Is set to true when a TYPE_STOP event has been seen. - AudioOutputEngine *oe; - AudioInputEngine *ie; + AudioOutputEngine *oe; + AudioInputEngine *ie; - std::list< Event* > activeevents[MAX_NUM_CHANNELS]; + std::list< Event* > activeevents[MAX_NUM_CHANNELS]; - CHResampler resampler[MAX_NUM_CHANNELS]; - sample_t resampler_output_buffer[MAX_NUM_CHANNELS][4096]; - sample_t resampler_input_buffer[MAX_NUM_CHANNELS][RESAMPLER_INPUT_BUFFER]; + CHResampler resampler[MAX_NUM_CHANNELS]; + sample_t resampler_output_buffer[MAX_NUM_CHANNELS][4096]; + sample_t resampler_input_buffer[MAX_NUM_CHANNELS][RESAMPLER_INPUT_BUFFER]; - std::map<std::string, AudioFile *> audiofiles; + std::map<std::string, AudioFile *> audiofiles; - AudioCache audioCache; - DrumKit kit; + AudioCache audioCache; + DrumKit kit; - size_t framesize; - bool freewheel; + size_t framesize; + bool freewheel; }; diff --git a/src/drumkitloader.cc b/src/drumkitloader.cc index 0a44db0..64d6710 100644 --- a/src/drumkitloader.cc +++ b/src/drumkitloader.cc @@ -32,146 +32,165 @@ #include "drumgizmo.h" DrumKitLoader::DrumKitLoader() - : semaphore("drumkitloader") - , framesize(0) + : semaphore("drumkitloader") + , framesize(0) { - run(); - run_semaphore.wait(); // Wait for the thread to actually start. + run(); + run_semaphore.wait(); // Wait for the thread to actually start. } DrumKitLoader::~DrumKitLoader() { DEBUG(loader, "~DrumKitLoader() pre\n"); - if(running) { - framesize_semaphore.post(); - stop(); - } + + if(running) + { + framesize_semaphore.post(); + stop(); + } + DEBUG(loader, "~DrumKitLoader() post\n"); } void DrumKitLoader::stop() { - { - MutexAutolock l(mutex); - load_queue.clear(); - } - - running = false; - semaphore.post(); - wait_stop(); + { + MutexAutolock l(mutex); + load_queue.clear(); + } + + running = false; + semaphore.post(); + wait_stop(); } void DrumKitLoader::skip() { - MutexAutolock l(mutex); - load_queue.clear(); + MutexAutolock l(mutex); + load_queue.clear(); } void DrumKitLoader::setFrameSize(size_t framesize) { DEBUG(loader, "%s pre\n", __PRETTY_FUNCTION__); + { - MutexAutolock l(mutex); - this->framesize = framesize; - framesize_semaphore.post(); // Signal that the framesize has been set. + MutexAutolock l(mutex); + this->framesize = framesize; + framesize_semaphore.post(); // Signal that the framesize has been set. } + DEBUG(loader, "%s post\n", __PRETTY_FUNCTION__); } bool DrumKitLoader::isDone() { - MutexAutolock l(mutex); - return load_queue.size() == 0; + MutexAutolock l(mutex); + return load_queue.size() == 0; } void DrumKitLoader::loadKit(DrumKit *kit) { - MutexAutolock l(mutex); - - DEBUG(loader, "Create AudioFile queue from DrumKit\n"); - - total_num_audiofiles = 0;// For UI Progress Messages - - { // Count total number of files that need loading: - Instruments::iterator i = kit->instruments.begin(); - while(i != kit->instruments.end()) { - Instrument *instr = *i; - total_num_audiofiles += instr->audiofiles.size(); - i++; - } - } - - fraction = total_num_audiofiles / 200; - if(fraction == 0) fraction = 1; - - { // Now actually queue them for loading: - Instruments::iterator i = kit->instruments.begin(); - while(i != kit->instruments.end()) { - Instrument *instr = *i; - - std::vector<AudioFile*>::iterator af = instr->audiofiles.begin(); - while(af != instr->audiofiles.end()) { - AudioFile *audiofile = *af; - load_queue.push_back(audiofile); - af++; - } - - i++; - } - } - - loaded = 0; // For UI Progress Messages - - DEBUG(loader, "Queued %d (size: %d) AudioFiles for loading.\n", - (int)total_num_audiofiles, (int)load_queue.size()); - - semaphore.post(); // Start loader loop. + MutexAutolock l(mutex); + + DEBUG(loader, "Create AudioFile queue from DrumKit\n"); + + total_num_audiofiles = 0;// For UI Progress Messages + + { // Count total number of files that need loading: + Instruments::iterator i = kit->instruments.begin(); + while(i != kit->instruments.end()) + { + Instrument *instr = *i; + total_num_audiofiles += instr->audiofiles.size(); + ++i; + } + } + + fraction = total_num_audiofiles / 200; + if(fraction == 0) + { + fraction = 1; + } + + { // Now actually queue them for loading: + Instruments::iterator i = kit->instruments.begin(); + while(i != kit->instruments.end()) + { + Instrument *instr = *i; + + std::vector<AudioFile*>::iterator af = instr->audiofiles.begin(); + while(af != instr->audiofiles.end()) + { + AudioFile *audiofile = *af; + load_queue.push_back(audiofile); + af++; + } + + ++i; + } + } + + loaded = 0; // For UI Progress Messages + + DEBUG(loader, "Queued %d (size: %d) AudioFiles for loading.\n", + (int)total_num_audiofiles, (int)load_queue.size()); + + semaphore.post(); // Start loader loop. } void DrumKitLoader::thread_main() { - running = true; - - run_semaphore.post(); // Signal that the thread has been started. - - framesize_semaphore.wait(); // Wait until the framesize has been set. - - while(running) { - size_t size; - { - MutexAutolock l(mutex); - size = load_queue.size(); - } - - // Only sleep if queue is empty. - if(size == 0) semaphore.wait(); - - std::string filename; - { - MutexAutolock l(mutex); - if(load_queue.size() == 0) continue; - AudioFile *audiofile = load_queue.front(); - load_queue.pop_front(); - filename = audiofile->filename; - size_t preload_size = framesize * CHUNK_MULTIPLIER + framesize; - if(preload_size < 1024) - { + running = true; + + run_semaphore.post(); // Signal that the thread has been started. + + framesize_semaphore.wait(); // Wait until the framesize has been set. + + while(running) + { + size_t size; + { + MutexAutolock l(mutex); + size = load_queue.size(); + } + + // Only sleep if queue is empty. + if(size == 0) + { + semaphore.wait(); + } + + std::string filename; + { + MutexAutolock l(mutex); + if(load_queue.size() == 0) + { + continue; + } + AudioFile *audiofile = load_queue.front(); + load_queue.pop_front(); + filename = audiofile->filename; + size_t preload_size = framesize * CHUNK_MULTIPLIER + framesize; + if(preload_size < 1024) + { preload_size = 1024; - } - (void)preload_size; - audiofile->load(ALL_SAMPLES); // Note: Change this to enable diskstreaming - } - - loaded++; - - if(loaded % fraction == 0 || loaded == total_num_audiofiles) { - LoadStatusMessage *ls = new LoadStatusMessage(); - ls->number_of_files = total_num_audiofiles; - ls->numer_of_files_loaded = loaded; - ls->current_file = filename; - msghandler.sendMessage(MSGRCV_UI, ls); - } - } - - DEBUG(loader, "Loader thread finished."); + } + (void)preload_size; + audiofile->load(ALL_SAMPLES); // Note: Change this to enable diskstreaming + } + + loaded++; + + if(loaded % fraction == 0 || loaded == total_num_audiofiles) + { + LoadStatusMessage *ls = new LoadStatusMessage(); + ls->number_of_files = total_num_audiofiles; + ls->numer_of_files_loaded = loaded; + ls->current_file = filename; + msghandler.sendMessage(MSGRCV_UI, ls); + } + } + + DEBUG(loader, "Loader thread finished."); } diff --git a/src/drumkitloader.h b/src/drumkitloader.h index 22859a0..0532691 100644 --- a/src/drumkitloader.h +++ b/src/drumkitloader.h @@ -24,8 +24,7 @@ * along with DrumGizmo; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -#ifndef __DRUMGIZMO_DRUMKITLOADER_H__ -#define __DRUMGIZMO_DRUMKITLOADER_H__ +#pragma once #include <string> #include <list> @@ -36,69 +35,51 @@ #include "drumkit.h" -/** - * This class is responsible for loading the drumkits in its own thread. - * All interaction calls are simply modifying queues and not doing any - * work in-sync with the caller. - * This means that if loadKit(...) is called, one cannot assume that the - * drumkit has actually been loaded when the call returns. - */ -class DrumKitLoader : public Thread { +//! This class is responsible for loading the drumkits in its own thread. +//! All interaction calls are simply modifying queues and not doing any +//! work in-sync with the caller. +//! This means that if loadKit(...) is called, one cannot assume that the +//! drumkit has actually been loaded when the call returns. +class DrumKitLoader + : public Thread +{ public: - /** - * The constrcutor starts the loader thread. - */ - DrumKitLoader(); + //! The constrcutor starts the loader thread. + DrumKitLoader(); - /** - * The destructor signals the thread to stop and waits to merge before - * returning (ie. deleting the object will garantuee that the thread has - * been stopped). - */ - ~DrumKitLoader(); + //! The destructor signals the thread to stop and waits to merge before + //! returning (ie. deleting the object will garantuee that the thread has + //! been stopped). + ~DrumKitLoader(); - /** - * Signal the loader to start loading all audio files contained in kit. - * All other AudioFiles in queue will be removed before the new ones are - * scheduled. - */ - void loadKit(DrumKit *kit); - - // I have no idea what this does.. - //void reset(AudioFile* af); + //! Signal the loader to start loading all audio files contained in kit. + //! All other AudioFiles in queue will be removed before the new ones are + //! scheduled. + void loadKit(DrumKit *kit); - void thread_main(); + void thread_main(); - /** - * Simply reports if the load queue is empty (i.e. all AudioFiles has been - * loaded). - */ - bool isDone(); + //! Simply reports if the load queue is empty (i.e. all AudioFiles has been + //! loaded). + bool isDone(); - /** - * Signal the loader to stop and wait until it has. - */ - void stop(); + //! Signal the loader to stop and wait until it has. + void stop(); - /** - * Skip all queued AudioFiles. - */ - void skip(); + //! Skip all queued AudioFiles. + void skip(); - void setFrameSize(size_t framesize); + void setFrameSize(size_t framesize); -private: - Semaphore run_semaphore; - Semaphore semaphore; - Semaphore framesize_semaphore; - Mutex mutex; +protected: + Semaphore run_semaphore; + Semaphore semaphore; + Semaphore framesize_semaphore; + Mutex mutex; volatile bool running{false}; - std::list<AudioFile*> load_queue; + std::list<AudioFile*> load_queue; size_t total_num_audiofiles{0}; size_t fraction{1}; size_t loaded{0}; - size_t framesize{0}; }; - -#endif/*__DRUMGIZMO_DRUMKITLOADER_H__*/ |