diff options
Diffstat (limited to 'src/drumgizmo.cc')
-rw-r--r-- | src/drumgizmo.cc | 1253 |
1 files changed, 623 insertions, 630 deletions
diff --git a/src/drumgizmo.cc b/src/drumgizmo.cc index 7ce05ef..a777125 100644 --- a/src/drumgizmo.cc +++ b/src/drumgizmo.cc @@ -46,718 +46,711 @@ #include "nolocale.h" DrumGizmo::DrumGizmo(AudioOutputEngine *o, AudioInputEngine *i) - : MessageReceiver(MSGRCV_ENGINE), - loader(), oe(o), ie(i) + : MessageReceiver(MSGRCV_ENGINE) + , loader() + , oe(o) + , ie(i) + , framesize(0) + , freewheel(false) { - is_stopping = false; + is_stopping = false; + audioCache.init(1000); // start thread } DrumGizmo::~DrumGizmo() { + 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; + } } -bool DrumGizmo::run(size_t pos, sample_t *samples, size_t nsamples) +void DrumGizmo::setFrameSize(size_t framesize) { - // 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 - // -#ifdef WITH_RESAMPLER - 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); - } - } -#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); - - //printf("ratio: %f\n", resampler[c].ratio()); - 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; + // 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); + } +} - return true; +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); + } } void DrumGizmo::run(int endpos) { - size_t pos = 0; - size_t nsamples = oe->getBufferSize(); - sample_t *samples = (sample_t *)malloc(nsamples * sizeof(sample_t)); + size_t pos = 0; + size_t nsamples = oe->getBufferSize(); + sample_t *samples = (sample_t *)malloc(nsamples * sizeof(sample_t)); + + setFrameSize(oe->getBufferSize()); + + ie->start(); + oe->start(); - ie->start(); - oe->start(); + while(run(pos, samples, nsamples) == true) + { + pos += nsamples; + if((endpos != -1) && (pos >= (size_t)endpos)) + { + break; + } + } + + ie->stop(); + oe->stop(); + + free(samples); +} + +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 = 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 + { +#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); + } + } + } +#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); + } + + } +#endif/*WITH_RESAMPLER*/ - while(run(pos, samples, nsamples) == true) { - pos += nsamples; - if(endpos != -1 && pos >= (size_t)endpos) break; - } + ie->post(); + oe->post(nsamples); - ie->stop(); - oe->stop(); + pos += nsamples; - free(samples); + return true; } +#undef SSE // SSE broken for now ... so disable it. #ifdef SSE #define N 8 -typedef float vNsf __attribute__ ((vector_size(sizeof(float)*N))); +typedef float vNsf __attribute__ ((vector_size(sizeof(sample_t)*N))); #endif/*SSE*/ void DrumGizmo::getSamples(int ch, int pos, sample_t *s, size_t sz) { - std::list< Event* >::iterator i = activeevents[ch].begin(); - while(i != activeevents[ch].end()) { - 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; - } - - { - MutexAutolock l(af->mutex); - - size_t n = 0; - if(evt->offset > (size_t)pos) n = evt->offset - pos; - size_t end = sz; - if((evt->t + end - n) > af->size) end = af->size - evt->t + n; - if(end > sz) end = sz; - - 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 -// DEBUG(drumgizmo,"%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; - } + 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; n++) { - s[n] += af->data[evt->t]; - evt->t++; - } - } else { // Ramp down in progress. - for(; n < end && evt->rampdown; n++) { - float scale = (float)evt->rampdown/(float)evt->ramp_start; - s[n] += af->data[evt->t] * scale; - evt->t++; - evt->rampdown--; - } - - if(evt->rampdown == 0) { - removeevent = true; // Down ramp done. Remove event. - } - } - - if(evt->t >= af->size) { - removeevent = true; - } - - } - } - break; - } - - if(removeevent) { - delete event; - i = activeevents[ch].erase(i); - continue; - } - i++; - } + 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) { - Conf::samplerate = samplerate; + DEBUG(dgeditor, "%s samplerate: %d\n", __PRETTY_FUNCTION__, samplerate); + Conf::samplerate = samplerate; #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); + } + 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*/ |