--- linuxsampler/trunk/src/engines/sfz/sfz.cpp 2009/10/23 17:53:17 2012 +++ linuxsampler/trunk/src/engines/sfz/sfz.cpp 2010/05/30 11:40:31 2101 @@ -2,8 +2,8 @@ * * * LinuxSampler - modular, streaming capable sampler * * * - * Copyright (C) 2008-2009 Anders Dahnielson * - * Copyright (C) 2009 Grigor Iliev * + * Copyright (C) 2008 Anders Dahnielson * + * Copyright (C) 2009 - 2010 Anders Dahnielson and Grigor Iliev * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * @@ -25,6 +25,9 @@ #include #include +#include +#include +#include #include "../../common/File.h" #include "../../common/Path.h" @@ -33,8 +36,8 @@ namespace sfz { - LinuxSampler::SampleFile* SampleManager::FindSample(std::string samplePath) { - std::map >::iterator it = sampleMap.begin(); + Sample* SampleManager::FindSample(std::string samplePath) { + std::map >::iterator it = sampleMap.begin(); for (; it != sampleMap.end(); it++) { if (it->first->GetFile() == samplePath) return it->first; } @@ -61,18 +64,7 @@ ///////////////////////////////////////////////////////////// // class Definition - Definition::Definition() : - locc(128), hicc(128), start_locc(128), start_hicc(128), stop_locc(128), - stop_hicc(128), on_locc(128), on_hicc(128), delay_oncc(128), delay_samples_oncc(128), - offset_oncc(128), amp_velcurve_(128), gain_oncc(128), xfin_locc(128), xfin_hicc(128), - xfout_locc(128), xfout_hicc(128), cutoff_oncc(128), cutoff2_oncc(128), cutoff_smoothcc(128), - cutoff2_smoothcc(128), cutoff_stepcc(128), cutoff2_stepcc(128), cutoff_curvecc(128), - cutoff2_curvecc(128), resonance_oncc(128), resonance2_oncc(128), resonance_smoothcc(128), - resonance2_smoothcc(128), resonance_stepcc(128), resonance2_stepcc(128), - resonance_curvecc(128), resonance2_curvecc(128), eq1_freq_oncc(128), eq2_freq_oncc(128), - eq3_freq_oncc(128), eq1_bw_oncc(128), eq2_bw_oncc(128), eq3_bw_oncc(128), - eq1_gain_oncc(128), eq2_gain_oncc(128), eq3_gain_oncc(128) - + Definition::Definition() { } @@ -86,6 +78,7 @@ Region::Region() { pSample = NULL; + seq_counter = 1; } Region::~Region() @@ -93,12 +86,12 @@ DestroySampleIfNotUsed(); } - LinuxSampler::SampleFile* Region::GetSample(bool create) + Sample* Region::GetSample(bool create) { if(pSample == NULL && create) { - LinuxSampler::SampleFile* sf = GetInstrument()->GetSampleManager()->FindSample(sample); + Sample* sf = GetInstrument()->GetSampleManager()->FindSample(sample); if (sf != NULL) pSample = sf; // Reuse already created sample - else pSample = new LinuxSampler::SampleFile(sample); + else pSample = new Sample(sample); GetInstrument()->GetSampleManager()->AddSampleConsumer(pSample, this); } return pSample; @@ -114,74 +107,55 @@ } } - bool - Region::OnKey(uint8_t chan, uint8_t key, uint8_t vel, - int bend, uint8_t bpm, uint8_t chanaft, uint8_t polyaft, - uint8_t prog, float rand, trigger_t trig, uint8_t* cc, - float timer, uint8_t seq, bool* sw, uint8_t last_sw_key, uint8_t prev_sw_key) - { - // chan (MIDI channel) - // key (MIDI note) - // vel (MIDI velocity) - - // bend (MIDI pitch bend) - // bpm (host BPM) - // chanaft (MIDI channel pressure) - // polyaft (MIDI polyphonic aftertouch) - // prog (MIDI program change) - // rand (generated random number) - // trigger (how it was triggered) - // cc (all 128 CC values) - - // timer (time since previous region in the group was triggered) - // seq (the state of the region sequence counter) - // sw (the state of region key switches, 128 possible values) - // last_sw_key (the last key pressed in the key switch range) - // prev_sw_key (the previous note value) - - bool is_triggered ( - chan >= lochan && chan <= hichan && - key >= lokey && key <= hikey && - vel >= lovel && vel <= hivel && - bend >= lobend && bend <= hibend && - bpm >= lobpm && bpm <= hibpm && - chanaft >= lochanaft && chanaft <= hichanaft && - polyaft >= lopolyaft && polyaft <= hipolyaft && - prog >= loprog && prog <= hiprog && - rand >= lorand && rand <= hirand && - timer >= lotimer && timer <= hitimer && - seq == seq_position && - - ( (sw_lokey == -1 || sw_hikey == -1 || sw_last == -1) || - ((sw_last >= sw_lokey && sw_last <= sw_hikey) ? (last_sw_key == sw_last) : true) ) && + bool Region::OnKey(const Query& q) { + bool is_triggered( + q.chan >= lochan && q.chan <= hichan && + q.key >= lokey && q.key <= hikey && + q.vel >= lovel && q.vel <= hivel && + q.bend >= lobend && q.bend <= hibend && + q.bpm >= lobpm && q.bpm < hibpm && + q.chanaft >= lochanaft && q.chanaft <= hichanaft && + q.polyaft >= lopolyaft && q.polyaft <= hipolyaft && + q.prog >= loprog && q.prog <= hiprog && + q.rand >= lorand && q.rand < hirand && + q.timer >= lotimer && q.timer <= hitimer && + + ( sw_last == -1 || + ((sw_last >= sw_lokey && sw_last <= sw_hikey) ? (q.last_sw_key == sw_last) : false) ) && + + ( sw_down == -1 || + ((sw_down >= sw_lokey && (sw_hikey == -1 || sw_down <= sw_hikey)) ? (q.sw[sw_down]) : false) ) && - ( (sw_down == -1 || sw_lokey == -1 || sw_hikey == -1) || - ((sw_down >= sw_lokey && sw_down <= sw_hikey) ? (sw[sw_down]) : true) ) && + ( sw_up == -1 || + ((sw_up >= sw_lokey && (sw_hikey == -1 || sw_up <= sw_hikey)) ? (!q.sw[sw_up]) : true) ) && - ( (sw_up == -1 || sw_lokey == -1 || sw_hikey == -1) || - ((sw_up >= sw_lokey && sw_up <= sw_hikey) ? (!sw[sw_up]) : true) ) && + ( sw_previous == -1 || + q.prev_sw_key == sw_previous ) && - ((sw_previous != -1) ? (prev_sw_key == sw_previous) : true) && - ((trigger && trig) != 0) + ((trigger & q.trig) != 0) ); if (!is_triggered) return false; - for (int i = 0; i < 128; ++i) - { - if (locc[i] != -1 && hicc[i] != -1 && !(cc[i] >= locc[i] && cc[i] <= hicc[i])) + for (int i = 0; i < 128; ++i) { + if (locc[i] != -1 && hicc[i] != -1 && !(q.cc[i] >= locc[i] && q.cc[i] <= hicc[i])) return false; } - return true; + // seq_position has to be checked last, so we know that we + // increment the right counter + is_triggered = (seq_counter == seq_position); + seq_counter = (seq_counter % seq_length) + 1; + + return is_triggered; } bool Region::OnControl(uint8_t chan, uint8_t cont, uint8_t val, int bend, uint8_t bpm, uint8_t chanaft, uint8_t polyaft, uint8_t prog, float rand, trigger_t trig, uint8_t* cc, - float timer, uint8_t seq, bool* sw, uint8_t last_sw_key, uint8_t prev_sw_key) + float timer, bool* sw, uint8_t last_sw_key, uint8_t prev_sw_key) { // chan (MIDI channel) // cont (MIDI controller) @@ -197,7 +171,6 @@ // cc (all CC values) // timer (time since previous region in the group was triggered) - // seq (the state of the region sequence counter) // sw (the state of region key switches, 128 possible values) // last_sw_key (the last key pressed in the key switch range) // prev_sw_key (the previous note value) @@ -207,25 +180,26 @@ ((val >= on_locc[cont] && val <= on_hicc[cont]) || (val >= start_locc[cont] && val <= start_hicc[cont])) && bend >= lobend && bend <= hibend && - bpm >= lobpm && bpm <= hibpm && + bpm >= lobpm && bpm < hibpm && chanaft >= lochanaft && chanaft <= hichanaft && polyaft >= lopolyaft && polyaft <= hipolyaft && prog >= loprog && prog <= hiprog && - rand >= lorand && rand <= hirand && + rand >= lorand && rand < hirand && timer >= lotimer && timer <= hitimer && - seq == seq_position && - ( (sw_lokey == -1 || sw_hikey == -1 || sw_last == -1) || - ((sw_last >= sw_lokey && sw_last <= sw_hikey) ? (last_sw_key == sw_last) : true) ) && + ( sw_last == -1 || + ((sw_last >= sw_lokey && sw_last <= sw_hikey) ? (last_sw_key == sw_last) : false) ) && + + ( sw_down == -1 || + ((sw_down >= sw_lokey && (sw_hikey == -1 || sw_down <= sw_hikey)) ? (sw[sw_down]) : false) ) && - ( (sw_down == -1 || sw_lokey == -1 || sw_hikey == -1) || - ((sw_down >= sw_lokey && sw_down <= sw_hikey) ? (sw[sw_down]) : true) ) && + ( sw_up == -1 || + ((sw_up >= sw_lokey && (sw_hikey == -1 || sw_up <= sw_hikey)) ? (!sw[sw_up]) : true) ) && - ( (sw_up == -1 || sw_lokey == -1 || sw_hikey == -1) || - ((sw_up >= sw_lokey && sw_up <= sw_hikey) ? (!sw[sw_up]) : true) ) && + ( sw_previous == -1 || + prev_sw_key == sw_previous ) && - ((sw_previous != -1) ? (prev_sw_key == sw_previous) : true) && - ((trigger && trig) != 0) + ((trigger & trig) != 0) ); if (!is_triggered) @@ -246,6 +220,23 @@ return new Articulation(); //todo: implement GetArticulation() } + bool Region::HasLoop() { + bool b = loop_mode == ::sfz::LOOP_CONTINUOUS || loop_mode == ::sfz::LOOP_SUSTAIN; // TODO: ONE_SHOT mode + return b && GetLoopStart() && GetLoopEnd() && GetLoopEnd() > GetLoopStart(); + } + + uint Region::GetLoopStart() { + return (!loop_start) ? 0 : *loop_start; // TODO: use sample loop when loop_start not defined + } + + uint Region::GetLoopEnd() { + return (!loop_end) ? 0 : *loop_end; // TODO: use sample loop when loop_end not defined + } + + uint Region::GetLoopCount() { + return (!count) ? 0 : *count; + } + ///////////////////////////////////////////////////////////// // class Instrument @@ -263,21 +254,16 @@ regions.clear(); } - std::vector Instrument::GetRegionsOnKey ( - uint8_t chan, uint8_t key, uint8_t vel, - int bend, uint8_t bpm, uint8_t chanaft, uint8_t polyaft, - uint8_t prog, float rand, trigger_t trig, uint8_t* cc, - float timer, uint8_t seq, bool* sw, uint8_t last_sw_key, uint8_t prev_sw_key - ) { - std::vector v; - for (int i = 0; i < regions.size(); i++) { - if (regions[i]->OnKey ( - chan, key, vel, bend, bpm, chanaft, polyaft, prog, - rand, trig, cc, timer, seq, sw, last_sw_key, prev_sw_key) - ) { v.push_back(regions[i]); } - } + Query::Query(const Instrument& instrument) { + i = instrument.regions.begin(); + regions_end = instrument.regions.end(); + } - return v; + Region* Query::next() { + while (i != regions_end) { + if ((*i++)->OnKey(*this)) return *i; + } + return 0; } bool Instrument::DestroyRegion(Region* pRegion) { @@ -347,7 +333,7 @@ trigger = TRIGGER_ATTACK; - group.unset(); + group = 0; off_by.unset(); off_mode = OFF_FAST; @@ -434,58 +420,100 @@ for (int i = 0; i < 128; ++i) { // input control - locc[i] = 0; - hicc[i] = 127; - start_locc[i] = -1; - start_hicc[i] = -1; - stop_locc[i] = -1; - stop_hicc[i] = -1; - on_locc[i] = -1; - on_hicc[i] = -1; + locc.set(i, 0); + hicc.set(i, 127); + start_locc.set(i, -1); + start_hicc.set(i, -1); + stop_locc.set(i, -1); + stop_hicc.set(i, -1); + on_locc.set(i, -1); + on_hicc.set(i, -1); // sample player - delay_oncc[i].unset(); - delay_samples_oncc[i].unset(); - offset_oncc[i].unset(); + delay_oncc.set(i, optional::nothing); + delay_samples_oncc.set(i, optional::nothing); + offset_oncc.set(i, optional::nothing); // amplifier - amp_velcurve_[i] = 0; //fixme: 20 log (127^2 / i^2) - gain_oncc[i] = 0; - xfin_locc[i] = 0; - xfin_hicc[i] = 0; - xfout_locc[i] = 127; - xfout_hicc[i] = 127; + amp_velcurve.set(i, -1); + gain_oncc.set(i, 0); + xfin_locc.set(i, 0); + xfin_hicc.set(i, 0); + xfout_locc.set(i, 127); + xfout_hicc.set(i, 127); // filter - cutoff_oncc[i] = 0; - cutoff_smoothcc[i] = 0; - cutoff_stepcc[i] = 0; - cutoff_curvecc[i] = 0; - resonance_oncc[i] = 0; - resonance_smoothcc[i] = 0; - resonance_stepcc[i] = 0; - resonance_curvecc[i] = 0; - - cutoff2_oncc[i] = 0; - cutoff2_smoothcc[i] = 0; - cutoff2_stepcc[i] = 0; - cutoff2_curvecc[i] = 0; - resonance2_oncc[i] = 0; - resonance2_smoothcc[i] = 0; - resonance2_stepcc[i] = 0; - resonance2_curvecc[i] = 0; + cutoff_oncc.set(i, 0); + cutoff_smoothcc.set(i, 0); + cutoff_stepcc.set(i, 0); + cutoff_curvecc.set(i, 0); + resonance_oncc.set(i, 0); + resonance_smoothcc.set(i, 0); + resonance_stepcc.set(i, 0); + resonance_curvecc.set(i, 0); + + cutoff2_oncc.set(i, 0); + cutoff2_smoothcc.set(i, 0); + cutoff2_stepcc.set(i, 0); + cutoff2_curvecc.set(i, 0); + resonance2_oncc.set(i, 0); + resonance2_smoothcc.set(i, 0); + resonance2_stepcc.set(i, 0); + resonance2_curvecc.set(i, 0); // per voice equalizer - eq1_freq_oncc[i] = 0; - eq2_freq_oncc[i] = 0; - eq3_freq_oncc[i] = 0; - eq1_bw_oncc[i] = 0; - eq2_bw_oncc[i] = 0; - eq3_bw_oncc[i] = 0; - eq1_gain_oncc[i] = 0; - eq2_gain_oncc[i] = 0; - eq3_gain_oncc[i] = 0; - } + eq1_freq_oncc.set(i, 0); + eq2_freq_oncc.set(i, 0); + eq3_freq_oncc.set(i, 0); + eq1_bw_oncc.set(i, 0); + eq2_bw_oncc.set(i, 0); + eq3_bw_oncc.set(i, 0); + eq1_gain_oncc.set(i, 0); + eq2_gain_oncc.set(i, 0); + eq3_gain_oncc.set(i, 0); + } + + eg.clear(); + + // deprecated + ampeg_delay = 0; + ampeg_start = 0; //in percentage + ampeg_attack = 0; + ampeg_hold = 0; + ampeg_decay = 0; + ampeg_sustain = 100; // in percentage + ampeg_release = 0; + + fileg_delay = 0; + fileg_start = 0; //in percentage + fileg_attack = 0; + fileg_hold = 0; + fileg_decay = 0; + fileg_sustain = 100; // in percentage + fileg_release = 0; + + pitcheg_delay = 0; + pitcheg_start = 0; //in percentage + pitcheg_attack = 0; + pitcheg_hold = 0; + pitcheg_decay = 0; + pitcheg_sustain = 100; // in percentage + pitcheg_release = 0; + + amplfo_delay = 0; + amplfo_fade = 0; + amplfo_freq = 0; + amplfo_depth = 0; + + fillfo_delay = 0; + fillfo_fade = 0; + fillfo_freq = 0; + fillfo_depth = 0; + + pitchlfo_delay = 0; + pitchlfo_fade = 0; + pitchlfo_freq = 0; + pitchlfo_depth = 0; } Region* @@ -571,7 +599,7 @@ region->amp_keytrack = amp_keytrack; region->amp_keycenter = amp_keycenter; region->amp_veltrack = amp_veltrack; - region->amp_velcurve_ = amp_velcurve_; + region->amp_velcurve = amp_velcurve; region->amp_random = amp_random; region->rt_decay = rt_decay; region->gain_oncc = gain_oncc; @@ -665,6 +693,49 @@ region->eq2_vel2gain = eq2_vel2gain; region->eq3_vel2gain = eq3_vel2gain; + // envelope generator + region->eg = eg; + + // deprecated + region->ampeg_delay = ampeg_delay; + region->ampeg_start = ampeg_start; + region->ampeg_attack = ampeg_attack; + region->ampeg_hold = ampeg_hold; + region->ampeg_decay = ampeg_decay; + region->ampeg_sustain = ampeg_sustain; + region->ampeg_release = ampeg_release; + + region->fileg_delay = fileg_delay; + region->fileg_start = fileg_start; + region->fileg_attack = fileg_attack; + region->fileg_hold = fileg_hold; + region->fileg_decay = fileg_decay; + region->fileg_sustain = fileg_sustain; + region->fileg_release = fileg_release; + + region->pitcheg_delay = pitcheg_delay; + region->pitcheg_start = pitcheg_start; + region->pitcheg_attack = pitcheg_attack; + region->pitcheg_hold = pitcheg_hold; + region->pitcheg_decay = pitcheg_decay; + region->pitcheg_sustain = pitcheg_sustain; + region->pitcheg_release = pitcheg_release; + + region->amplfo_delay = amplfo_delay; + region->amplfo_fade = amplfo_fade; + region->amplfo_freq = amplfo_freq; + region->amplfo_depth = amplfo_depth; + + region->fillfo_delay = fillfo_delay; + region->fillfo_fade = fillfo_fade; + region->fillfo_freq = fillfo_freq; + region->fillfo_depth = fillfo_depth; + + region->pitchlfo_delay = pitchlfo_delay; + region->pitchlfo_fade = pitchlfo_fade; + region->pitchlfo_freq = pitchlfo_freq; + region->pitchlfo_depth = pitchlfo_depth; + return region; } @@ -679,7 +750,7 @@ { _instrument = new Instrument(LinuxSampler::Path::getBaseName(file), pSampleManager); _current_group = new Group(); - pCurDef = _current_group; + pCurDef = _current_group; enum token_type_t { HEADER, OPCODE }; token_type_t token_type; std::string token_string; @@ -762,6 +833,7 @@ } } + std::set velcurves; for (int i = 0; i < _instrument->regions.size(); i++) { ::sfz::Region* pRegion = _instrument->regions[i]; int low = pRegion->lokey; @@ -774,14 +846,53 @@ // get keyswitches low = pRegion->sw_lokey; + if (low < 0) low = 0; high = pRegion->sw_hikey; - if(low == -1 && high == -1) { + if (high == -1) { // Key switches not defined, so nothing to do - } else if(low >= 0 && low <= 127 && high >= 0 && high <= 127 && high >= low) { + } else if (low >= 0 && low <= 127 && high >= 0 && high <= 127 && high >= low) { for (int j = low; j <= high; j++) _instrument->KeySwitchBindings[j] = true; } else { std::cerr << "Invalid key switch range: " << low << " - " << high << std::endl; } + + // create velocity response curve + + // don't use copy-on-write here, instead change the actual + // unique buffers in memory + float* velcurve = const_cast(&pRegion->amp_velcurve[0]); + if (velcurves.insert(velcurve).second) { + int prev = 0; + float prevvalue = 0; + for (int v = 0 ; v < 128 ; v++) { + if (velcurve[v] >= 0) { + float step = (velcurve[v] - prevvalue) / (v - prev); + for ( ; prev < v ; prev++) { + velcurve[prev] = prevvalue; + prevvalue += step; + } + } + } + if (prev) { + float step = (1 - prevvalue) / (127 - prev); + for ( ; prev < 128 ; prev++) { + velcurve[prev] = prevvalue; + prevvalue += step; + } + } else { + // default curve + for (int v = 0 ; v < 128 ; v++) { + velcurve[v] = v * v / (127.0 * 127.0); + } + } + + // apply amp_veltrack + float offset = -pRegion->amp_veltrack; + if (offset <= 0) offset += 100; + for (int v = 0 ; v < 128 ; v++) { + velcurve[v] = (offset + pRegion->amp_veltrack * velcurve[v]) / 100; + } + } } } @@ -804,15 +915,15 @@ { _current_section = GROUP; _current_group->Reset(); - pCurDef = _current_group; + pCurDef = _current_group; } else if (token == "") { _current_section = REGION; _current_region = _current_group->RegionFactory(); - pCurDef = _current_region; + pCurDef = _current_region; _instrument->regions.push_back(_current_region); - _current_region->SetInstrument(_instrument); + _current_region->SetInstrument(_instrument); } else if (token == "") { @@ -837,6 +948,7 @@ std::string::size_type delimiter_index = token.find('='); std::string key = token.substr(0, delimiter_index); std::string value = token.substr(delimiter_index + 1); + int x, y; // sample definition if ("sample" == key) @@ -883,12 +995,11 @@ // input controls else if ("lochan" == key) pCurDef->lochan = ToInt(value); else if ("hichan" == key) pCurDef->hichan = ToInt(value); - else if ("lokey" == key) pCurDef->lokey = ToInt(value) + note_offset + 12 * octave_offset; - else if ("hikey" == key) pCurDef->hikey = ToInt(value) + note_offset + 12 * octave_offset; + else if ("lokey" == key) pCurDef->lokey = parseKey(value); + else if ("hikey" == key) pCurDef->hikey = parseKey(value); else if ("key" == key) { - pCurDef->lokey = ToInt(value) + note_offset + 12 * octave_offset; - pCurDef->hikey = ToInt(value) + note_offset + 12 * octave_offset; + pCurDef->lokey = pCurDef->hikey = pCurDef->pitch_keycenter = parseKey(value); } else if ("lovel" == key) pCurDef->lovel = ToInt(value); else if ("hivel" == key) pCurDef->hivel = ToInt(value); @@ -908,12 +1019,12 @@ else if ("hitimer" == key) pCurDef->hitimer = ToFloat(value); else if ("seq_length" == key) pCurDef->seq_length = ToInt(value); else if ("seq_position" == key) pCurDef->seq_position = ToInt(value); - else if ("sw_lokey" == key) pCurDef->sw_lokey = ToInt(value) + note_offset + 12 * octave_offset; - else if ("sw_hikey" == key) pCurDef->sw_hikey = ToInt(value) + note_offset + 12 * octave_offset; - else if ("sw_last" == key) pCurDef->sw_last = ToInt(value) + note_offset + 12 * octave_offset; - else if ("sw_down" == key) pCurDef->sw_down = ToInt(value) + note_offset + 12 * octave_offset; - else if ("sw_up" == key) pCurDef->sw_up = ToInt(value) + note_offset + 12 * octave_offset; - else if ("sw_previous" == key) pCurDef->sw_previous = ToInt(value) + note_offset + 12 * octave_offset; + else if ("sw_lokey" == key) pCurDef->sw_lokey = parseKey(value); + else if ("sw_hikey" == key) pCurDef->sw_hikey = parseKey(value); + else if ("sw_last" == key) pCurDef->sw_last = parseKey(value); + else if ("sw_down" == key) pCurDef->sw_down = parseKey(value); + else if ("sw_up" == key) pCurDef->sw_up = parseKey(value); + else if ("sw_previous" == key) pCurDef->sw_previous = parseKey(value); else if ("sw_vel" == key) { if (value == "current") pCurDef->sw_vel = VEL_CURRENT; @@ -927,15 +1038,15 @@ else if (value == "legato") pCurDef->trigger = TRIGGER_LEGATO; } else if ("group" == key) pCurDef->group = ToInt(value); - else if ("off_by" == key) pCurDef->off_by = ToInt(value); - else if ("off_mode" == key) + else if ("off_by" == key || "offby" == key) pCurDef->off_by = ToInt(value); + else if ("off_mode" == key || "offmode" == key) { if (value == "fast") _current_group->off_mode = OFF_FAST; else if (value == "normal") _current_group->off_mode = OFF_NORMAL; } // sample player - else if ("count" == key) pCurDef->count = ToInt(value); + else if ("count" == key) { pCurDef->count = ToInt(value); pCurDef->loop_mode = ONE_SHOT; } else if ("delay" == key) pCurDef->delay = ToFloat(value); else if ("delay_random" == key) pCurDef->delay_random = ToFloat(value); else if ("delay_beats" == key) pCurDef->delay_beats = ToInt(value); @@ -944,15 +1055,17 @@ else if ("end" == key) pCurDef->end = ToInt(value); else if ("loop_crossfade" == key) pCurDef->loop_crossfade = ToFloat(value); else if ("offset_random" == key) pCurDef->offset_random = ToInt(value); - else if ("loop_mode" == key) + else if ("loop_mode" == key || "loopmode" == key) { if (value == "no_loop") pCurDef->loop_mode = NO_LOOP; else if (value == "one_shot") pCurDef->loop_mode = ONE_SHOT; - else if (value == "loop_continous") pCurDef->loop_mode = LOOP_CONTINOUS; + else if (value == "loop_continuous") pCurDef->loop_mode = LOOP_CONTINUOUS; else if (value == "loop_sustain") pCurDef->loop_mode = LOOP_SUSTAIN; } else if ("loop_start" == key) pCurDef->loop_start = ToInt(value); + else if ("loopstart" == key) pCurDef->loop_start = ToInt(value); // nonstandard else if ("loop_end" == key) pCurDef->loop_end = ToInt(value); + else if ("loopend" == key) pCurDef->loop_end = ToInt(value); // nonstandard else if ("sync_beats" == key) pCurDef->sync_beats = ToInt(value); else if ("sync_offset" == key) pCurDef->sync_offset = ToInt(value); @@ -962,14 +1075,14 @@ else if ("width" == key) pCurDef->width = ToFloat(value); else if ("position" == key) pCurDef->position = ToFloat(value); else if ("amp_keytrack" == key) pCurDef->amp_keytrack = ToFloat(value); - else if ("amp_keycenter" == key) pCurDef->amp_keycenter = ToInt(value) + note_offset + 12 * octave_offset; + else if ("amp_keycenter" == key) pCurDef->amp_keycenter = parseKey(value); else if ("amp_veltrack" == key) pCurDef->amp_veltrack = ToFloat(value); else if ("amp_random" == key) pCurDef->amp_random = ToFloat(value); else if ("rt_decay" == key) pCurDef->rt_decay = ToFloat(value); - else if ("xfin_lokey" == key) pCurDef->xfin_lokey = ToInt(value) + note_offset + 12 * octave_offset; - else if ("xfin_hikey" == key) pCurDef->xfin_hikey = ToInt(value) + note_offset + 12 * octave_offset; - else if ("xfout_lokey" == key) pCurDef->xfout_lokey = ToInt(value) + note_offset + 12 * octave_offset; - else if ("xfout_hikey" == key) pCurDef->xfout_hikey = ToInt(value) + note_offset + 12 * octave_offset; + else if ("xfin_lokey" == key) pCurDef->xfin_lokey = parseKey(value); + else if ("xfin_hikey" == key) pCurDef->xfin_hikey = parseKey(value); + else if ("xfout_lokey" == key) pCurDef->xfout_lokey = parseKey(value); + else if ("xfout_hikey" == key) pCurDef->xfout_hikey = parseKey(value); else if ("xf_keycurve" == key) { if (value == "gain") pCurDef->xf_keycurve = GAIN; @@ -993,16 +1106,16 @@ // pitch else if ("transpose" == key) pCurDef->transpose = ToInt(value); else if ("tune" == key) pCurDef->tune = ToInt(value); - else if ("pitch_keycenter" == key) pCurDef->pitch_keycenter = ToInt(value) + note_offset + 12 * octave_offset; + else if ("pitch_keycenter" == key) pCurDef->pitch_keycenter = parseKey(value); else if ("pitch_keytrack" == key) pCurDef->pitch_keytrack = ToInt(value); else if ("pitch_veltrack" == key) pCurDef->pitch_veltrack = ToInt(value); else if ("pitch_random" == key) pCurDef->pitch_random = ToInt(value); - else if ("bend_up" == key) pCurDef->bend_up = ToInt(value); - else if ("bend_down" == key) pCurDef->bend_down = ToInt(value); + else if ("bend_up" == key || "bendup" == key) pCurDef->bend_up = ToInt(value); + else if ("bend_down" == key || "benddown" == key) pCurDef->bend_down = ToInt(value); else if ("bend_step" == key) pCurDef->bend_step = ToInt(value); // filter - else if ("fil_type" == key) + else if ("fil_type" == key || "filtype" == key) { if (value == "lpf_1p") pCurDef->fil_type = LPF_1P; else if (value == "hpf_1p") pCurDef->fil_type = HPF_1P; @@ -1046,8 +1159,8 @@ else if ("resonance2" == key) pCurDef->resonance2 = ToFloat(value); else if ("fil_keytrack" == key) pCurDef->fil_keytrack = ToInt(value); else if ("fil2_keytrack" == key) pCurDef->fil2_keytrack = ToInt(value); - else if ("fil_keycenter" == key) pCurDef->fil_keycenter = ToInt(value) + note_offset + 12 * octave_offset; - else if ("fil2_keycenter" == key) pCurDef->fil2_keycenter = ToInt(value) + note_offset + 12 * octave_offset; + else if ("fil_keycenter" == key) pCurDef->fil_keycenter = parseKey(value); + else if ("fil2_keycenter" == key) pCurDef->fil2_keycenter = parseKey(value); else if ("fil_veltrack" == key) pCurDef->fil_veltrack = ToInt(value); else if ("fil2_veltrack" == key) pCurDef->fil2_veltrack = ToInt(value); else if ("fil_random" == key) pCurDef->fil_random = ToInt(value); @@ -1070,7 +1183,9 @@ else if ("eq2_vel2gain" == key) pCurDef->eq2_vel2gain = ToFloat(value); else if ("eq3_vel2gain" == key) pCurDef->eq3_vel2gain = ToFloat(value); - //fixme: parse amp_velcurve_N + else if (sscanf(key.c_str(), "amp_velcurve_%d", &x)) { + pCurDef->amp_velcurve.set(x, ToFloat(value)); + } // CCs else if (key.find("cc") != std::string::npos) @@ -1080,59 +1195,170 @@ int num_cc = ToInt(key.substr(delimiter_index + 2)); // input controls - if ("lo" == key_cc) pCurDef->locc[num_cc] = ToInt(value); - else if ("hi" == key_cc) pCurDef->hicc[num_cc] = ToInt(value); - else if ("start_lo" == key_cc) pCurDef->start_locc[num_cc] = ToInt(value); - else if ("start_hi" == key_cc) pCurDef->start_hicc[num_cc] = ToInt(value); - else if ("stop_lo" == key_cc) pCurDef->stop_locc[num_cc] = ToInt(value); - else if ("stop_hi" == key_cc) pCurDef->stop_hicc[num_cc] = ToInt(value); - else if ("on_lo" == key_cc) pCurDef->on_locc[num_cc] = ToInt(value); - else if ("on_hi" == key_cc) pCurDef->on_hicc[num_cc] = ToInt(value); + if ("lo" == key_cc) pCurDef->locc.set(num_cc, ToInt(value)); + else if ("hi" == key_cc) pCurDef->hicc.set(num_cc, ToInt(value)); + else if ("start_lo" == key_cc) pCurDef->start_locc.set(num_cc, ToInt(value)); + else if ("start_hi" == key_cc) pCurDef->start_hicc.set(num_cc, ToInt(value)); + else if ("stop_lo" == key_cc) pCurDef->stop_locc.set(num_cc, ToInt(value)); + else if ("stop_hi" == key_cc) pCurDef->stop_hicc.set(num_cc, ToInt(value)); + else if ("on_lo" == key_cc) pCurDef->on_locc.set(num_cc, ToInt(value)); + else if ("on_hi" == key_cc) pCurDef->on_hicc.set(num_cc, ToInt(value)); // sample player - else if ("delay_on" == key_cc) pCurDef->delay_oncc[num_cc] = ToFloat(value); - else if ("delay_samples_on" == key_cc) pCurDef->delay_samples_oncc[num_cc] = ToInt(value); - else if ("offset_on" == key_cc) pCurDef->offset_oncc[num_cc] = ToInt(value); + else if ("delay_on" == key_cc) pCurDef->delay_oncc.set(num_cc, ToFloat(value)); + else if ("delay_samples_on" == key_cc) pCurDef->delay_samples_oncc.set(num_cc, ToInt(value)); + else if ("offset_on" == key_cc) pCurDef->offset_oncc.set(num_cc, ToInt(value)); // amplifier - else if ("gain_on" == key_cc) pCurDef->gain_oncc[num_cc] = ToFloat(value); - else if ("xfin_lo" == key_cc) pCurDef->xfin_locc[num_cc] = ToInt(value); - else if ("xfin_hi" == key_cc) pCurDef->xfin_hicc[num_cc] = ToInt(value); - else if ("xfout_lo" == key_cc) pCurDef->xfout_locc[num_cc] = ToInt(value); - else if ("xfout_hi" == key_cc) pCurDef->xfout_hicc[num_cc] = ToInt(value); + else if ("gain_on" == key_cc || "gain_" == key_cc) pCurDef->gain_oncc.set(num_cc, ToFloat(value)); + else if ("xfin_lo" == key_cc) pCurDef->xfin_locc.set(num_cc, ToInt(value)); + else if ("xfin_hi" == key_cc) pCurDef->xfin_hicc.set(num_cc, ToInt(value)); + else if ("xfout_lo" == key_cc) pCurDef->xfout_locc.set(num_cc, ToInt(value)); + else if ("xfout_hi" == key_cc) pCurDef->xfout_hicc.set(num_cc, ToInt(value)); // filter - else if ("cutoff_on" == key_cc) pCurDef->cutoff_oncc[num_cc] = ToInt(value); - else if ("cutoff2_on" == key_cc) pCurDef->cutoff2_oncc[num_cc] = ToInt(value); - else if ("cutoff_smooth" == key_cc) pCurDef->cutoff_smoothcc[num_cc] = ToInt(value); - else if ("cutoff2_smooth" == key_cc) pCurDef->cutoff2_smoothcc[num_cc] = ToInt(value); - else if ("cutoff_step" == key_cc) pCurDef->cutoff_stepcc[num_cc] = ToInt(value); - else if ("cutoff2_step" == key_cc) pCurDef->cutoff2_stepcc[num_cc] = ToInt(value); - else if ("cutoff_curve" == key_cc) pCurDef->cutoff_curvecc[num_cc] = ToInt(value); - else if ("cutoff2_curve" == key_cc) pCurDef->cutoff2_curvecc[num_cc] = ToInt(value); - else if ("resonance_on" == key_cc) pCurDef->resonance_oncc[num_cc] = ToInt(value); - else if ("resonance2_on" == key_cc) pCurDef->resonance2_oncc[num_cc] = ToInt(value); - else if ("resonance_smooth" == key_cc) pCurDef->resonance_smoothcc[num_cc] = ToInt(value); - else if ("resonance2_smooth" == key_cc) pCurDef->resonance2_smoothcc[num_cc] = ToInt(value); - else if ("resonance_step" == key_cc) pCurDef->resonance_stepcc[num_cc] = ToInt(value); - else if ("resonance2_step" == key_cc) pCurDef->resonance2_stepcc[num_cc] = ToInt(value); - else if ("resonance_curve" == key_cc) pCurDef->resonance_curvecc[num_cc] = ToInt(value); - else if ("resonance2_curve" == key_cc) pCurDef->resonance2_curvecc[num_cc] = ToInt(value); + else if ("cutoff_on" == key_cc || "cutoff_" == key_cc) pCurDef->cutoff_oncc.set(num_cc, ToInt(value)); + else if ("cutoff2_on" == key_cc) pCurDef->cutoff2_oncc.set(num_cc, ToInt(value)); + else if ("cutoff_smooth" == key_cc) pCurDef->cutoff_smoothcc.set(num_cc, ToInt(value)); + else if ("cutoff2_smooth" == key_cc) pCurDef->cutoff2_smoothcc.set(num_cc, ToInt(value)); + else if ("cutoff_step" == key_cc) pCurDef->cutoff_stepcc.set(num_cc, ToInt(value)); + else if ("cutoff2_step" == key_cc) pCurDef->cutoff2_stepcc.set(num_cc, ToInt(value)); + else if ("cutoff_curve" == key_cc) pCurDef->cutoff_curvecc.set(num_cc, ToInt(value)); + else if ("cutoff2_curve" == key_cc) pCurDef->cutoff2_curvecc.set(num_cc, ToInt(value)); + else if ("resonance_on" == key_cc) pCurDef->resonance_oncc.set(num_cc, ToInt(value)); + else if ("resonance2_on" == key_cc) pCurDef->resonance2_oncc.set(num_cc, ToInt(value)); + else if ("resonance_smooth" == key_cc) pCurDef->resonance_smoothcc.set(num_cc, ToInt(value)); + else if ("resonance2_smooth" == key_cc) pCurDef->resonance2_smoothcc.set(num_cc, ToInt(value)); + else if ("resonance_step" == key_cc) pCurDef->resonance_stepcc.set(num_cc, ToInt(value)); + else if ("resonance2_step" == key_cc) pCurDef->resonance2_stepcc.set(num_cc, ToInt(value)); + else if ("resonance_curve" == key_cc) pCurDef->resonance_curvecc.set(num_cc, ToInt(value)); + else if ("resonance2_curve" == key_cc) pCurDef->resonance2_curvecc.set(num_cc, ToInt(value)); // per voice equalizer - else if ("eq1_freq_on" == key_cc) pCurDef->eq1_freq_oncc[num_cc] = ToInt(value); - else if ("eq2_freq_on" == key_cc) pCurDef->eq2_freq_oncc[num_cc] = ToInt(value); - else if ("eq3_freq_on" == key_cc) pCurDef->eq3_freq_oncc[num_cc] = ToInt(value); - else if ("eq1_bw_on" == key_cc) pCurDef->eq1_bw_oncc[num_cc] = ToInt(value); - else if ("eq2_bw_on" == key_cc) pCurDef->eq2_bw_oncc[num_cc] = ToInt(value); - else if ("eq3_bw_on" == key_cc) pCurDef->eq3_bw_oncc[num_cc] = ToInt(value); - else if ("eq1_gain_on" == key_cc) pCurDef->eq1_gain_oncc[num_cc] = ToInt(value); - else if ("eq2_gain_on" == key_cc) pCurDef->eq2_gain_oncc[num_cc] = ToInt(value); - else if ("eq3_gain_on" == key_cc) pCurDef->eq3_gain_oncc[num_cc] = ToInt(value); + else if ("eq1_freq_on" == key_cc || "eq1_freq" == key_cc) pCurDef->eq1_freq_oncc.set(num_cc, ToInt(value)); + else if ("eq2_freq_on" == key_cc || "eq2_freq" == key_cc) pCurDef->eq2_freq_oncc.set(num_cc, ToInt(value)); + else if ("eq3_freq_on" == key_cc || "eq3_freq" == key_cc) pCurDef->eq3_freq_oncc.set(num_cc, ToInt(value)); + else if ("eq1_bw_on" == key_cc || "eq1_bw" == key_cc) pCurDef->eq1_bw_oncc.set(num_cc, ToInt(value)); + else if ("eq2_bw_on" == key_cc || "eq2_bw" == key_cc) pCurDef->eq2_bw_oncc.set(num_cc, ToInt(value)); + else if ("eq3_bw_on" == key_cc || "eq3_bw" == key_cc) pCurDef->eq3_bw_oncc.set(num_cc, ToInt(value)); + else if ("eq1_gain_on" == key_cc || "eq1_gain" == key_cc) pCurDef->eq1_gain_oncc.set(num_cc, ToInt(value)); + else if ("eq2_gain_on" == key_cc || "eq2_gain" == key_cc) pCurDef->eq2_gain_oncc.set(num_cc, ToInt(value)); + else if ("eq3_gain_on" == key_cc || "eq3_gain" == key_cc) pCurDef->eq3_gain_oncc.set(num_cc, ToInt(value)); else std::cerr << "The opcode '" << key << "' is unsupported by libsfz!" << std::endl; - } else { + } + // v2 envelope generators + else if (sscanf(key.c_str(), "eg%d%n", &x, &y)) { + const char* s = key.c_str() + y; + if (sscanf(s, "_time%d", &y)) egnode(x, y).time = ToFloat(value); + else if (sscanf(s, "_level%d", &y)) egnode(x, y).level = ToFloat(value); + else if (sscanf(s, "_shape%d", &y)) egnode(x, y).shape = ToFloat(value); + else if (sscanf(s, "_curve%d", &y)) egnode(x, y).curve = ToFloat(value); + else if (strcmp(s, "_sustain") == 0) eg(x).sustain = ToInt(value); + else if (strcmp(s, "_loop") == 0) eg(x).loop = ToInt(value); + else if (strcmp(s, "_loop_count") == 0) eg(x).loop_count = ToInt(value); + else if (strcmp(s, "_amplitude") == 0) eg(x).amplitude = ToFloat(value); + else if (strcmp(s, "_cutoff") == 0) eg(x).cutoff = ToFloat(value); + else std::cerr << "The opcode '" << key << "' is unsupported by libsfz!" << std::endl; + } + + // v1 envelope generators + else if ("ampeg_delay" == key) pCurDef->ampeg_delay = ToFloat(value); + else if ("ampeg_start" == key) pCurDef->ampeg_start = ToFloat(value); + else if ("ampeg_attack" == key) pCurDef->ampeg_attack = ToFloat(value); + else if ("ampeg_hold" == key) pCurDef->ampeg_hold = ToFloat(value); + else if ("ampeg_decay" == key) pCurDef->ampeg_decay = ToFloat(value); + else if ("ampeg_sustain" == key) pCurDef->ampeg_sustain = ToFloat(value); + else if ("ampeg_release" == key) pCurDef->ampeg_release = ToFloat(value); + else if ("fileg_delay" == key) pCurDef->fileg_delay = ToFloat(value); + else if ("fileg_start" == key) pCurDef->fileg_start = ToFloat(value); + else if ("fileg_attack" == key) pCurDef->fileg_attack = ToFloat(value); + else if ("fileg_hold" == key) pCurDef->fileg_hold = ToFloat(value); + else if ("fileg_decay" == key) pCurDef->fileg_decay = ToFloat(value); + else if ("fileg_sustain" == key) pCurDef->fileg_sustain = ToFloat(value); + else if ("fileg_release" == key) pCurDef->fileg_release = ToFloat(value); + else if ("pitcheg_delay" == key) pCurDef->pitcheg_delay = ToFloat(value); + else if ("pitcheg_start" == key) pCurDef->pitcheg_start = ToFloat(value); + else if ("pitcheg_attack" == key) pCurDef->pitcheg_attack = ToFloat(value); + else if ("pitcheg_hold" == key) pCurDef->pitcheg_hold = ToFloat(value); + else if ("pitcheg_decay" == key) pCurDef->pitcheg_decay = ToFloat(value); + else if ("pitcheg_sustain" == key) pCurDef->pitcheg_sustain = ToFloat(value); + else if ("pitcheg_release" == key) pCurDef->pitcheg_release = ToFloat(value); + + // v1 LFO + else if ("amplfo_delay" == key) pCurDef->amplfo_delay = ToFloat(value); + else if ("amplfo_fade" == key) pCurDef->amplfo_fade = ToFloat(value); + else if ("amplfo_freq" == key) pCurDef->amplfo_freq = ToFloat(value); + else if ("amplfo_depth" == key) pCurDef->amplfo_depth = ToFloat(value); + else if ("fillfo_delay" == key) pCurDef->fillfo_delay = ToFloat(value); + else if ("fillfo_fade" == key) pCurDef->fillfo_fade = ToFloat(value); + else if ("fillfo_freq" == key) pCurDef->fillfo_freq = ToFloat(value); + else if ("fillfo_depth" == key) pCurDef->fillfo_depth = ToFloat(value); + else if ("pitchlfo_delay" == key) pCurDef->pitchlfo_delay = ToFloat(value); + else if ("pitchlfo_fade" == key) pCurDef->pitchlfo_fade = ToFloat(value); + else if ("pitchlfo_freq" == key) pCurDef->pitchlfo_freq = ToFloat(value); + else if ("pitchlfo_depth" == key) pCurDef->pitchlfo_depth = ToInt(value); + + else { std::cerr << "The opcode '" << key << "' is unsupported by libsfz!" << std::endl; } } + int File::parseKey(const std::string& s) { + int i; + std::istringstream iss(s); + if (isdigit(iss.peek())) { + iss >> i; + } else { + switch (tolower(iss.get())) { + case 'c': i = 0; break; + case 'd': i = 2; break; + case 'e': i = 4; break; + case 'f': i = 5; break; + case 'g': i = 7; break; + case 'a': i = 9; break; + case 'b': i = 11; break; + default: + std::cerr << "Not a note: " << s << std::endl; + return 0; + } + if (iss.peek() == '#') { + i++; + iss.get(); + } else if (tolower(iss.peek()) == 'b') { + i--; + iss.get(); + } + int octave; + if (!(iss >> octave)) { + std::cerr << "Not a note: " << s << std::endl; + return 0; + } + i += (octave + 1) * 12; + } + return i + note_offset + 12 * octave_offset; + } + + EGNode::EGNode() : time(0), level(0), shape(0), curve(0) { + } + + EG::EG() : + sustain(0), loop(0), loop_count(0), + amplitude(0), cutoff(0) { + } + + EG& File::eg(int x) { + while (pCurDef->eg.size() <= x) { + pCurDef->eg.add(EG()); + } + return pCurDef->eg[x]; + } + + EGNode& File::egnode(int x, int y) { + EG& e = eg(x); + while (e.node.size() <= y) { + e.node.add(EGNode()); + } + return e.node[y]; + } + } // !namespace sfz