diff options
author | Damien Zammit <damien@zamaudio.com> | 2016-07-20 01:22:34 +1000 |
---|---|---|
committer | Damien Zammit <damien@zamaudio.com> | 2016-07-20 01:22:34 +1000 |
commit | 404058e2bdcf41165d00e61fa3f78a273920b81b (patch) | |
tree | 228f9b63e8f02fcf1f86c00f67f92be24af6a906 /plugins | |
parent | 27f9c885aa4243e6e02df0ab82046aee87c46cf3 (diff) |
Improved SFZ parser
Signed-off-by: Damien Zammit <damien@zamaudio.com>
Diffstat (limited to 'plugins')
-rw-r--r-- | plugins/ZamSFZ/Sfz.cpp | 17 | ||||
-rw-r--r-- | plugins/ZamSFZ/Sfz.hpp | 3 | ||||
-rw-r--r-- | plugins/ZamSFZ/ZamSFZPlugin.cpp | 11 | ||||
-rw-r--r-- | plugins/ZamSFZ/ZamSFZPlugin.hpp | 3 | ||||
-rw-r--r-- | plugins/ZamSFZ/ZamSFZUI.cpp | 2 | ||||
-rw-r--r-- | plugins/ZamSFZ/ZamSFZUI.hpp | 5 | ||||
-rw-r--r-- | plugins/ZamSFZ/libsfz/LICENSE | 19 | ||||
-rw-r--r-- | plugins/ZamSFZ/libsfz/sfz.cpp | 3031 | ||||
-rw-r--r-- | plugins/ZamSFZ/libsfz/sfz.h | 356 |
9 files changed, 525 insertions, 2922 deletions
diff --git a/plugins/ZamSFZ/Sfz.cpp b/plugins/ZamSFZ/Sfz.cpp index 800f437..c58bea9 100644 --- a/plugins/ZamSFZ/Sfz.cpp +++ b/plugins/ZamSFZ/Sfz.cpp @@ -50,10 +50,13 @@ void Sfz::clearsamples() void Sfz::loadsamples(std::string path, std::string filename) { int note, i, j, k, key; - ::sfz::File* sfzfile = NULL; - ::sfz::Instrument* sfzinstrument = NULL; - sfzfile = new ::sfz::File(filename, path); - sfzinstrument = sfzfile->GetInstrument(); + ::sfz::SFZParser sfzfile; + std::string fullsfzpath = path + std::string("/") + filename; + if (sfzfile.readsfz(fullsfzpath) == -1) { + printf("Can't open SFZ\n"); + return; + } + ::sfz::Instrument* sfzinstrument = &sfzfile.instrument; SNDFILE *infile = NULL; SF_INFO sfinfo; @@ -73,10 +76,11 @@ void Sfz::loadsamples(std::string path, std::string filename) layers[note].keymiddle = key; layers[note].dsemitones = 0; infile = NULL; - if ((infile = sf_open(sfzinstrument->regions[i]->sample.c_str(), SFM_READ, &sfinfo)) == NULL) { + std::string fullsamplepath = path + std::string("/") + sfzinstrument->regions[i]->sample; + if ((infile = sf_open(fullsamplepath.c_str(), SFM_READ, &sfinfo)) == NULL) { printf("Missing samples\n"); puts (sf_strerror (NULL)); - printf("File: %s\n",sfzinstrument->regions[i]->sample.c_str()); + printf("File: %s\n",fullsamplepath.c_str()); } readsamples (infile, sfinfo.channels, note, layers[note].max); k = layers[note].max; @@ -97,7 +101,6 @@ void Sfz::loadsamples(std::string path, std::string filename) } printf("All samples loaded, Woot!\n"); } - delete sfzfile; for (i = 0; i < 128; i++) { if (!(layers[i].keymiddle == i)) { k = layers[i].keymiddle; diff --git a/plugins/ZamSFZ/Sfz.hpp b/plugins/ZamSFZ/Sfz.hpp index 5698283..18e2b9b 100644 --- a/plugins/ZamSFZ/Sfz.hpp +++ b/plugins/ZamSFZ/Sfz.hpp @@ -5,7 +5,8 @@ #include "libsfz/sfz.h" #include <rubberband/RubberBandStretcher.h> #include <sndfile.h> -#define MAX_LAYERS 8 +#include <math.h> +#define MAX_LAYERS 25 #define MAX_SAMPLES 64000 class Sfz { diff --git a/plugins/ZamSFZ/ZamSFZPlugin.cpp b/plugins/ZamSFZ/ZamSFZPlugin.cpp index c7bd616..8208bad 100644 --- a/plugins/ZamSFZ/ZamSFZPlugin.cpp +++ b/plugins/ZamSFZ/ZamSFZPlugin.cpp @@ -91,17 +91,22 @@ void ZamSFZPlugin::setState(const char* key, const char* value) path.assign(value, 0, strlen(value) - strlen(tmp)); loading = true; printf("Path: %s\nFile: %s\n", path.c_str(), filename.c_str()); - sfz.clearsamples(); + sfz.clearsamples(); sfz.loadsamples(path, filename); sfz.pitchshiftsamples((int)getSampleRate()); loading = false; } } -void ZamSFZPlugin::initState(unsigned int key, String& val, d_string&) +String ZamSFZPlugin::getState(const char*) const +{ + return String("filepath"); +} + +void ZamSFZPlugin::initState(unsigned int key, String& val, String&) { if (key == 0) - val = "filepath"; + val = "filepath"; } void ZamSFZPlugin::loadProgram(uint32_t index) diff --git a/plugins/ZamSFZ/ZamSFZPlugin.hpp b/plugins/ZamSFZ/ZamSFZPlugin.hpp index 170b76a..3602776 100644 --- a/plugins/ZamSFZ/ZamSFZPlugin.hpp +++ b/plugins/ZamSFZ/ZamSFZPlugin.hpp @@ -120,7 +120,8 @@ protected: void run(const float** inputs, float** outputs, uint32_t frames, const MidiEvent* midievent, uint32_t midicount) override; void setState(const char* key, const char* value) override; - void initState(unsigned int, String&, d_string&) override; + String getState(const char* key) const override; + void initState(unsigned int, String&, String&) override; // ------------------------------------------------------------------- private: diff --git a/plugins/ZamSFZ/ZamSFZUI.cpp b/plugins/ZamSFZ/ZamSFZUI.cpp index 6c4b5f4..a4b282b 100644 --- a/plugins/ZamSFZ/ZamSFZUI.cpp +++ b/plugins/ZamSFZ/ZamSFZUI.cpp @@ -84,7 +84,7 @@ void ZamSFZUI::stateChanged(const char* key, const char*) } } -void ZamSFZUI::d_uiFileBrowserSelected(const char* filename) +void ZamSFZUI::uiFileBrowserSelected(const char* filename) { // if a file was selected, tell DSP if (filename != nullptr) diff --git a/plugins/ZamSFZ/ZamSFZUI.hpp b/plugins/ZamSFZ/ZamSFZUI.hpp index b90daaf..bae978e 100644 --- a/plugins/ZamSFZ/ZamSFZUI.hpp +++ b/plugins/ZamSFZ/ZamSFZUI.hpp @@ -19,8 +19,7 @@ #define ZAMSFZUI_HPP_INCLUDED #include "DistrhoUI.hpp" -#include "ImageKnob.hpp" -#include "ImageButton.hpp" +#include "ImageWidgets.hpp" #include "ZamSFZArtwork.hpp" using DGL::Image; @@ -46,7 +45,7 @@ protected: void programLoaded(uint32_t index) override; void stateChanged(const char* key, const char* value) override; - void d_uiFileBrowserSelected(const char* filename) override; + void uiFileBrowserSelected(const char* filename) override; // ------------------------------------------------------------------- // Widget Callbacks diff --git a/plugins/ZamSFZ/libsfz/LICENSE b/plugins/ZamSFZ/libsfz/LICENSE deleted file mode 100644 index 5c53037..0000000 --- a/plugins/ZamSFZ/libsfz/LICENSE +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (c) 2009 Anders Dahnielson - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/plugins/ZamSFZ/libsfz/sfz.cpp b/plugins/ZamSFZ/libsfz/sfz.cpp index 23ecf28..5df0c78 100644 --- a/plugins/ZamSFZ/libsfz/sfz.cpp +++ b/plugins/ZamSFZ/libsfz/sfz.cpp @@ -1,2648 +1,437 @@ -/* -*- Mode: C++ ; c-basic-offset: 8 -*- */ - -// SFZ 1.0 -// Copyright (c) 2008-2009, Anders Dahnielson -// -// Contact: anders@dahnielson.com -// -// 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 -// the Free Software Foundation; either version 2 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - #include "sfz.h" +namespace sfz { -#include <iostream> -#include <sstream> - -#include <boost/lexical_cast.hpp> - -namespace sfz +SFZParser::SFZParser() { +} - ///////////////////////////////////////////////////////////// - // class Articulation - - Articulation::Articulation() - { - } - - Articulation::~Articulation() - { - } - - ///////////////////////////////////////////////////////////// - // class Definition - - Definition::Definition() - { - } - - Definition::~Definition() - { - } - - ///////////////////////////////////////////////////////////// - // class Region - - Region::Region() - { - } - - Region::~Region() - { - } - - 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_last >= sw_lokey && sw_last <= sw_hikey) ? (last_sw_key == sw_last) : true) && - ((sw_down >= sw_lokey && sw_down <= sw_hikey) ? (sw[sw_down]) : true) && - ((sw_up >= sw_lokey && sw_up <= sw_hikey) ? (!sw[sw_up]) : true) && - ((sw_previous != -1) ? (prev_sw_key == sw_previous) : true) && - ((trigger && trig) != 0) - ); - - if (!is_triggered) - return false; - - for (int i = 0; i < 128; ++i) - { - if (!(cc[i] >= locc[i] && cc[i] <= hicc[i])) - return false; - } - - return true; - } - - 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) - { - // chan (MIDI channel) - // cont (MIDI controller) - // val (MIDI controller value) - - // 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 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 && - ((val >= on_locc[cont] && val <= on_hicc[cont]) || - (val >= start_locc[cont] && val <= start_hicc[cont])) && - 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_last >= sw_lokey && sw_last <= sw_hikey) ? (last_sw_key == sw_last) : true) && - ((sw_down >= sw_lokey && sw_down <= sw_hikey) ? (sw[sw_down]) : true) && - ((sw_up >= sw_lokey && sw_up <= sw_hikey) ? (!sw[sw_up]) : true) && - ((sw_previous != -1) ? (prev_sw_key == sw_previous) : true) && - ((trigger && trig) != 0) - ); - - if (!is_triggered) - return false; - - for (int i = 0; i < 128; ++i) - { - if (!(cc[i] >= locc[i] && cc[i] <= hicc[i])) - return false; - } +SFZParser::~SFZParser() +{ +} - return true; - } +int SFZParser::readsfz(std::string path) +{ + FILE* fp; + uint32_t len; - Articulation* - Region::GetArticulation(int bend, uint8_t bpm, uint8_t chanaft, uint8_t polyaft, uint8_t* cc) - { - return new Articulation(); //todo: implement GetArticulation() + if (! (fp = fopen(path.c_str(), "rb"))) { + return -1; } - ///////////////////////////////////////////////////////////// - // class Instrument + fseek(fp, 0, SEEK_END); + len = ftell(fp); + fseek(fp, 0, SEEK_SET); - Instrument::Instrument() - { - } - - Instrument::~Instrument() - { - for (uint32_t i = 0; i < regions.size(); i++) { - delete regions[i]; - } - } + char sfz[len]; - ///////////////////////////////////////////////////////////// - // class Group + fread(sfz, 1, len, fp); + fclose(fp); + + SFZParser::read(sfz, len); + return 0; +} - Group::Group() : - id(0) - { - Reset(); +void SFZParser::read(const char* text, unsigned int length) +{ + const char* p = text; + const char* end = text + length; + char c; + + SFZRegion curGroup(&instrument); + SFZRegion curRegion(&instrument); + SFZRegion *buildingRegion = NULL; + bool inControl = false; + std::string defaultPath; + + while (p < end) { + // We're at the start of a line; skip any whitespace. + while (p < end) { + c = *p; + if (c != ' ' && c != '\t') + break; + p += 1; + } + if (p >= end) + break; + + // Check if it's a comment line. + if (c == '/' && *(p+1) == '/') { + // Skip to end of line. + while (p < end) { + c = *++p; + if (c == '\n' || c == '\r') + break; + } + p = handleLineEnd(p); + continue; + } + + // Check if it's a blank line. + if (c == '\r' || c == '\n') { + p = handleLineEnd(p); + continue; + } + + // Handle elements on the line. + while (p < end) { + c = *p; + + // Tag. + if (c == '<') { + p += 1; + const char* tagStart = p; + while (p < end) { + c = *p++; + if (c == '\n' || c == '\r') { + error(std::string("Unterminated tag")); + goto fatalError; + } + else if (c == '>') + break; + } + if (p >= end) { + error(std::string("Unterminated tag")); + goto fatalError; + } + StringSlice tag(tagStart, p - 1); + if (tag == "region") { + if (buildingRegion && buildingRegion == &curRegion) + finishRegion(&curRegion); + curRegion = curGroup; + buildingRegion = &curRegion; + inControl = false; + } + else if (tag == "group") { + if (buildingRegion && buildingRegion == &curRegion) + finishRegion(&curRegion); + curGroup.clear(); + buildingRegion = &curGroup; + inControl = false; + } + else if (tag == "control") { + if (buildingRegion && buildingRegion == &curRegion) + finishRegion(&curRegion); + curGroup.clear(); + buildingRegion = NULL; + inControl = true; + } + else + error(std::string("Illegal tag")); + } + + // Comment. + else if (c == '/' && *(p+1) == '/') { + // Skip to end of line. + while (p < end) { + c = *p; + if (c == '\r' || c == '\n') + break; + p += 1; + } + } + + // Parameter. + else { + // Get the parameter name. + const char* parameterStart = p; + while (p < end) { + c = *p++; + if (c == '=' || c == ' ' || c == '\t' || c == '\r' || c == '\n') + break; + } + if (p >= end || c != '=') { + error(std::string("Malformed parameter")); + goto nextElement; + } + StringSlice opcode(parameterStart, p - 1); + if (inControl) { + if (opcode == "default_path") + p = readPathInto(&defaultPath, p, end); + else { + const char* valueStart = p; + while (p < end) { + c = *p; + if (c == ' ' || c == '\t' || c == '\n' || c == '\r') + break; + p++; + } + std::string value(valueStart, p - valueStart); + std::string fauxOpcode = + std::string(opcode.start, opcode.length()) + " (in <control>)"; + printf("Unsupported: %s\n", fauxOpcode.c_str()); + } + } + else if (opcode == "sample") { + std::string path; + p = readPathInto(&path, p, end); + if (!path.empty()) { + printf("`%s'\n", path.c_str()); + if (buildingRegion) + buildingRegion->sample = path; + else + error("Adding sample outside a group or region"); + } + else + error(std::string("Empty sample path")); + } + else { + const char* valueStart = p; + while (p < end) { + c = *p; + if (c == ' ' || c == '\t' || c == '\n' || c == '\r') + break; + p++; + } + std::string value(valueStart, p - valueStart); + if (buildingRegion == NULL) + error("Setting a parameter outside a region or group"); + else if (opcode == "lokey") + buildingRegion->lokey = keyValue(value); + else if (opcode == "hikey") + buildingRegion->hikey = keyValue(value); + else if (opcode == "key") { + buildingRegion->hikey = + buildingRegion->lokey = + buildingRegion->pitch_keycenter = + keyValue(value); + } + else if (opcode == "lovel") + buildingRegion->lovel = atoi(value.c_str()); + else if (opcode == "hivel") + buildingRegion->hivel = atoi(value.c_str()); + else if (opcode == "trigger") + buildingRegion->trigger = (SFZRegion::Trigger) triggerValue(value); + else if (opcode == "group") + buildingRegion->group = (unsigned long) atol(value.c_str()); + else if (opcode == "off_by") + buildingRegion->off_by = (unsigned long) atol(value.c_str()); + else if (opcode == "offset") + buildingRegion->offset = (unsigned long) atol(value.c_str()); + else if (opcode == "end") { + int64_t end = (unsigned long) atol(value.c_str()); + if (end < 0) + buildingRegion->negative_end = true; + else + buildingRegion->end = end; + } + else if (opcode == "loop_mode") { + bool modeIsSupported = + value == "no_loop" || + value == "one_shot" || + value == "loop_continuous"; + if (modeIsSupported) + buildingRegion->loop_mode = (SFZRegion::LoopMode) loopModeValue(value); + else { + std::string fauxOpcode = + std::string(opcode.start, opcode.length()) + "=" + value; + printf("Unsupported: %s\n", fauxOpcode.c_str()); + } + } + else if (opcode == "loop_start") + buildingRegion->loop_start = (unsigned long) atol(value.c_str()); + else if (opcode == "loop_end") + buildingRegion->loop_end = (unsigned long) atol(value.c_str()); + else if (opcode == "transpose") + buildingRegion->transpose = atoi(value.c_str()); + else if (opcode == "tune") + buildingRegion->tune = atoi(value.c_str()); + else if (opcode == "pitch_keycenter") + buildingRegion->pitch_keycenter = keyValue(value); + else if (opcode == "pitch_keytrack") + buildingRegion->pitch_keytrack = atoi(value.c_str()); + else if (opcode == "bend_up") + buildingRegion->bend_up = atoi(value.c_str()); + else if (opcode == "bend_down") + buildingRegion->bend_down = atoi(value.c_str()); + else if (opcode == "volume") + buildingRegion->volume = atof(value.c_str()); + else if (opcode == "pan") + buildingRegion->pan = atof(value.c_str()); + else if (opcode == "amp_veltrack") + buildingRegion->amp_veltrack = atof(value.c_str()); + else if (opcode == "default_path") + error(std::string("\"default_path\" outside of <control> tag")); + else + error(std::string("Unsupported")); + } + } + + // Skip to next element. +nextElement: + c = 0; + while (p < end) { + c = *p; + if (c != ' ' && c != '\t') + break; + p += 1; + } + if (c == '\r' || c == '\n') { + p = handleLineEnd(p); + break; + } + } + } + +fatalError: + if (buildingRegion && buildingRegion == &curRegion) + finishRegion(buildingRegion); +} + +const char* SFZParser::handleLineEnd(const char* p) +{ + // Check for DOS-style line ending. + char lineEndChar = *p++; + if (lineEndChar == '\r' && *p == '\n') + p += 1; + line += 1; + return p; +} + +const char* SFZParser::readPathInto(std::string* pathOut, const char* pIn, const char* endIn) +{ + // Paths are kind of funny to parse because they can contain whitespace. + const char* p = pIn; + const char* end = endIn; + const char* pathStart = p; + const char* potentialEnd = NULL; + while (p < end) { + char c = *p; + if (c == ' ') { + // Is this space part of the path? Or the start of the next opcode? We + // don't know yet. + potentialEnd = p; + p += 1; + // Skip any more spaces. + while (p < end && *p == ' ') + p += 1; + } + else if (c == '\n' || c == '\r' || c == '\t') + break; + else if (c == '=') { + // We've been looking at an opcode; we need to rewind to + // potentialEnd. + p = potentialEnd; + break; + } + p += 1; } - - Group::~Group() - { - + if (p > pathStart) { + std::string path(pathStart, p); + *pathOut = path; } + else + *pathOut = std::string(""); + return p; +} - void - Group::Reset() - { - // This is where all the default values are set. - - // sample definition default - sample = ""; - - // input control - lochan = 1; hichan = 16; - lokey = 0; hikey = 127; - lovel = 0; hivel = 127; - lobend = -8192; hibend = 8192; - lobpm = 0; hibpm = 500; - lochanaft = 0; hichanaft = 127; - lopolyaft = 0; hipolyaft = 127; - loprog = 0; hiprog = 127; - lorand = 0.0; hirand = 1.0; - lotimer = 0.0; hitimer = 0.0; - - seq_length = 1; - seq_position = 1; - - sw_lokey = -1; sw_hikey = -1; - sw_last = -1; - sw_down = -1; - sw_up = -1; - sw_previous = -1; - sw_vel = VEL_CURRENT; - - trigger = TRIGGER_ATTACK; - - group = 0; - off_by = 0; - off_mode = OFF_FAST; - - // sample player - count = 0; - delay = 0; delay_random = 0; - delay_beats = 0; stop_beats = 0; - delay_samples = 0; - end = 0; - loop_crossfade = 0; - offset = 0; offset_random = 0; - loop_mode = NO_LOOP; - loop_start = 0; loop_end = 0; - sync_beats = 0; sync_offset = 0; - - // amplifier - volume = 0; - pan = 0; - width = 100; - position = 0; - amp_keytrack = 0; - amp_keycenter = 60; - amp_veltrack = 100; - amp_random = 0; - rt_decay = 0; - xfin_lokey = 0; xfin_hikey = 0; - xfout_lokey = 127; xfout_hikey = 127; - xf_keycurve = POWER; - xfin_lovel = 0; xfin_hivel = 0; - xfout_lovel = 127; xfout_hivel = 127; - xf_velcurve = POWER; - xf_cccurve = POWER; - - // pitch - transpose = 0; - tune = 0; - pitch_keycenter = 60; - pitch_keytrack = 100; - pitch_veltrack = 0; - pitch_random = 0; - bend_up = 200; - bend_down = -200; - bend_step = 1; - - // filter - fil_type = LPF_2P; - cutoff = 0; - cutoff_chanaft = 0; - cutoff_polyaft = 0; - resonance = 0; - fil_keytrack = 0; - fil_keycenter = 60; - fil_veltrack = 0; - fil_random = 0; - - fil2_type = LPF_2P; - cutoff2 = 0; - cutoff2_chanaft = 0; - cutoff2_polyaft = 0; - resonance2 = 0; - fil2_keytrack = 0; - fil2_keycenter = 60; - fil2_veltrack = 0; - fil2_random = 0; - - // per voice equalizer - eq1_freq = 50; - eq2_freq = 500; - eq3_freq = 5000; - eq1_vel2freq = 0; - eq2_vel2freq = 0; - eq3_vel2freq = 0; - eq1_bw = 1; - eq2_bw = 1; - eq3_bw = 1; - eq1_gain = 0; - eq2_gain = 0; - eq3_gain = 0; - eq1_vel2gain = 0; - eq2_vel2gain = 0; - eq3_vel2gain = 0; - - // CCs - 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; - - // sample player - delay_oncc[i] = 0; - delay_samples_oncc[i] = 0; - offset_oncc[i] = 0; - - // 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; - - // 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; - - // 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; +int SFZParser::keyValue(const std::string& str) +{ + char c = str[0]; + if (c >= '0' && c <= '9') + return atoi(str.c_str()); + + int note = 0; + static const int notes[] = { + 12 + 0, 12 + 2, 3, 5, 7, 8, 10, + }; + if (c >= 'A' && c <= 'G') + note = notes[c - 'A']; + else if (c >= 'a' && c <= 'g') + note = notes[c - 'a']; + int octaveStart = 1; + c = str[1]; + if (c == 'b' || c == '#') { + octaveStart += 1; + if (c == 'b') + note -= 1; + else + note += 1; } - } - - Region* - Group::RegionFactory() - { - // This is where the current group setting are copied to the new region. - - Region* region = new Region(); - - region->id = id++; - - // sample definition - region->sample = sample; - - // input control - region->lochan = lochan; - region->hichan = hichan; - region->lokey = lokey; - region->hikey = hikey; - region->lovel = lovel; - region->hivel = hivel; - region->locc = locc; - region->hicc = hicc; - region->lobend = lobend; - region->hibend = hibend; - region->lobpm = lobpm; - region->hibpm = hibpm; - region->lochanaft = lochanaft; - region->hichanaft = hichanaft; - region->lopolyaft = lopolyaft; - region->hipolyaft = hipolyaft; - region->loprog = loprog; - region->hiprog = hiprog; - region->lorand = lorand; - region->hirand = hirand; - region->lotimer = lotimer; - region->hitimer = hitimer; - region->seq_length = seq_length; - region->seq_position = seq_position; - region->start_locc = start_locc; - region->start_hicc = start_hicc; - region->stop_locc = stop_locc; - region->stop_hicc = stop_hicc; - region->sw_lokey = sw_lokey; - region->sw_hikey = sw_hikey; - region->sw_last = sw_last; - region->sw_down = sw_down; - region->sw_up = sw_up; - region->sw_previous = sw_previous; - region->sw_vel = sw_vel; - region->trigger = trigger; - region->group = group; - region->off_by = off_by; - region->off_mode = off_mode; - region->on_locc = on_locc; - region->on_hicc = on_hicc; - - // sample player - region->count = count; - region->delay = delay; - region->delay_random = delay_random; - region->delay_oncc = delay_oncc; - region->delay_beats = delay_beats; - region->stop_beats = stop_beats; - region->delay_samples = delay_samples; - region->delay_samples_oncc = delay_samples_oncc; - region->end = end; - region->loop_crossfade = loop_crossfade; - region->offset = offset; - region->offset_random = offset_random; - region->offset_oncc = offset_oncc; - region->loop_mode = loop_mode; - region->loop_start = loop_start; - region->loop_end = loop_end; - region->sync_beats = sync_beats; - region->sync_offset = sync_offset; - - // amplifier - region->volume = volume; - region->pan = pan; - region->width = width; - region->position = position; - region->amp_keytrack = amp_keytrack; - region->amp_keycenter = amp_keycenter; - region->amp_veltrack = amp_veltrack; - region->amp_velcurve_ = amp_velcurve_; - region->amp_random = amp_random; - region->rt_decay = rt_decay; - region->gain_oncc = gain_oncc; - region->xfin_lokey = xfin_lokey; - region->xfin_hikey = xfin_hikey; - region->xfout_lokey = xfout_lokey; - region->xfout_hikey = xfout_hikey; - region->xf_keycurve = xf_keycurve; - region->xfin_lovel = xfin_lovel; - region->xfin_hivel = xfin_lovel; - region->xfout_lovel = xfout_lovel; - region->xfout_hivel = xfout_hivel; - region->xf_velcurve = xf_velcurve; - region->xfin_locc = xfin_locc; - region->xfin_hicc = xfin_hicc; - region->xfout_locc = xfout_locc; - region->xfout_hicc = xfout_hicc; - region->xf_cccurve = xf_cccurve; - - // pitch - region->transpose = transpose; - region->tune = tune; - region->pitch_keycenter = pitch_keycenter; - region->pitch_keytrack = pitch_keytrack; - region->pitch_veltrack = pitch_veltrack; - region->pitch_random = pitch_random; - region->bend_up = bend_up; - region->bend_down = bend_down; - region->bend_step = bend_step; - - // filter - region->fil_type = fil_type; - region->cutoff = cutoff; - region->cutoff_oncc = cutoff_oncc; - region->cutoff_smoothcc = cutoff_smoothcc; - region->cutoff_stepcc = cutoff_stepcc; - region->cutoff_curvecc = cutoff_curvecc; - region->cutoff_chanaft = cutoff_chanaft; - region->cutoff_polyaft = cutoff_polyaft; - region->resonance = resonance; - region->resonance_oncc = resonance_oncc; - region->resonance_smoothcc = resonance_smoothcc; - region->resonance_stepcc = resonance_stepcc; - region->resonance_curvecc = resonance_curvecc; - region->fil_keytrack = fil_keytrack; - region->fil_keycenter = fil_keycenter; - region->fil_veltrack = fil_veltrack; - region->fil_random = fil_random; - - region->fil2_type = fil2_type; - region->cutoff2 = cutoff2; - region->cutoff2_oncc = cutoff2_oncc; - region->cutoff2_smoothcc = cutoff2_smoothcc; - region->cutoff2_stepcc = cutoff2_stepcc; - region->cutoff2_curvecc = cutoff2_curvecc; - region->cutoff2_chanaft = cutoff2_chanaft; - region->cutoff2_polyaft = cutoff2_polyaft; - region->resonance2 = resonance2; - region->resonance2_oncc = resonance2_oncc; - region->resonance2_smoothcc = resonance2_smoothcc; - region->resonance2_stepcc = resonance2_stepcc; - region->resonance2_curvecc = resonance2_curvecc; - region->fil2_keytrack = fil2_keytrack; - region->fil2_keycenter = fil2_keycenter; - region->fil2_veltrack = fil2_veltrack; - region->fil2_random = fil2_random; - - // per voice equalizer - region->eq1_freq = eq1_freq; - region->eq2_freq = eq2_freq; - region->eq3_freq = eq3_freq; - region->eq1_freq_oncc = eq1_freq_oncc; - region->eq2_freq_oncc = eq2_freq_oncc; - region->eq3_freq_oncc = eq3_freq_oncc; - region->eq1_vel2freq = eq1_vel2freq; - region->eq2_vel2freq = eq2_vel2freq; - region->eq3_vel2freq = eq3_vel2freq; - region->eq1_bw = eq1_bw; - region->eq2_bw = eq2_bw; - region->eq3_bw = eq3_bw; - region->eq1_bw_oncc = eq1_bw_oncc; - region->eq2_bw_oncc = eq2_bw_oncc; - region->eq3_bw_oncc = eq3_bw_oncc; - region->eq1_gain = eq1_gain; - region->eq2_gain = eq2_gain; - region->eq3_gain = eq3_gain; - region->eq1_gain_oncc = eq1_gain_oncc; - region->eq2_gain_oncc = eq2_gain_oncc; - region->eq3_gain_oncc = eq3_gain_oncc; - region->eq1_vel2gain = eq1_vel2gain; - region->eq2_vel2gain = eq2_vel2gain; - region->eq3_vel2gain = eq3_vel2gain; - - return region; - } - - ///////////////////////////////////////////////////////////// - // class File - - File::File(std::string file, std::string path) : - _instrument(new Instrument()), - _current_section(GROUP), - _current_group(new Group()), - default_path(path.c_str()), - octave_offset(0), - note_offset(0) - { - - enum token_type_t { HEADER, OPCODE }; - token_type_t token_type; - std::string token_string; - - default_path = default_path + "/"; - std::string fullpath = default_path + file; - std::ifstream fs(fullpath.c_str()); - std::string token; - std::string line; - token_type = HEADER; - - int currentLine = 0; - - while (std::getline(fs, line)) - { - currentLine++; - printf("line %d: %s\n", currentLine, line.c_str()); - // COMMENT - std::string::size_type slash_index = line.find("//"); - if (slash_index != std::string::npos) - line.resize(slash_index); - - // #include - if (line.find("#include ") == 0) { - size_t fname_start = line.find("\""); - if (fname_start == std::string::npos) continue; - - size_t fname_end = line.find("\"", fname_start + 1); - if (fname_end == std::string::npos || fname_start == fname_end) - continue; - std::string fname = line.substr(fname_start + 1, fname_end - fname_start - 1); + int octave = atoi(str.substr(octaveStart).c_str()); + // A3 == 57. + int result = octave * 12 + note + (57 - 4 * 12); + return result; +} - std::string cd = default_path; - int cl = currentLine; - File(file, cd); - default_path = cd; - currentLine = cl; - continue; - } - - // DEFINITION - std::stringstream linestream(line); - int spaces = 0; - while (linestream >> token) - { - linestream >> std::noskipws; - if (token[0] == '<' && token[token.size()-1] == '>') - { - // HEAD - if (!token_string.empty()) - { - switch (token_type) - { - case HEADER: - push_header(token_string); - break; - case OPCODE: - push_opcode(token_string); - break; - } - token_string.erase(); - } - token_string.append(token); - token_type = HEADER; - } - else if (token.find('=') != std::string::npos) - { - // HEAD - if (!token_string.empty()) - { - switch (token_type) - { - case HEADER: - push_header(token_string); - break; - case OPCODE: - push_opcode(token_string); - break; - } - token_string.erase(); - } - token_string.append(token); - token_type = OPCODE; - } - else - { - // TAIL - token_string.append(spaces, ' '); - token_string.append(token); - } - spaces = 0; - while (isspace(linestream.peek())) { - linestream.ignore(); - spaces++; - } - } +int SFZParser::triggerValue(const std::string& str) +{ + if (str == "release") + return SFZRegion::RELEASE; + else if (str == "first") + return SFZRegion::FIRST; + else if (str == "legato") + return SFZRegion::LEGATO; + return SFZRegion::ATTACK; +} + +int SFZParser::loopModeValue(const std::string& str) +{ + if (str == "no_loop") + return SFZRegion::NO_LOOP; + else if (str == "one_shot") + return SFZRegion::ONE_SHOT; + else if (str == "loop_continuous") + return SFZRegion::LOOP_CONTINUOUS; + else if (str == "loop_sustain") + return SFZRegion::LOOP_SUSTAIN; + return SFZRegion::SAMPLE_LOOP; +} + +void SFZParser::finishRegion(SFZRegion* region) +{ + SFZRegion* newRegion = new SFZRegion(region->instrument); + *newRegion = *region; + instrument.regions.push_back(newRegion); +} - // EOL - if (!token_string.empty()) - { - switch (token_type) - { - case HEADER: - push_header(token_string); - break; - case OPCODE: - push_opcode(token_string); - break; - } - token_string.erase(); - } - } - } +void SFZParser::error(const std::string& message) +{ + std::string fullMessage = message; + printf("%s\n", fullMessage.c_str()); +} - File::~File() - { - delete _current_group; - delete _instrument; - } +// ---------------------------------------- - Instrument* - File::GetInstrument() - { - return _instrument; - } +SFZRegion::SFZRegion(Instrument* i) +{ + instrument = i; + clear(); +} - void - File::push_header(std::string token) - { - if (token == "<group>") - { - _current_section = GROUP; - _current_group->Reset(); - } - else if (token == "<region>") - { - _current_section = REGION; - _current_region = _current_group->RegionFactory(); - _instrument->regions.push_back(_current_region); - } - else if (token == "<control>") - { - _current_section = CONTROL; - octave_offset = 0; - note_offset = 0; - } - else - { - _current_section = UNKNOWN; - std::cerr << "The header '" << token << "' is unsupported by libsfz!" << std::endl; - } +void SFZRegion::clear() +{ + hikey = 127; + hivel = 127; + pitch_keycenter = 60; // C4 + pitch_keytrack = 100; + bend_up = 200; + bend_down = -200; + volume = pan = 0.0; + amp_veltrack = 100.0; +} + +void SFZRegion::dump() +{ + printf("%d - %d, vel %d - %d", lokey, hikey, lovel, hivel); + if (!sample.empty()) { + printf(": %s", sample.c_str()); } - - void - File::push_opcode(std::string token) - { - if (_current_section == UNKNOWN) - return; - - std::string::size_type delimiter_index = token.find('='); - std::string key = token.substr(0, delimiter_index); - std::string value = token.substr(delimiter_index + 1); - - // sample definition - if ("sample" == key) - { - std::string path = default_path + value; - for (uint32_t i = 0; i < path.length(); i++) if (path[i] == '\\') path[i] = '/'; - switch (_current_section) - { - case REGION: - _current_region->sample = path; - case GROUP: - _current_group->sample = path; - } - return; - } + printf("\n"); +} - // control header directives - else if ("default_path" == key) - { - switch (_current_section) - { - case CONTROL: - default_path = value; - } - return; - } - else if ("octave_offset" == key) - { - switch (_current_section) - { - case CONTROL: - octave_offset = boost::lexical_cast<int>(value); - } - return; - } - else if ("note_offset" == key) - { - switch (_current_section) - { - case CONTROL: - note_offset = boost::lexical_cast<int>(value); - } - return; - } - // input controls - else if ("lochan" == key) - { - switch (_current_section) - { - case REGION: - _current_region->lochan = boost::lexical_cast<int>(value); - case GROUP: - _current_group->lochan = boost::lexical_cast<int>(value); - } - return; - } - else if ("hichan" == key) - { - switch (_current_section) - { - case REGION: - _current_region->hichan = boost::lexical_cast<int>(value); - case GROUP: - _current_group->hichan = boost::lexical_cast<int>(value); - } - return; - } - else if ("lokey" == key) - { - switch (_current_section) - { - case REGION: - _current_region->lokey = boost::lexical_cast<int>(value) + note_offset + 12 * octave_offset; - case GROUP: - _current_group->lokey = boost::lexical_cast<int>(value) + note_offset + 12 * octave_offset; - } - return; - } - else if ("hikey" == key) - { - switch (_current_section) - { - case REGION: - _current_region->hikey = boost::lexical_cast<int>(value) + note_offset + 12 * octave_offset; - case GROUP: - _current_group->hikey = boost::lexical_cast<int>(value) + note_offset + 12 * octave_offset; - } - return; - } - else if ("key" == key) - { - switch (_current_section) - { - case REGION: - _current_region->lokey = boost::lexical_cast<int>(value) + note_offset + 12 * octave_offset; - _current_region->hikey = boost::lexical_cast<int>(value) + note_offset + 12 * octave_offset; - case GROUP: - _current_group->lokey = boost::lexical_cast<int>(value) + note_offset + 12 * octave_offset; - _current_group->hikey = boost::lexical_cast<int>(value) + note_offset + 12 * octave_offset; - } - return; - } - else if ("lovel" == key) - { - switch (_current_section) - { - case REGION: - _current_region->lovel = boost::lexical_cast<int>(value); - case GROUP: - _current_group->lovel = boost::lexical_cast<int>(value); - } - return; - } - else if ("hivel" == key) - { - switch (_current_section) - { - case REGION: - _current_region->hivel = boost::lexical_cast<int>(value); - case GROUP: - _current_group->hivel = boost::lexical_cast<int>(value); - } - return; - } - else if ("lobend" == key) - { - switch (_current_section) - { - case REGION: - _current_region->lobend = boost::lexical_cast<int>(value); - case GROUP: - _current_group->lobend = boost::lexical_cast<int>(value); - } - return; - } - else if ("hibend" == key) - { - switch (_current_section) - { - case REGION: - _current_region->hibend = boost::lexical_cast<int>(value); - case GROUP: - _current_group->hibend = boost::lexical_cast<int>(value); - } - return; - } - else if ("lobpm" == key) - { - switch (_current_section) - { - case REGION: - _current_region->lobpm = boost::lexical_cast<int>(value); - case GROUP: - _current_group->lobpm = boost::lexical_cast<int>(value); - } - return; - } - else if ("hibpm" == key) - { - switch (_current_section) - { - case REGION: - _current_region->hibpm = boost::lexical_cast<int>(value); - case GROUP: - _current_group->hibpm = boost::lexical_cast<int>(value); - } - return; - } - else if ("lochanaft" == key) - { - switch (_current_section) - { - case REGION: - _current_region->lochanaft = boost::lexical_cast<int>(value); - case GROUP: - _current_group->lochanaft = boost::lexical_cast<int>(value); - } - return; - } - else if ("hichanaft" == key) - { - switch (_current_section) - { - case REGION: - _current_region->hichanaft = boost::lexical_cast<int>(value); - case GROUP: - _current_group->hichanaft = boost::lexical_cast<int>(value); - } - return; - } - else if ("lopolyaft" == key) - { - switch (_current_section) - { - case REGION: - _current_region->lopolyaft = boost::lexical_cast<int>(value); - case GROUP: - _current_group->lopolyaft = boost::lexical_cast<int>(value); - } - return; - } - else if ("hipolyaft" == key) - { - switch (_current_section) - { - case REGION: - _current_region->hipolyaft = boost::lexical_cast<int>(value); - case GROUP: - _current_group->hipolyaft = boost::lexical_cast<int>(value); - } - return; - } - else if ("loprog" == key) - { - switch (_current_section) - { - case REGION: - _current_region->loprog = boost::lexical_cast<int>(value); - case GROUP: - _current_group->loprog = boost::lexical_cast<int>(value); - } - return; - } - else if ("hiprog" == key) - { - switch (_current_section) - { - case REGION: - _current_region->hiprog = boost::lexical_cast<int>(value); - case GROUP: - _current_group->hiprog = boost::lexical_cast<int>(value); - } - return; - } - else if ("lorand" == key) - { - switch (_current_section) - { - case REGION: - _current_region->lorand = boost::lexical_cast<float>(value); - case GROUP: - _current_group->lorand = boost::lexical_cast<float>(value); - } - return; - } - else if ("hirand" == key) - { - switch (_current_section) - { - case REGION: - _current_region->hirand = boost::lexical_cast<float>(value); - case GROUP: - _current_group->hirand = boost::lexical_cast<float>(value); - } - return; - } - else if ("lotimer" == key) - { - switch (_current_section) - { - case REGION: - _current_region->lotimer = boost::lexical_cast<float>(value); - case GROUP: - _current_group->lotimer = boost::lexical_cast<float>(value); - } - return; - } - else if ("hitimer" == key) - { - switch (_current_section) - { - case REGION: - _current_region->hitimer = boost::lexical_cast<float>(value); - case GROUP: - _current_group->hitimer = boost::lexical_cast<float>(value); - } - return; - } - else if ("seq_length" == key) - { - switch (_current_section) - { - case REGION: - _current_region->seq_length = boost::lexical_cast<int>(value); - case GROUP: - _current_group->seq_length = boost::lexical_cast<int>(value); - } - return; - } - else if ("seq_position" == key) - { - switch (_current_section) - { - case REGION: - _current_region->seq_position = boost::lexical_cast<int>(value); - case GROUP: - _current_group->seq_position = boost::lexical_cast<int>(value); - } - return; - } - else if ("sw_lokey" == key) - { - switch (_current_section) - { - case REGION: - _current_region->sw_lokey = boost::lexical_cast<int>(value) + note_offset + 12 * octave_offset; - case GROUP: - _current_group->sw_lokey = boost::lexical_cast<int>(value) + note_offset + 12 * octave_offset; - } - return; - } - else if ("sw_hikey" == key) - { - switch (_current_section) - { - case REGION: - _current_region->sw_hikey = boost::lexical_cast<int>(value) + note_offset + 12 * octave_offset; - case GROUP: - _current_group->sw_hikey = boost::lexical_cast<int>(value) + note_offset + 12 * octave_offset; - } - return; - } - else if ("sw_last" == key) - { - switch (_current_section) - { - case REGION: - _current_region->sw_last = boost::lexical_cast<int>(value) + note_offset + 12 * octave_offset; - case GROUP: - _current_group->sw_last = boost::lexical_cast<int>(value) + note_offset + 12 * octave_offset; - } - return; - } - else if ("sw_down" == key) - { - switch (_current_section) - { - case REGION: - _current_region->sw_down = boost::lexical_cast<int>(value) + note_offset + 12 * octave_offset; - case GROUP: - _current_group->sw_down = boost::lexical_cast<int>(value) + note_offset + 12 * octave_offset; - } - return; - } - else if ("sw_up" == key) - { - switch (_current_section) - { - case REGION: - _current_region->sw_up = boost::lexical_cast<int>(value) + note_offset + 12 * octave_offset; - case GROUP: - _current_group->sw_up = boost::lexical_cast<int>(value) + note_offset + 12 * octave_offset; - } - return; - } - else if ("sw_previous" == key) - { - switch (_current_section) - { - case REGION: - _current_region->sw_previous = boost::lexical_cast<int>(value) + note_offset + 12 * octave_offset; - case GROUP: - _current_group->sw_previous = boost::lexical_cast<int>(value) + note_offset + 12 * octave_offset; - } - return; - } - else if ("sw_vel" == key) - { - switch (_current_section) - { - case REGION: - if (value == "current") - _current_region->sw_vel = VEL_CURRENT; - else if (value == "previous") - _current_region->sw_vel = VEL_PREVIOUS; - case GROUP: - if (value == "current") - _current_group->sw_vel = VEL_CURRENT; - else if (value == "previous") - _current_group->sw_vel = VEL_PREVIOUS; - } - return; - } - else if ("trigger" == key) - { - switch (_current_section) - { - case REGION: - if (value == "attack") - _current_region->trigger = TRIGGER_ATTACK; - else if (value == "release") - _current_region->trigger = TRIGGER_RELEASE; - else if (value == "first") - _current_region->trigger = TRIGGER_FIRST; - else if (value == "legato") - _current_region->trigger = TRIGGER_LEGATO; - case GROUP: - if (value == "attack") - _current_group->trigger = TRIGGER_ATTACK; - else if (value == "release") - _current_group->trigger = TRIGGER_RELEASE; - else if (value == "first") - _current_group->trigger = TRIGGER_FIRST; - else if (value == "legato") - _current_group->trigger = TRIGGER_LEGATO; - } - return; - } - else if ("group" == key) - { - switch (_current_section) - { - case REGION: - _current_region->group = boost::lexical_cast<int>(value); - case GROUP: - _current_group->group = boost::lexical_cast<int>(value); - } - return; - } - else if ("off_by" == key) - { - switch (_current_section) - { - case REGION: - _current_region->off_by = boost::lexical_cast<int>(value); - case GROUP: - _current_group->off_by = boost::lexical_cast<int>(value); - } - return; - } - else if ("off_mode" == key) - { - switch (_current_section) - { - case REGION: - if (value == "fast") - _current_region->off_mode = OFF_FAST; - else if (value == "normal") - _current_region->off_mode = OFF_NORMAL; - case GROUP: - if (value == "fast") - _current_group->off_mode = OFF_FAST; - else if (value == "normal") - _current_group->off_mode = OFF_NORMAL; - } - return; - } - - // sample player - else if ("count" == key) - { - switch (_current_section) - { - case REGION: - _current_region->count = boost::lexical_cast<int>(value); - case GROUP: - _current_group->count = boost::lexical_cast<int>(value); - } - return; - } - else if ("delay" == key) - { - switch (_current_section) - { - case REGION: - _current_region->delay = boost::lexical_cast<float>(value); - case GROUP: - _current_group->delay = boost::lexical_cast<float>(value); - } - return; - } - else if ("delay_random" == key) - { - switch (_current_section) - { - case REGION: - _current_region->delay_random = boost::lexical_cast<float>(value); - case GROUP: - _current_group->delay_random = boost::lexical_cast<float>(value); - } - return; - } - else if ("delay_beats" == key) - { - switch (_current_section) - { - case REGION: - _current_region->delay_beats = boost::lexical_cast<int>(value); - case GROUP: - _current_group->delay_beats = boost::lexical_cast<int>(value); - } - return; - } - else if ("stop_beats" == key) - { - switch (_current_section) - { - case REGION: - _current_region->stop_beats = boost::lexical_cast<int>(value); - case GROUP: - _current_group->stop_beats = boost::lexical_cast<int>(value); - } - return; - } - else if ("delay_samples" == key) - { - switch (_current_section) - { - case REGION: - _current_region->delay_samples = boost::lexical_cast<int>(value); - case GROUP: - _current_group->delay_samples = boost::lexical_cast<int>(value); - } - return; - } - else if ("end" == key) - { - switch (_current_section) - { - case REGION: - _current_region->end = boost::lexical_cast<int>(value); - case GROUP: - _current_group->end = boost::lexical_cast<int>(value); - } - return; - } - else if ("loop_crossfade" == key) - { - switch (_current_section) - { - case REGION: - _current_region->loop_crossfade = boost::lexical_cast<float>(value); - case GROUP: - _current_group->loop_crossfade = boost::lexical_cast<float>(value); - } - return; - } - else if ("offset_random" == key) - { - switch (_current_section) - { - case REGION: - _current_region->offset_random = boost::lexical_cast<int>(value); - case GROUP: - _current_group->offset_random = boost::lexical_cast<int>(value); - } - return; - } - else if ("loop_mode" == key) - { - switch (_current_section) - { - case REGION: - if (value == "no_loop") - _current_region->loop_mode = NO_LOOP; - else if (value == "one_shot") - _current_region->loop_mode = ONE_SHOT; - else if (value == "loop_continous") - _current_region->loop_mode = LOOP_CONTINOUS; - else if (value == "loop_sustain") - _current_region->loop_mode = LOOP_SUSTAIN; - case GROUP: - if (value == "no_loop") - _current_group->loop_mode = NO_LOOP; - else if (value == "one_shot") - _current_group->loop_mode = ONE_SHOT; - else if (value == "loop_continous") - _current_group->loop_mode = LOOP_CONTINOUS; - else if (value == "loop_sustain") - _current_group->loop_mode = LOOP_SUSTAIN; - } - return; - } - else if ("loop_start" == key) - { - switch (_current_section) - { - case REGION: - _current_region->loop_start = boost::lexical_cast<int>(value); - case GROUP: - _current_group->loop_start = boost::lexical_cast<int>(value); - } - return; - } - else if ("loop_end" == key) - { - switch (_current_section) - { - case REGION: - _current_region->loop_end = boost::lexical_cast<int>(value); - case GROUP: - _current_group->loop_end = boost::lexical_cast<int>(value); - } - return; - } - else if ("sync_beats" == key) - { - switch (_current_section) - { - case REGION: - _current_region->sync_beats = boost::lexical_cast<int>(value); - case GROUP: - _current_group->sync_beats = boost::lexical_cast<int>(value); - } - return; - } - else if ("sync_offset" == key) - { - switch (_current_section) - { - case REGION: - _current_region->sync_offset = boost::lexical_cast<int>(value); - case GROUP: - _current_group->sync_offset = boost::lexical_cast<int>(value); - } - return; - } +// ----------------------------------------- - // amplifier - else if ("volume" == key) - { - switch (_current_section) - { - case REGION: - _current_region->volume = boost::lexical_cast<float>(value); - case GROUP: - _current_group->volume = boost::lexical_cast<float>(value); - } - return; - } - else if ("pan" == key) - { - switch (_current_section) - { - case REGION: - _current_region->pan = boost::lexical_cast<float>(value); - case GROUP: - _current_group->pan = boost::lexical_cast<float>(value); - } - return; - } - else if ("width" == key) - { - switch (_current_section) - { - case REGION: - _current_region->width = boost::lexical_cast<float>(value); - case GROUP: - _current_group->width = boost::lexical_cast<float>(value); - } - return; - } - else if ("position" == key) - { - switch (_current_section) - { - case REGION: - _current_region->position = boost::lexical_cast<float>(value); - case GROUP: - _current_group->position = boost::lexical_cast<float>(value); - } - return; - } - else if ("amp_keytrack" == key) - { - switch (_current_section) - { - case REGION: - _current_region->amp_keytrack = boost::lexical_cast<float>(value); - case GROUP: - _current_group->amp_keytrack = boost::lexical_cast<float>(value); - } - return; - } - else if ("amp_keycenter" == key) - { - switch (_current_section) - { - case REGION: - _current_region->amp_keycenter = boost::lexical_cast<int>(value) + note_offset + 12 * octave_offset; - case GROUP: - _current_group->amp_keycenter = boost::lexical_cast<int>(value) + note_offset + 12 * octave_offset; - } - return; - } - else if ("amp_veltrack" == key) - { - switch (_current_section) - { - case REGION: - _current_region->amp_veltrack = boost::lexical_cast<float>(value); - case GROUP: - _current_group->amp_veltrack = boost::lexical_cast<float>(value); - } - return; - } - else if ("amp_random" == key) - { - switch (_current_section) - { - case REGION: - _current_region->amp_random = boost::lexical_cast<float>(value); - case GROUP: - _current_group->amp_random = boost::lexical_cast<float>(value); - } - return; - } - else if ("rt_decay" == key) - { - switch (_current_section) - { - case REGION: - _current_region->rt_decay = boost::lexical_cast<float>(value); - case GROUP: - _current_group->rt_decay = boost::lexical_cast<float>(value); - } - return; - } - else if ("xfin_lokey" == key) - { - switch (_current_section) - { - case REGION: - _current_region->xfin_lokey = boost::lexical_cast<int>(value) + note_offset + 12 * octave_offset; - case GROUP: - _current_group->xfin_lokey = boost::lexical_cast<int>(value) + note_offset + 12 * octave_offset; - } - return; - } - else if ("xfin_hikey" == key) - { - switch (_current_section) - { - case REGION: - _current_region->xfin_hikey = boost::lexical_cast<int>(value) + note_offset + 12 * octave_offset; - case GROUP: - _current_group->xfin_hikey = boost::lexical_cast<int>(value) + note_offset + 12 * octave_offset; - } - return; - } - else if ("xfout_lokey" == key) - { - switch (_current_section) - { - case REGION: - _current_region->xfout_lokey = boost::lexical_cast<int>(value) + note_offset + 12 * octave_offset; - case GROUP: - _current_group->xfout_lokey = boost::lexical_cast<int>(value) + note_offset + 12 * octave_offset; - } - return; - } - else if ("xfout_hikey" == key) - { - switch (_current_section) - { - case REGION: - _current_region->xfout_hikey = boost::lexical_cast<int>(value) + note_offset + 12 * octave_offset; - case GROUP: - _current_group->xfout_hikey = boost::lexical_cast<int>(value) + note_offset + 12 * octave_offset; - } - return; - } - else if ("xf_keycurve" == key) - { - switch (_current_section) - { - case REGION: - if (value == "gain") - _current_region->xf_keycurve = GAIN; - else if (value == "power") - _current_region->xf_keycurve = POWER; - case GROUP: - if (value == "gain") - _current_group->xf_keycurve = GAIN; - else if (value == "power") - _current_group->xf_keycurve = POWER; - } - return; - } - else if ("xfin_lovel" == key) - { - switch (_current_section) - { - case REGION: - _current_region->xfin_lovel = boost::lexical_cast<int>(value); - case GROUP: - _current_group->xfin_lovel = boost::lexical_cast<int>(value); - } - return; - } - else if ("xfin_hivel" == key) - { - switch (_current_section) - { - case REGION: - _current_region->xfin_hivel = boost::lexical_cast<int>(value); - case GROUP: - _current_group->xfin_hivel = boost::lexical_cast<int>(value); - } - return; - } - else if ("xfout_lovel" == key) - { - switch (_current_section) - { - case REGION: - _current_region->xfout_lovel = boost::lexical_cast<int>(value); - case GROUP: - _current_group->xfout_lovel = boost::lexical_cast<int>(value); - } - return; - } - else if ("xfout_hivel" == key) - { - switch (_current_section) - { - case REGION: - _current_region->xfout_hivel = boost::lexical_cast<int>(value); - case GROUP: - _current_group->xfout_hivel = boost::lexical_cast<int>(value); - } - return; - } - else if ("xf_velcurve" == key) - { - switch (_current_section) - { - case REGION: - if (value == "gain") - _current_region->xf_velcurve = GAIN; - else if (value == "power") - _current_region->xf_velcurve = POWER; - case GROUP: - if (value == "gain") - _current_group->xf_velcurve = GAIN; - else if (value == "power") - _current_group->xf_velcurve = POWER; - } - return; - } - else if ("xf_cccurve" == key) - { - switch (_current_section) - { - case REGION: - if (value == "gain") - _current_region->xf_cccurve = GAIN; - else if (value == "power") - _current_region->xf_cccurve = POWER; - case GROUP: - if (value == "gain") - _current_group->xf_cccurve = GAIN; - else if (value == "power") - _current_group->xf_cccurve = POWER; - } - return; - } - - // pitch - else if ("transpose" == key) - { - switch (_current_section) - { - case REGION: - _current_region->transpose = boost::lexical_cast<int>(value); - case GROUP: - _current_group->transpose = boost::lexical_cast<int>(value); - } - return; - } - else if ("tune" == key) - { - switch (_current_section) - { - case REGION: - _current_region->tune = boost::lexical_cast<int>(value); - case GROUP: - _current_group->tune = boost::lexical_cast<int>(value); - } - return; - } - else if ("pitch_keycenter" == key) - { - switch (_current_section) - { - case REGION: - _current_region->pitch_keycenter = boost::lexical_cast<int>(value) + note_offset + 12 * octave_offset; - case GROUP: - _current_group->pitch_keycenter = boost::lexical_cast<int>(value) + note_offset + 12 * octave_offset; - } - return; - } - else if ("pitch_keytrack" == key) - { - switch (_current_section) - { - case REGION: - _current_region->pitch_keytrack = boost::lexical_cast<int>(value); - case GROUP: - _current_group->pitch_keytrack = boost::lexical_cast<int>(value); - } - return; - } - else if ("pitch_veltrack" == key) - { - switch (_current_section) - { - case REGION: - _current_region->pitch_veltrack = boost::lexical_cast<int>(value); - case GROUP: - _current_group->pitch_veltrack = boost::lexical_cast<int>(value); - } - return; - } - else if ("pitch_random" == key) - { - switch (_current_section) - { - case REGION: - _current_region->pitch_random = boost::lexical_cast<int>(value); - case GROUP: - _current_group->pitch_random = boost::lexical_cast<int>(value); - } - return; - } - else if ("bend_up" == key) - { - switch (_current_section) - { - case REGION: - _current_region->bend_up = boost::lexical_cast<int>(value); - case GROUP: - _current_group->bend_up = boost::lexical_cast<int>(value); - } - return; - } - else if ("bend_down" == key) - { - switch (_current_section) - { - case REGION: - _current_region->bend_down = boost::lexical_cast<int>(value); - case GROUP: - _current_group->bend_down = boost::lexical_cast<int>(value); - } - return; - } - else if ("bend_step" == key) - { - switch (_current_section) - { - case REGION: - _current_region->bend_step = boost::lexical_cast<int>(value); - case GROUP: - _current_group->bend_step = boost::lexical_cast<int>(value); - } - return; - } - - // filter - else if ("fil_type" == key) - { - switch (_current_section) - { - case REGION: - if (value == "lpf_1p") - _current_region->fil_type = LPF_1P; - else if (value == "hpf_1p") - _current_region->fil_type = HPF_1P; - else if (value == "bpf_1p") - _current_region->fil_type = BPF_1P; - else if (value == "brf_1p") - _current_region->fil_type = BRF_1P; - else if (value == "apf_1p") - _current_region->fil_type = APF_1P; - else if (value == "lpf_2p") - _current_region->fil_type = LPF_2P; - else if (value == "hpf_2p") - _current_region->fil_type = HPF_2P; - else if (value == "bpf_2p") - _current_region->fil_type = BPF_2P; - else if (value == "brf_2p") - _current_region->fil_type = BRF_2P; - else if (value == "pkf_2p") - _current_region->fil_type = PKF_2P; - else if (value == "lpf_4p") - _current_region->fil_type = LPF_4P; - else if (value == "hpf_4p") - _current_region->fil_type = HPF_4P; - else if (value == "lpf_6p") - _current_region->fil_type = LPF_6P; - else if (value == "hpf_6p") - _current_region->fil_type = HPF_6P; - case GROUP: - if (value == "lpf_1p") - _current_group->fil_type = LPF_1P; - else if (value == "hpf_1p") - _current_group->fil_type = HPF_1P; - else if (value == "bpf_1p") - _current_group->fil_type = BPF_1P; - else if (value == "brf_1p") - _current_group->fil_type = BRF_1P; - else if (value == "apf_1p") - _current_group->fil_type = APF_1P; - else if (value == "lpf_2p") - _current_group->fil_type = LPF_2P; - else if (value == "hpf_2p") - _current_group->fil_type = HPF_2P; - else if (value == "bpf_2p") - _current_group->fil_type = BPF_2P; - else if (value == "brf_2p") - _current_group->fil_type = BRF_2P; - else if (value == "pkf_2p") - _current_group->fil_type = PKF_2P; - else if (value == "lpf_4p") - _current_group->fil_type = LPF_4P; - else if (value == "hpf_4p") - _current_group->fil_type = HPF_4P; - else if (value == "lpf_6p") - _current_group->fil_type = LPF_6P; - else if (value == "hpf_6p") - _current_group->fil_type = HPF_6P; - } - return; - } - else if ("fil2_type" == key) - { - switch (_current_section) - { - case REGION: - if (value == "lpf_1p") - _current_region->fil2_type = LPF_1P; - else if (value == "hpf_1p") - _current_region->fil2_type = HPF_1P; - else if (value == "bpf_1p") - _current_region->fil2_type = BPF_1P; - else if (value == "brf_1p") - _current_region->fil2_type = BRF_1P; - else if (value == "apf_1p") - _current_region->fil2_type = APF_1P; - else if (value == "lpf_2p") - _current_region->fil2_type = LPF_2P; - else if (value == "hpf_2p") - _current_region->fil2_type = HPF_2P; - else if (value == "bpf_2p") - _current_region->fil2_type = BPF_2P; - else if (value == "brf_2p") - _current_region->fil2_type = BRF_2P; - else if (value == "pkf_2p") - _current_region->fil2_type = PKF_2P; - else if (value == "lpf_4p") - _current_region->fil2_type = LPF_4P; - else if (value == "hpf_4p") - _current_region->fil2_type = HPF_4P; - else if (value == "lpf_6p") - _current_region->fil2_type = LPF_6P; - else if (value == "hpf_6p") - _current_region->fil2_type = HPF_6P; - case GROUP: - if (value == "lpf_1p") - _current_group->fil2_type = LPF_1P; - else if (value == "hpf_1p") - _current_group->fil2_type = HPF_1P; - else if (value == "bpf_1p") - _current_group->fil2_type = BPF_1P; - else if (value == "brf_1p") - _current_group->fil2_type = BRF_1P; - else if (value == "apf_1p") - _current_group->fil2_type = APF_1P; - else if (value == "lpf_2p") - _current_group->fil2_type = LPF_2P; - else if (value == "hpf_2p") - _current_group->fil2_type = HPF_2P; - else if (value == "bpf_2p") - _current_group->fil2_type = BPF_2P; - else if (value == "brf_2p") - _current_group->fil2_type = BRF_2P; - else if (value == "pkf_2p") - _current_group->fil2_type = PKF_2P; - else if (value == "lpf_4p") - _current_group->fil2_type = LPF_4P; - else if (value == "hpf_4p") - _current_group->fil2_type = HPF_4P; - else if (value == "lpf_6p") - _current_group->fil2_type = LPF_6P; - else if (value == "hpf_6p") - _current_group->fil2_type = HPF_6P; - } - return; - } - else if ("cutoff" == key) - { - switch (_current_section) - { - case REGION: - _current_region->cutoff = boost::lexical_cast<float>(value); - case GROUP: - _current_group->cutoff = boost::lexical_cast<float>(value); - } - return; - } - else if ("cutoff2" == key) - { - switch (_current_section) - { - case REGION: - _current_region->cutoff2 = boost::lexical_cast<float>(value); - case GROUP: - _current_group->cutoff2 = boost::lexical_cast<float>(value); - } - return; - } - else if ("cutoff_chanaft" == key) - { - switch (_current_section) - { - case REGION: - _current_region->cutoff_chanaft = boost::lexical_cast<int>(value); - case GROUP: - _current_group->cutoff_chanaft = boost::lexical_cast<int>(value); - } - return; - } - else if ("cutoff2_chanaft" == key) - { - switch (_current_section) - { - case REGION: - _current_region->cutoff2_chanaft = boost::lexical_cast<int>(value); - case GROUP: - _current_group->cutoff2_chanaft = boost::lexical_cast<int>(value); - } - return; - } - else if ("cutoff_polyaft" == key) - { - switch (_current_section) - { - case REGION: - _current_region->cutoff_polyaft = boost::lexical_cast<int>(value); - case GROUP: - _current_group->cutoff_polyaft = boost::lexical_cast<int>(value); - } - return; - } - else if ("cutoff2_polyaft" == key) - { - switch (_current_section) - { - case REGION: - _current_region->cutoff2_polyaft = boost::lexical_cast<int>(value); - case GROUP: - _current_group->cutoff2_polyaft = boost::lexical_cast<int>(value); - } - return; - } - else if ("resonance" == key) - { - switch (_current_section) - { - case REGION: - _current_region->resonance = boost::lexical_cast<float>(value); - case GROUP: - _current_group->resonance = boost::lexical_cast<float>(value); - } - return; - } - else if ("resonance2" == key) - { - switch (_current_section) - { - case REGION: - _current_region->resonance2 = boost::lexical_cast<float>(value); - case GROUP: - _current_group->resonance2 = boost::lexical_cast<float>(value); - } - return; - } - else if ("fil_keytrack" == key) - { - switch (_current_section) - { - case REGION: - _current_region->fil_keytrack = boost::lexical_cast<int>(value); - case GROUP: - _current_group->fil_keytrack = boost::lexical_cast<int>(value); - } - return; - } - else if ("fil2_keytrack" == key) - { - switch (_current_section) - { - case REGION: - _current_region->fil2_keytrack = boost::lexical_cast<int>(value); - case GROUP: - _current_group->fil2_keytrack = boost::lexical_cast<int>(value); - } - return; - } - else if ("fil_keycenter" == key) - { - switch (_current_section) - { - case REGION: - _current_region->fil_keycenter = boost::lexical_cast<int>(value) + note_offset + 12 * octave_offset; - case GROUP: - _current_group->fil_keycenter = boost::lexical_cast<int>(value) + note_offset + 12 * octave_offset; - } - return; - } - else if ("fil2_keycenter" == key) - { - switch (_current_section) - { - case REGION: - _current_region->fil2_keycenter = boost::lexical_cast<int>(value) + note_offset + 12 * octave_offset; - case GROUP: - _current_group->fil2_keycenter = boost::lexical_cast<int>(value) + note_offset + 12 * octave_offset; - } - return; - } - else if ("fil_veltrack" == key) - { - switch (_current_section) - { - case REGION: - _current_region->fil_veltrack = boost::lexical_cast<int>(value); - case GROUP: - _current_group->fil_veltrack = boost::lexical_cast<int>(value); - } - return; - } - else if ("fil2_veltrack" == key) - { - switch (_current_section) - { - case REGION: - _current_region->fil2_veltrack = boost::lexical_cast<int>(value); - case GROUP: - _current_group->fil2_veltrack = boost::lexical_cast<int>(value); - } - return; - } - else if ("fil_random" == key) - { - switch (_current_section) - { - case REGION: - _current_region->fil_random = boost::lexical_cast<int>(value); - case GROUP: - _current_group->fil_random = boost::lexical_cast<int>(value); - } - return; - } - else if ("fil2_random" == key) - { - switch (_current_section) - { - case REGION: - _current_region->fil2_random = boost::lexical_cast<int>(value); - case GROUP: - _current_group->fil2_random = boost::lexical_cast<int>(value); - } - return; - } - - // per voice equalizer - else if ("eq1_freq" == key) - { - switch (_current_section) - { - case REGION: - _current_region->eq1_freq = boost::lexical_cast<float>(value); - case GROUP: - _current_group->eq1_freq = boost::lexical_cast<float>(value); - } - return; - } - else if ("eq2_freq" == key) - { - switch (_current_section) - { - case REGION: - _current_region->eq2_freq = boost::lexical_cast<float>(value); - case GROUP: - _current_group->eq2_freq = boost::lexical_cast<float>(value); - } - return; - } - else if ("eq3_freq" == key) - { - switch (_current_section) - { - case REGION: - _current_region->eq3_freq = boost::lexical_cast<float>(value); - case GROUP: - _current_group->eq3_freq = boost::lexical_cast<float>(value); - } - return; - } - else if ("eq1_vel2freq" == key) - { - switch (_current_section) - { - case REGION: - _current_region->eq1_vel2freq = boost::lexical_cast<float>(value); - case GROUP: - _current_group->eq1_vel2freq = boost::lexical_cast<float>(value); - } - return; - } - else if ("eq2_vel2freq" == key) - { - switch (_current_section) - { - case REGION: - _current_region->eq2_vel2freq = boost::lexical_cast<float>(value); - case GROUP: - _current_group->eq2_vel2freq = boost::lexical_cast<float>(value); - } - return; - } - else if ("eq3_vel2freq" == key) - { - switch (_current_section) - { - case REGION: - _current_region->eq3_vel2freq = boost::lexical_cast<float>(value); - case GROUP: - _current_group->eq3_vel2freq = boost::lexical_cast<float>(value); - } - return; - } - else if ("eq1_bw" == key) - { - switch (_current_section) - { - case REGION: - _current_region->eq1_bw = boost::lexical_cast<float>(value); - case GROUP: - _current_group->eq1_bw = boost::lexical_cast<float>(value); - } - return; - } - else if ("eq2_bw" == key) - { - switch (_current_section) - { - case REGION: - _current_region->eq2_bw = boost::lexical_cast<float>(value); - case GROUP: - _current_group->eq2_bw = boost::lexical_cast<float>(value); - } - return; - } - else if ("eq3_bw" == key) - { - switch (_current_section) - { - case REGION: - _current_region->eq3_bw = boost::lexical_cast<float>(value); - case GROUP: - _current_group->eq3_bw = boost::lexical_cast<float>(value); - } - return; - } - else if ("eq1_gain" == key) - { - switch (_current_section) - { - case REGION: - _current_region->eq1_gain = boost::lexical_cast<float>(value); - case GROUP: - _current_group->eq1_gain = boost::lexical_cast<float>(value); - } - return; - } - else if ("eq2_gain" == key) - { - switch (_current_section) - { - case REGION: - _current_region->eq2_gain = boost::lexical_cast<float>(value); - case GROUP: - _current_group->eq2_gain = boost::lexical_cast<float>(value); - } - return; - } - else if ("eq3_gain" == key) - { - switch (_current_section) - { - case REGION: - _current_region->eq3_gain = boost::lexical_cast<float>(value); - case GROUP: - _current_group->eq3_gain = boost::lexical_cast<float>(value); - } - return; - } - else if ("eq1_vel2gain" == key) - { - switch (_current_section) - { - case REGION: - _current_region->eq1_vel2gain = boost::lexical_cast<float>(value); - case GROUP: - _current_group->eq1_vel2gain = boost::lexical_cast<float>(value); - } - return; - } - else if ("eq2_vel2gain" == key) - { - switch (_current_section) - { - case REGION: - _current_region->eq2_vel2gain = boost::lexical_cast<float>(value); - case GROUP: - _current_group->eq2_vel2gain = boost::lexical_cast<float>(value); - } - return; - } - else if ("eq3_vel2gain" == key) - { - switch (_current_section) - { - case REGION: - _current_region->eq3_vel2gain = boost::lexical_cast<float>(value); - case GROUP: - _current_group->eq3_vel2gain = boost::lexical_cast<float>(value); - } - return; - } - - //fixme: parse amp_velcurve_N - - // CCs - else - { - std::string::size_type delimiter_index = key.find("cc"); - std::string key_cc = key.substr(0, delimiter_index); - int num_cc = boost::lexical_cast<int>(key.substr(delimiter_index + 2)); - - // input controls - if ("lo" == key_cc) - { - switch (_current_section) - { - case REGION: - _current_region->locc[num_cc] = boost::lexical_cast<int>(value); - case GROUP: - _current_group->locc[num_cc] = boost::lexical_cast<int>(value); - } - return; - } - else if ("hi" == key_cc) - { - switch (_current_section) - { - case REGION: - _current_region->hicc[num_cc] = boost::lexical_cast<int>(value); - case GROUP: - _current_group->hicc[num_cc] = boost::lexical_cast<int>(value); - } - return; - } - else if ("start_lo" == key_cc) - { - switch (_current_section) - { - case REGION: - _current_region->start_locc[num_cc] = boost::lexical_cast<int>(value); - case GROUP: - _current_group->start_locc[num_cc] = boost::lexical_cast<int>(value); - } - return; - } - else if ("start_hi" == key_cc) - { - switch (_current_section) - { - case REGION: - _current_region->start_hicc[num_cc] = boost::lexical_cast<int>(value); - case GROUP: - _current_group->start_hicc[num_cc] = boost::lexical_cast<int>(value); - } - return; - } - else if ("stop_lo" == key_cc) - { - switch (_current_section) - { - case REGION: - _current_region->stop_locc[num_cc] = boost::lexical_cast<int>(value); - case GROUP: - _current_group->stop_locc[num_cc] = boost::lexical_cast<int>(value); - } - return; - } - else if ("stop_hi" == key_cc) - { - switch (_current_section) - { - case REGION: - _current_region->stop_hicc[num_cc] = boost::lexical_cast<int>(value); - case GROUP: - _current_group->stop_hicc[num_cc] = boost::lexical_cast<int>(value); - } - return; - } - else if ("on_lo" == key_cc) - { - switch (_current_section) - { - case REGION: - _current_region->on_locc[num_cc] = boost::lexical_cast<int>(value); - case GROUP: - _current_group->on_locc[num_cc] = boost::lexical_cast<int>(value); - } - return; - } - else if ("on_hi" == key_cc) - { - switch (_current_section) - { - case REGION: - _current_region->on_hicc[num_cc] = boost::lexical_cast<int>(value); - case GROUP: - _current_group->on_hicc[num_cc] = boost::lexical_cast<int>(value); - } - return; - } - - // sample player - else if ("delay_on" == key_cc) - { - switch (_current_section) - { - case REGION: - _current_region->delay_oncc[num_cc] = boost::lexical_cast<float>(value); - case GROUP: - _current_group->delay_oncc[num_cc] = boost::lexical_cast<float>(value); - } - return; - } - else if ("delay_samples_on" == key_cc) - { - switch (_current_section) - { - case REGION: - _current_region->delay_samples_oncc[num_cc] = boost::lexical_cast<int>(value); - case GROUP: - _current_group->delay_samples_oncc[num_cc] = boost::lexical_cast<int>(value); - } - return; - } - else if ("offset_on" == key_cc) - { - switch (_current_section) - { - case REGION: - _current_region->offset_oncc[num_cc] = boost::lexical_cast<int>(value); - case GROUP: - _current_group->offset_oncc[num_cc] = boost::lexical_cast<int>(value); - } - return; - } - - // amplifier - else if ("gain_on" == key_cc) - { - switch (_current_section) - { - case REGION: - _current_region->gain_oncc[num_cc] = boost::lexical_cast<float>(value); - case GROUP: - _current_group->gain_oncc[num_cc] = boost::lexical_cast<float>(value); - } - return; - } - else if ("xfin_lo" == key_cc) - { - switch (_current_section) - { - case REGION: - _current_region->xfin_locc[num_cc] = boost::lexical_cast<int>(value); - case GROUP: - _current_group->xfin_locc[num_cc] = boost::lexical_cast<int>(value); - } - return; - } - else if ("xfin_hi" == key_cc) - { - switch (_current_section) - { - case REGION: - _current_region->xfin_hicc[num_cc] = boost::lexical_cast<int>(value); - case GROUP: - _current_group->xfin_hicc[num_cc] = boost::lexical_cast<int>(value); - } - return; - } - else if ("xfout_lo" == key_cc) - { - switch (_current_section) - { - case REGION: - _current_region->xfout_locc[num_cc] = boost::lexical_cast<int>(value); - case GROUP: - _current_group->xfout_locc[num_cc] = boost::lexical_cast<int>(value); - } - return; - } - else if ("xfout_hi" == key_cc) - { - switch (_current_section) - { - case REGION: - _current_region->xfout_hicc[num_cc] = boost::lexical_cast<int>(value); - case GROUP: - _current_group->xfout_hicc[num_cc] = boost::lexical_cast<int>(value); - } - return; - } - - // filter - else if ("cutoff_on" == key_cc) - { - switch (_current_section) - { - case REGION: - _current_region->cutoff_oncc[num_cc] = boost::lexical_cast<int>(value); - case GROUP: - _current_group->cutoff_oncc[num_cc] = boost::lexical_cast<int>(value); - } - return; - } - else if ("cutoff2_on" == key_cc) - { - switch (_current_section) - { - case REGION: - _current_region->cutoff2_oncc[num_cc] = boost::lexical_cast<int>(value); - case GROUP: - _current_group->cutoff2_oncc[num_cc] = boost::lexical_cast<int>(value); - } - return; - } - else if ("cutoff_smooth" == key_cc) - { - switch (_current_section) - { - case REGION: - _current_region->cutoff_smoothcc[num_cc] = boost::lexical_cast<int>(value); - case GROUP: - _current_group->cutoff_smoothcc[num_cc] = boost::lexical_cast<int>(value); - } - return; - } - else if ("cutoff2_smooth" == key_cc) - { - switch (_current_section) - { - case REGION: - _current_region->cutoff2_smoothcc[num_cc] = boost::lexical_cast<int>(value); - case GROUP: - _current_group->cutoff2_smoothcc[num_cc] = boost::lexical_cast<int>(value); - } - return; - } - else if ("cutoff_step" == key_cc) - { - switch (_current_section) - { - case REGION: - _current_region->cutoff_stepcc[num_cc] = boost::lexical_cast<int>(value); - case GROUP: - _current_group->cutoff_stepcc[num_cc] = boost::lexical_cast<int>(value); - } - return; - } - else if ("cutoff2_step" == key_cc) - { - switch (_current_section) - { - case REGION: - _current_region->cutoff2_stepcc[num_cc] = boost::lexical_cast<int>(value); - case GROUP: - _current_group->cutoff2_stepcc[num_cc] = boost::lexical_cast<int>(value); - } - return; - } - else if ("cutoff_curve" == key_cc) - { - switch (_current_section) - { - case REGION: - _current_region->cutoff_curvecc[num_cc] = boost::lexical_cast<int>(value); - case GROUP: - _current_group->cutoff_curvecc[num_cc] = boost::lexical_cast<int>(value); - } - return; - } - else if ("cutoff2_curve" == key_cc) - { - switch (_current_section) - { - case REGION: - _current_region->cutoff2_curvecc[num_cc] = boost::lexical_cast<int>(value); - case GROUP: - _current_group->cutoff2_curvecc[num_cc] = boost::lexical_cast<int>(value); - } - return; - } - else if ("resonance_on" == key_cc) - { - switch (_current_section) - { - case REGION: - _current_region->resonance_oncc[num_cc] = boost::lexical_cast<int>(value); - case GROUP: - _current_group->resonance_oncc[num_cc] = boost::lexical_cast<int>(value); - } - return; - } - else if ("resonance2_on" == key_cc) - { - switch (_current_section) - { - case REGION: - _current_region->resonance2_oncc[num_cc] = boost::lexical_cast<int>(value); - case GROUP: - _current_group->resonance2_oncc[num_cc] = boost::lexical_cast<int>(value); - } - return; - } - else if ("resonance_smooth" == key_cc) - { - switch (_current_section) - { - case REGION: - _current_region->resonance_smoothcc[num_cc] = boost::lexical_cast<int>(value); - case GROUP: - _current_group->resonance_smoothcc[num_cc] = boost::lexical_cast<int>(value); - } - return; - } - else if ("resonance2_smooth" == key_cc) - { - switch (_current_section) - { - case REGION: - _current_region->resonance2_smoothcc[num_cc] = boost::lexical_cast<int>(value); - case GROUP: - _current_group->resonance2_smoothcc[num_cc] = boost::lexical_cast<int>(value); - } - return; - } - else if ("resonance_step" == key_cc) - { - switch (_current_section) - { - case REGION: - _current_region->resonance_stepcc[num_cc] = boost::lexical_cast<int>(value); - case GROUP: - _current_group->resonance_stepcc[num_cc] = boost::lexical_cast<int>(value); - } - return; - } - else if ("resonance2_step" == key_cc) - { - switch (_current_section) - { - case REGION: - _current_region->resonance2_stepcc[num_cc] = boost::lexical_cast<int>(value); - case GROUP: - _current_group->resonance2_stepcc[num_cc] = boost::lexical_cast<int>(value); - } - return; - } - else if ("resonance_curve" == key_cc) - { - switch (_current_section) - { - case REGION: - _current_region->resonance_curvecc[num_cc] = boost::lexical_cast<int>(value); - case GROUP: - _current_group->resonance_curvecc[num_cc] = boost::lexical_cast<int>(value); - } - return; - } - else if ("resonance2_curve" == key_cc) - { - switch (_current_section) - { - case REGION: - _current_region->resonance2_curvecc[num_cc] = boost::lexical_cast<int>(value); - case GROUP: - _current_group->resonance2_curvecc[num_cc] = boost::lexical_cast<int>(value); - } - return; - } - - // per voice equalizer - else if ("eq1_freq_on" == key_cc) - { - switch (_current_section) - { - case REGION: - _current_region->eq1_freq_oncc[num_cc] = boost::lexical_cast<int>(value); - case GROUP: - _current_group->eq1_freq_oncc[num_cc] = boost::lexical_cast<int>(value); - } - return; - } - else if ("eq2_freq_on" == key_cc) - { - switch (_current_section) - { - case REGION: - _current_region->eq2_freq_oncc[num_cc] = boost::lexical_cast<int>(value); - case GROUP: - _current_group->eq2_freq_oncc[num_cc] = boost::lexical_cast<int>(value); - } - return; - } - else if ("eq3_freq_on" == key_cc) - { - switch (_current_section) - { - case REGION: - _current_region->eq3_freq_oncc[num_cc] = boost::lexical_cast<int>(value); - case GROUP: - _current_group->eq3_freq_oncc[num_cc] = boost::lexical_cast<int>(value); - } - return; - } - else if ("eq1_bw_on" == key_cc) - { - switch (_current_section) - { - case REGION: - _current_region->eq1_bw_oncc[num_cc] = boost::lexical_cast<int>(value); - case GROUP: - _current_group->eq1_bw_oncc[num_cc] = boost::lexical_cast<int>(value); - } - return; - } - else if ("eq2_bw_on" == key_cc) - { - switch (_current_section) - { - case REGION: - _current_region->eq2_bw_oncc[num_cc] = boost::lexical_cast<int>(value); - case GROUP: - _current_group->eq2_bw_oncc[num_cc] = boost::lexical_cast<int>(value); - } - return; - } - else if ("eq3_bw_on" == key_cc) - { - switch (_current_section) - { - case REGION: - _current_region->eq3_bw_oncc[num_cc] = boost::lexical_cast<int>(value); - case GROUP: - _current_group->eq3_bw_oncc[num_cc] = boost::lexical_cast<int>(value); - } - return; - } - else if ("eq1_gain_on" == key_cc) - { - switch (_current_section) - { - case REGION: - _current_region->eq1_gain_oncc[num_cc] = boost::lexical_cast<int>(value); - case GROUP: - _current_group->eq1_gain_oncc[num_cc] = boost::lexical_cast<int>(value); - } - return; - } - else if ("eq2_gain_on" == key_cc) - { - switch (_current_section) - { - case REGION: - _current_region->eq2_gain_oncc[num_cc] = boost::lexical_cast<int>(value); - case GROUP: - _current_group->eq2_gain_oncc[num_cc] = boost::lexical_cast<int>(value); - } - return; - } - else if ("eq3_gain_on" == key_cc) - { - switch (_current_section) - { - case REGION: - _current_region->eq3_gain_oncc[num_cc] = boost::lexical_cast<int>(value); - case GROUP: - _current_group->eq3_gain_oncc[num_cc] = boost::lexical_cast<int>(value); - } - return; - } - } +Instrument::Instrument() +{ +} - std::cerr << "The opcode '" << key << "' is unsupported by libsfz!" << std::endl; +Instrument::~Instrument() +{ + uint32_t i; + for (i = 0; i < regions.size(); i++) { + delete regions[i]; } - +} -} // !namespace sfz +} diff --git a/plugins/ZamSFZ/libsfz/sfz.h b/plugins/ZamSFZ/libsfz/sfz.h index 3dfe480..d5d24ab 100644 --- a/plugins/ZamSFZ/libsfz/sfz.h +++ b/plugins/ZamSFZ/libsfz/sfz.h @@ -1,286 +1,110 @@ -/* -*- Mode: C++ ; c-basic-offset: 8 -*- */ -#ifndef LIBSFZ_SFZ_H -#define LIBSFZ_SFZ_H - -// SFZ 1.0 -// Copyright (c) 2008-2009, Anders Dahnielson -// -// Contact: anders@dahnielson.com -// -// 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 -// the Free Software Foundation; either version 2 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -#include <fstream> -#include <iostream> -#include <vector> +#include <stdio.h> +#include <string.h> #include <string> -#include <stdexcept> - -#include <boost/array.hpp> - -#define TRIGGER_ATTACK ((unsigned char) (1 << 0)) // 0x01 -#define TRIGGER_RELEASE ((unsigned char) (1 << 1)) // 0x02 -#define TRIGGER_FIRST ((unsigned char) (1 << 2)) // 0x04 -#define TRIGGER_LEGATO ((unsigned char) (1 << 3)) // 0x08 - -namespace sfz -{ - - // Forward declarations - class Articulation; - class Region; - class Group; - class Instrument; - class File; - - // Enumerations - enum sw_vel_t { VEL_CURRENT, VEL_PREVIOUS }; - enum off_mode_t { OFF_FAST, OFF_NORMAL }; - enum loop_mode_t { NO_LOOP, ONE_SHOT, LOOP_CONTINOUS, LOOP_SUSTAIN }; - enum curve_t { GAIN, POWER }; - enum filter_t { LPF_1P, HPF_1P, BPF_1P, BRF_1P, APF_1P, - LPF_2P, HPF_2P, BPF_2P, BRF_2P, PKF_2P, - LPF_4P, HPF_4P, - LPF_6P, HPF_6P }; - - typedef unsigned char trigger_t; - typedef unsigned char uint8_t; - - ///////////////////////////////////////////////////////////// - // class Articulation - - // Articulation containing all performance parameters for synthesis - class Articulation - { - public: - Articulation(); - virtual ~Articulation(); - }; - - ///////////////////////////////////////////////////////////// - // class Definition - - // Base definition used by groups and regions - class Definition - { - public: - Definition(); - virtual ~Definition(); - - // sample definition - std::string sample; - - // input controls - int lochan; int hichan; - int lokey; int hikey; - int lovel; int hivel; - boost::array<int, 128> locc; boost::array<int, 128> hicc; - int lobend; int hibend; - int lobpm; int hibpm; - int lochanaft; int hichanaft; - int lopolyaft; int hipolyaft; - int loprog; int hiprog; - float lorand; float hirand; - float lotimer; float hitimer; - - int seq_length; - int seq_position; - - boost::array<int, 128> start_locc; boost::array<int, 128> start_hicc; - boost::array<int, 128> stop_locc; boost::array<int, 128> stop_hicc; - - int sw_lokey; int sw_hikey; - int sw_last; - int sw_down; - int sw_up; - int sw_previous; - sw_vel_t sw_vel; +#include <vector> +#include <cstdlib> +#include <inttypes.h> - trigger_t trigger; +namespace sfz { - int group; - int off_by; - off_mode_t off_mode; +class Instrument; - boost::array<int, 128> on_locc; boost::array<int, 128> on_hicc; +class StringSlice { +public: + StringSlice(const char* startIn, const char* endIn) + : start(startIn), end(endIn) {} - // sample player - int count; - float delay; float delay_random; boost::array<float, 128> delay_oncc; - int delay_beats; int stop_beats; - int delay_samples; boost::array<int, 128> delay_samples_oncc; - int end; - float loop_crossfade; - int offset; int offset_random; boost::array<int, 128> offset_oncc; - loop_mode_t loop_mode; - int loop_start; int loop_end; - int sync_beats; - int sync_offset; - - // amplifier - float volume; - float pan; - float width; - float position; - float amp_keytrack; int amp_keycenter; float amp_veltrack; boost::array<float, 128> amp_velcurve_; float amp_random; - float rt_decay; - boost::array<float, 128> gain_oncc; - int xfin_lokey; int xfin_hikey; - int xfout_lokey; int xfout_hikey; - curve_t xf_keycurve; - int xfin_lovel; int xfin_hivel; - int xfout_lovel; int xfout_hivel; - curve_t xf_velcurve; - boost::array<int, 128> xfin_locc; boost::array<int, 128> xfin_hicc; - boost::array<int, 128> xfout_locc; boost::array<int, 128> xfout_hicc; - curve_t xf_cccurve; + unsigned int length() { + return end - start; + } - // pitch - int transpose; - int tune; - int pitch_keycenter; int pitch_keytrack; int pitch_veltrack; int pitch_random; - int bend_up; int bend_down; int bend_step; + bool operator==(const char* other) { + return strncmp(start, other, length()) == 0; + } + bool operator!=(const char* other) { + return strncmp(start, other, length()) != 0; + } - // filter - filter_t fil_type; filter_t fil2_type; - float cutoff; float cutoff2; - boost::array<int, 128> cutoff_oncc; boost::array<int, 128> cutoff2_oncc; - boost::array<int, 128> cutoff_smoothcc; boost::array<int, 128> cutoff2_smoothcc; - boost::array<int, 128> cutoff_stepcc; boost::array<int, 128> cutoff2_stepcc; - boost::array<int, 128> cutoff_curvecc; boost::array<int, 128> cutoff2_curvecc; - int cutoff_chanaft; int cutoff2_chanaft; - int cutoff_polyaft; int cutoff2_polyaft; - float resonance; float resonance2; - boost::array<int, 128> resonance_oncc; boost::array<int, 128> resonance2_oncc; - boost::array<int, 128> resonance_smoothcc; boost::array<int, 128> resonance2_smoothcc; - boost::array<int, 128> resonance_stepcc; boost::array<int, 128> resonance2_stepcc; - boost::array<int, 128> resonance_curvecc; boost::array<int, 128> resonance2_curvecc; - int fil_keytrack; int fil2_keytrack; - int fil_keycenter; int fil2_keycenter; - int fil_veltrack; int fil2_veltrack; - int fil_random; int fil2_random; + const char* start; + const char* end; +}; - // per voice equalizer - float eq1_freq; float eq2_freq; float eq3_freq; - boost::array<float, 128> eq1_freq_oncc; boost::array<float, 128> eq2_freq_oncc; boost::array<float, 128> eq3_freq_oncc; - float eq1_vel2freq; float eq2_vel2freq; float eq3_vel2freq; - float eq1_bw; float eq2_bw; float eq3_bw; - boost::array<float, 128> eq1_bw_oncc; boost::array<float, 128> eq2_bw_oncc; boost::array<float, 128> eq3_bw_oncc; - float eq1_gain; float eq2_gain; float eq3_gain; - boost::array<float, 128> eq1_gain_oncc; boost::array<float, 128> eq2_gain_oncc; boost::array<float, 128> eq3_gain_oncc; - float eq1_vel2gain; float eq2_vel2gain; float eq3_vel2gain; +class SFZRegion { +public: + enum Trigger { + ATTACK, RELEASE, FIRST, LEGATO }; - - ///////////////////////////////////////////////////////////// - // class Region - - /// Defines Region information of an Instrument - class Region : - public Definition - { - public: - Region(); - virtual ~Region(); - - /// Return true if region is triggered by key - bool 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); - - /// Return true if region is triggered by control change - bool 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); - - /// Return an articulation for the current state - Articulation* GetArticulation(int bend, uint8_t bpm, uint8_t chanaft, uint8_t polyaft, uint8_t* cc); - - // unique region id - int id; + enum LoopMode { + SAMPLE_LOOP, NO_LOOP, ONE_SHOT, LOOP_CONTINUOUS, LOOP_SUSTAIN }; - - ///////////////////////////////////////////////////////////// - // class Instrument - - /// Provides all neccessary information for the synthesis of an Instrument - class Instrument - { - public: - Instrument(); - virtual ~Instrument(); - - /// List of Regions belonging to this Instrument - std::vector<Region*> regions; + enum OffMode { + FAST, NORMAL }; - ///////////////////////////////////////////////////////////// - // class Group - /// A Group act just as a template containing Region default values - class Group : - public Definition - { - public: - Group(); - virtual ~Group(); - - /// Reset Group to default values - void Reset(); - - /// Create a new Region - Region* RegionFactory(); - - // id counter - int id; - - }; - - ///////////////////////////////////////////////////////////// - // class File - - /// Parses SFZ files and provides abstract access to the data - class File - { - public: - /// Load an existing SFZ file - File(std::string file, std::string path); - virtual ~File(); + SFZRegion(Instrument* i); + void clear(); + void dump(); + + bool matches(unsigned char note, unsigned char velocity, Trigger trigger) { + return + note >= lokey && note <= hikey && + velocity >= lovel && velocity <= hivel && + (trigger == this->trigger || + (this->trigger == ATTACK && (trigger == FIRST || trigger == LEGATO))); + } + + Instrument* instrument; + unsigned char lokey, hikey; + unsigned char lovel, hivel; + Trigger trigger; + unsigned long group, off_by; + OffMode off_mode; + + std::string sample; + unsigned long offset; + unsigned long end; + bool negative_end; + LoopMode loop_mode; + unsigned long loop_start, loop_end; + int transpose; + int tune; + int pitch_keycenter, pitch_keytrack; + int bend_up, bend_down; + + float volume, pan; + float amp_veltrack; +}; + +class Instrument +{ +public: + Instrument(); + ~Instrument(); - /// Returns a pointer to the instrument object - Instrument* GetInstrument(); + std::vector<SFZRegion*> regions; +}; - private: - void push_header(std::string token); - void push_opcode(std::string token); +class SFZParser { +public: + SFZParser(); + ~SFZParser(); - /// Pointer to the Instrument belonging to this file - Instrument* _instrument; + void read(const char* text, unsigned int length); + int readsfz(std::string path); - // state variables - enum section_t { UNKNOWN, GROUP, REGION, CONTROL }; - section_t _current_section; - Region* _current_region; - Group* _current_group; + Instrument instrument; - // control header directives - std::string default_path; - int octave_offset; - int note_offset; - }; +protected: + int line; -} // !namespace sfz + const char* handleLineEnd(const char* p); + const char* readPathInto(std::string* pathOut, const char* p, const char* end); + int keyValue(const std::string& str); + int triggerValue(const std::string& str); + int loopModeValue(const std::string& str); + void finishRegion(SFZRegion* region); + void error(const std::string& message); +}; -#endif // !LIBSFZ_SFZ_H +} |