From 62bd868f56a00c0340a0d1e35626ffbef10f5db0 Mon Sep 17 00:00:00 2001 From: Bent Bisballe Nyeng Date: Wed, 11 Jan 2012 09:42:06 +0100 Subject: New SSE optimised buffer accumulation + tests. --- src/drumgizmo.cc | 358 ++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 327 insertions(+), 31 deletions(-) (limited to 'src') diff --git a/src/drumgizmo.cc b/src/drumgizmo.cc index 7da5947..5b48e0c 100644 --- a/src/drumgizmo.cc +++ b/src/drumgizmo.cc @@ -53,8 +53,15 @@ DrumGizmo::~DrumGizmo() */ } +std::string DrumGizmo::drumkitfile() +{ + return kitfile; +} + bool DrumGizmo::loadkit(const std::string &kitfile) { + this->kitfile = kitfile; + kit = DrumKit(); DrumKitParser parser(kitfile, kit); if(parser.parse()) return false; /* @@ -159,9 +166,15 @@ bool DrumGizmo::run(size_t pos, sample_t *samples, size_t nsamples) // for(size_t c = 0; c < kit.channels.size(); c++) { - memset(samples, 0, nsamples * sizeof(sample_t)); - getSamples(c, pos, samples, nsamples); - oe->run(c, samples, nsamples); + sample_t *buf = samples; + bool internal = false; + if(oe->getBuffer(c)) { + buf = oe->getBuffer(c); + internal = true; + } + memset(buf, 0, nsamples * sizeof(sample_t)); + getSamples(c, pos, buf, nsamples); + if(!internal) oe->run(c, samples, nsamples); } ie->post(); @@ -189,6 +202,19 @@ void DrumGizmo::run() oe->stop(); } +#ifdef SSE +#define SZ 16 +typedef float v4sf __attribute__ ((vector_size (sizeof(float)*SZ))); + +union f4vector +{ + v4sf v; + float f[SZ]; +}; +#else/*SSE*/ +#define SZ 0 +#endif/*SSE*/ + void DrumGizmo::getSamples(int ch, int pos, sample_t *s, size_t sz) { for(std::list< Event* >::iterator i = activeevents[ch].begin(); @@ -206,22 +232,25 @@ void DrumGizmo::getSamples(int ch, int pos, sample_t *s, size_t sz) AudioFile *af = evt->file; af->load(); // Make sure it is loaded. - for(size_t n = 0; n < sz; n++) { + 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(evt->offset > (pos + n)) continue; +#ifdef SSE + size_t optend = ((end - n) / SZ) * SZ; + for(; n < optend; n+=SZ) { + *(v4sf*)&(s[n]) += *(v4sf*)&(af->data[evt->t]); + evt->t += SZ; + } +#endif - if(evt->t > af->size) { - removeevent = true; - break; - } - - //float gain = evt->gain; - //gain *= 1.0 - ((float)evt->t / (float)af->size); - sample_t val = af->data[evt->t]; - s[n] += val;// * gain; - + for(; n < end; n++) { + s[n] += af->data[evt->t]; evt->t++; } + + if(evt->t > af->size) removeevent = true; } break; } @@ -239,34 +268,301 @@ void DrumGizmo::stop() // engine.stop(); } +#include "configuration.h" + +std::string float2str(float a) +{ + char buf[256]; + sprintf(buf, "%f", a); + return buf; +} + +std::string bool2str(bool a) +{ + return a?"true":"false"; +} + +float str2float(std::string a) +{ + if(a == "") return 0.0; + return atof(a.c_str()); +} + +std::string DrumGizmo::configString() +{ + return + "\n" + " " + kitfile + "\n" + " " + midimapfile + "\n" + " " + + bool2str(Conf::enable_velocity_modifier) + "\n" + " " + + float2str(Conf::velocity_modifier_falloff) + "\n" + " " + + float2str(Conf::velocity_modifier_weight) + "\n" + " " + + bool2str(Conf::enable_velocity_randomiser) + "\n" + " " + + float2str(Conf::velocity_randomiser_weight) + "\n" + ""; +} + +#include "saxparser.h" + +class ConfigParser : public SAXParser { +public: + ConfigParser() + { + str = NULL; + } + + void characterData(std::string &data) + { + if(str) str->append(data); + } + + void startTag(std::string name, attr_t attr) + { + if(name == "value" && attr.find("name") != attr.end()) { + values[attr["name"]] = ""; + str = &values[attr["name"]]; + } + } + + void endTag(std::string name) + { + if(name == "value") str = NULL; + } + + std::string value(std::string name, std::string def = "") + { + if(values.find(name) == values.end()) return def; + return values[name]; + } + + std::map values; + std::string *str; +}; + +void DrumGizmo::setConfigString(std::string cfg) +{ + printf("Load config: %s\n", cfg.c_str()); + + std::string dkf; + ConfigParser p; + p.parse(cfg); + + midimapfile = p.value("midimapfile"); + + 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(drumkitfile() != p.value("drumkitfile")) { + loadkit(p.values["drumkitfile"]); + init(true); + } +} + #ifdef TEST_DRUMGIZMO -//deps: instrument.cc sample.cc channel.cc audiofile.cc event.cc -//cflags: $(SNDFILE_CFLAGS) -//libs: $(SNDFILE_LIBS) +//deps: instrument.cc sample.cc channel.cc audiofile.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" -class AudioOutputEngineDummy : public AudioOutputEngine { +static float f(size_t x) +{ + return x + 1.0; +} + +class AITest : public AudioInputEngine { public: - bool init(Channels *channels) { return true; } - void run(DrumGizmo *drumgizmo) {} + 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[] = + "\n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + ""; + +const char xml_instr[] = + "\n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + ""; + +#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; -AudioOutputEngineDummy a; -DrumGizmo g(a); +createTestKit(); -Channel ch0("ch0"); g.channels.push_back(ch0); -Channel ch1("ch1"); g.channels.push_back(ch1); +size_t size = PCM_SIZE; +for(size_t chunksz = 1; chunksz < offset + size + padding + 1; chunksz++) { -Instrument i("test"); -Sample s1; i.addSample(0.0, 1.0, &s1); -Sample s2; i.addSample(0.0, 1.0, &s2); -Sample s3; i.addSample(0.0, 1.0, &s3); + sample_t samples[chunksz]; -//g.kit.instruments["instr"] = i; + 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); + } + + } + } +} -g.run(); +deleteTestKit(); TEST_END; -- cgit v1.2.3