1 /* 2 * liquidsfz - sfz sampler 3 * 4 * Copyright (C) 2019 Stefan Westerfeld 5 * 6 * This library is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU Lesser General Public License as published by the 8 * Free Software Foundation; either version 2.1 of the License, or (at your 9 * option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 14 * for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public License 17 * along with this library; if not, write to the Free Software Foundation, 18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 */ 20 21 #ifndef LIQUIDSFZ_LOADER_HH 22 #define LIQUIDSFZ_LOADER_HH 23 24 #include <string> 25 #include <set> 26 27 #include "log.hh" 28 #include "samplecache.hh" 29 #include "curve.hh" 30 #include "filter.hh" 31 32 namespace LiquidSFZInternal 33 { 34 35 enum class Trigger { 36 ATTACK, 37 RELEASE, 38 CC 39 }; 40 41 enum class LoopMode { 42 NONE, /* no_loop */ 43 ONE_SHOT, /* one_shot */ 44 CONTINUOUS, /* loop_continuous */ 45 SUSTAIN, /* loop_sustain */ 46 }; 47 48 enum class OffMode { 49 FAST, 50 NORMAL, 51 TIME 52 }; 53 54 enum class XFCurve { 55 POWER, 56 GAIN 57 }; 58 59 class CCParamVec 60 { 61 public: 62 struct Entry 63 { 64 int curvecc = 0; 65 int cc = -1; 66 float value = 0; 67 }; 68 const std::vector<Entry>::const_iterator begin() const69 begin() const 70 { 71 return entries_.begin(); 72 } 73 const std::vector<Entry>::const_iterator end() const74 end() const 75 { 76 return entries_.end(); 77 } 78 bool empty() const79 empty() const 80 { 81 return entries_.empty(); 82 } 83 void set(int cc,float value)84 set (int cc, float value) 85 { 86 for (auto& entry : entries_) 87 { 88 if (entry.cc == cc) 89 { 90 /* overwrite old value */ 91 entry.value = value; 92 return; 93 } 94 } 95 Entry entry; 96 entry.cc = cc; 97 entry.value = value; 98 entries_.push_back (entry); 99 } 100 void set_curvecc(int cc,int curvecc)101 set_curvecc (int cc, int curvecc) 102 { 103 for (auto& entry : entries_) 104 { 105 if (entry.cc == cc) 106 { 107 /* overwrite old value */ 108 entry.curvecc = curvecc; 109 return; 110 } 111 } 112 Entry entry; 113 entry.cc = cc; 114 entry.curvecc = curvecc; 115 entries_.push_back (entry); 116 } 117 bool contains(int cc) const118 contains (int cc) const 119 { 120 for (const auto& entry : entries_) 121 if (entry.cc == cc) 122 return true; 123 return false; 124 } 125 private: 126 std::vector<Entry> entries_; 127 }; 128 129 struct EGParam 130 { EGParamLiquidSFZInternal::EGParam131 explicit EGParam (float b) 132 : base (b) 133 { 134 } 135 float base = 0; 136 float vel2 = 0; 137 CCParamVec cc_vec; 138 }; 139 140 struct XFCC 141 { 142 int cc = -1; 143 int lo = -1; 144 int hi = -1; 145 }; 146 147 struct CCInfo 148 { 149 int cc = -1; 150 bool has_label = false; 151 std::string label; 152 int default_value = 0; 153 }; 154 155 struct KeyInfo 156 { 157 int key = -1; 158 std::string label; 159 bool is_switch = false; 160 }; 161 162 struct FilterParams 163 { 164 Filter::Type type = Filter::Type::LPF_2P; 165 float cutoff = -1; 166 float resonance = 0; 167 CCParamVec cutoff_cc; 168 CCParamVec resonance_cc; 169 int keytrack = 0; 170 int keycenter = 60; 171 int veltrack = 0; 172 }; 173 174 struct LFOParams 175 { 176 int id = -1; 177 float freq = 0; 178 int wave = 0; // default to triangle 179 float delay = 0; 180 float fade = 0; 181 float phase = 0; 182 183 float pitch = 0; 184 float volume = 0; 185 float cutoff = 0; 186 187 CCParamVec freq_cc; 188 CCParamVec delay_cc; 189 CCParamVec fade_cc; 190 CCParamVec phase_cc; 191 192 CCParamVec pitch_cc; 193 CCParamVec volume_cc; 194 CCParamVec cutoff_cc; 195 196 struct LFOMod { 197 int to_index = -1; 198 float lfo_freq = 0; 199 CCParamVec lfo_freq_cc; 200 }; 201 std::vector<LFOMod> lfo_mods; // LFO modulating LFO 202 }; 203 204 struct SimpleLFO 205 { 206 enum Type { PITCH, AMP, FIL }; 207 bool used = false; 208 float delay = 0; 209 float fade = 0; 210 float freq = 0; 211 float depth = 0; 212 213 CCParamVec freq_cc; 214 CCParamVec depth_cc; 215 }; 216 217 struct CurveSection 218 { 219 int curve_index = -1; 220 Curve curve; 221 222 bool emptyLiquidSFZInternal::CurveSection223 empty() 224 { 225 return curve_index < 0; 226 } 227 }; 228 229 struct Limits 230 { 231 size_t max_lfos = 0; 232 size_t max_lfo_mods = 0; 233 }; 234 235 struct Region 236 { 237 std::string sample; 238 std::shared_ptr<SampleCache::Entry> cached_sample; 239 std::string location; 240 241 bool switch_match = true; 242 243 int lokey = 0; 244 int hikey = 127; 245 int lovel = 0; 246 int hivel = 127; 247 double lorand = 0; 248 double hirand = 1; 249 int pitch_keycenter = 60; 250 int pitch_keytrack = 100; 251 int loop_start = 0; 252 int loop_end = 0; 253 LoopMode loop_mode = LoopMode::NONE; 254 bool have_loop_mode = false; 255 bool have_loop_start = false; 256 bool have_loop_end = false; 257 Trigger trigger = Trigger::ATTACK; 258 int seq_length = 1; 259 int seq_position = 1; 260 std::vector<int> locc = std::vector<int> (128, 0); 261 std::vector<int> hicc = std::vector<int> (128, 127); 262 263 /* amp envelope generator */ 264 EGParam ampeg_delay { 0 }; 265 EGParam ampeg_attack { 0 }; 266 EGParam ampeg_hold { 0 }; 267 EGParam ampeg_decay { 0 }; 268 EGParam ampeg_sustain { 100 }; 269 EGParam ampeg_release { 0 }; 270 Curve amp_velcurve; 271 272 /* fil envelope generator */ 273 EGParam fileg_depth { 0 }; 274 EGParam fileg_delay { 0 }; 275 EGParam fileg_attack { 0 }; 276 EGParam fileg_hold { 0 }; 277 EGParam fileg_decay { 0 }; 278 EGParam fileg_sustain { 100 }; 279 EGParam fileg_release { 0 }; 280 281 float volume = 0; 282 float amplitude = 100; 283 float amp_veltrack = 100; 284 float amp_random = 0; 285 float pan = 0; 286 float rt_decay = 0; 287 uint group = 0; 288 uint off_by = 0; 289 OffMode off_mode = OffMode::FAST; 290 float off_time = 0; 291 float delay = 0; 292 uint offset = 0; 293 uint offset_random = 0; 294 295 int sw_lokey = -1; 296 int sw_hikey = -1; 297 int sw_lolast = -1; 298 int sw_hilast = -1; 299 int sw_default = -1; 300 std::string sw_label; 301 302 int tune = 0; 303 int transpose = 0; 304 int pitch_random = 0; 305 306 int bend_up = 200; 307 int bend_down = -200; 308 309 int xfin_lovel = 0; 310 int xfin_hivel = 0; 311 int xfout_lovel = 127; 312 int xfout_hivel = 127; 313 int xfin_lokey = 0; 314 int xfin_hikey = 0; 315 int xfout_lokey = 127; 316 int xfout_hikey = 127; 317 std::vector<XFCC> xfin_ccs; 318 std::vector<XFCC> xfout_ccs; 319 320 XFCurve xf_velcurve = XFCurve::POWER; 321 XFCurve xf_keycurve = XFCurve::POWER; 322 XFCurve xf_cccurve = XFCurve::POWER; 323 324 FilterParams fil, fil2; 325 326 std::vector<LFOParams> lfos; 327 328 SimpleLFO amplfo, pitchlfo, fillfo; 329 330 CCParamVec pan_cc; 331 CCParamVec gain_cc; 332 CCParamVec amplitude_cc; 333 CCParamVec tune_cc; 334 CCParamVec delay_cc; 335 CCParamVec offset_cc; 336 emptyLiquidSFZInternal::Region337 bool empty() 338 { 339 return sample == ""; 340 } 341 342 /* playback state */ 343 int play_seq = 1; 344 }; 345 346 struct SetCC 347 { 348 int cc; 349 int value; 350 }; 351 352 struct Control 353 { 354 std::string default_path; 355 struct Define 356 { 357 std::string variable; 358 std::string value; 359 }; 360 std::vector<Define> defines; 361 std::vector<SetCC> set_cc; 362 }; 363 364 class Synth; 365 366 class Loader 367 { 368 struct LineInfo 369 { 370 std::string filename; 371 372 int number = 0; 373 std::string line; 374 375 std::string locationLiquidSFZInternal::Loader::LineInfo376 location() const 377 { 378 return string_printf ("%s: line %d:",filename.c_str(), number); 379 } 380 }; 381 LineInfo current_line_info; 382 Synth *synth_ = nullptr; 383 384 bool find_variable (const std::string& line, Control::Define& out_define); 385 bool parse_eg_param (const std::string& eg, EGParam& amp_param, const std::string& key, const std::string& value, const std::string& param_str); 386 bool parse_ampeg_param (EGParam& amp_param, const std::string& key, const std::string& value, const std::string& param_str); 387 bool parse_fileg_param (EGParam& amp_param, const std::string& key, const std::string& value, const std::string& param_str); 388 bool parse_cc (const std::string& key, const std::string& value, CCParamVec& ccvec, const std::vector<std::string>& opcodes); 389 template <class ... Args> parse_cc(const std::string & key,const std::string & value,CCParamVec & ccvec,Args...args)390 bool parse_cc (const std::string& key, const std::string& value, CCParamVec& ccvec, Args ... args) /* make it possible to pass any number of strings here */ 391 { 392 std::vector<std::string> opcodes; 393 for (auto s : {args...}) 394 opcodes.push_back (s); 395 return parse_cc (key, value, ccvec, opcodes); 396 } 397 int lfo_index_by_id (Region& region, int id); 398 int lfo_mod_index_by_dest_id (Region& region, int lfo_index, int dest_id); 399 int find_unused_lfo_id (Region& region); 400 bool parse_freq_cc_lfo (Region& region, int lfo_index, const std::string& lfo_key, const std::string& value); 401 bool parse_lfo_param (Region& region, const std::string& key, const std::string& value); 402 bool parse_simple_lfo_param (Region& region, const std::string& type, SimpleLFO& lfo, const std::string& key, const std::string& value); 403 void convert_lfo (Region& region, SimpleLFO& simple_lfo, SimpleLFO::Type type); 404 405 static constexpr int MAX_INCLUDE_DEPTH = 25; 406 public: Loader(Synth * synth)407 Loader (Synth *synth) 408 { 409 synth_ = synth; 410 } 411 bool in_control = false; 412 bool in_curve = false; 413 CurveSection active_curve_section; 414 enum class RegionType { NONE, GLOBAL, MASTER, GROUP, REGION }; 415 RegionType region_type = RegionType::NONE; 416 Region active_global; 417 Region active_master; 418 Region active_group; 419 Region active_region; 420 bool have_master = false; 421 bool have_group = false; 422 std::vector<Region> regions; 423 std::vector<Curve> curves; 424 Control control; 425 std::vector<CCInfo> cc_list; 426 std::map<int, KeyInfo> key_map; 427 std::vector<KeyInfo> key_list; 428 CurveTable curve_table; 429 Limits limits; 430 std::string sample_path; 431 432 int convert_key(const std::string & k)433 convert_key (const std::string& k) 434 { 435 if (k.size() >= 2) 436 { 437 int offset = -1; 438 439 std::string::const_iterator ki = k.begin(); 440 switch (tolower (*ki++)) 441 { 442 case 'c': offset = 0; break; 443 case 'd': offset = 2; break; 444 case 'e': offset = 4; break; 445 case 'f': offset = 5; break; 446 case 'g': offset = 7; break; 447 case 'a': offset = 9; break; 448 case 'b': offset = 11; break; 449 } 450 if (offset >= 0) 451 { 452 if (*ki == '#') 453 { 454 offset++; 455 ki++; 456 } 457 else if (*ki == 'b') 458 { 459 offset--; 460 ki++; 461 } 462 // c4 should be 60 463 return atoi (std::string (ki, k.end()).c_str()) * 12 + offset + 12; 464 } 465 } 466 return atoi (k.c_str()); 467 } 468 int convert_int(const std::string & s)469 convert_int (const std::string& s) 470 { 471 return atoi (s.c_str()); 472 } 473 unsigned int convert_uint(const std::string & s)474 convert_uint (const std::string& s) 475 { 476 return strtoul (s.c_str(), nullptr, 10); 477 } 478 float convert_float(const std::string & s)479 convert_float (const std::string& s) 480 { 481 return string_to_double (s); 482 } 483 Trigger convert_trigger(const std::string & t)484 convert_trigger (const std::string& t) 485 { 486 if (t == "release") 487 return Trigger::RELEASE; 488 return Trigger::ATTACK; 489 } 490 LoopMode convert_loop_mode (const std::string& l); 491 OffMode convert_off_mode (const std::string& s); 492 XFCurve convert_xfcurve (const std::string& c); 493 Filter::Type convert_filter_type (const std::string& f); 494 int convert_wave (const std::string& w); 495 bool starts_with(const std::string & key,const std::string & start)496 starts_with (const std::string& key, const std::string& start) 497 { 498 return key.substr (0, start.size()) == start; 499 } 500 bool ends_with(const std::string & key,const std::string & end)501 ends_with (const std::string& key, const std::string& end) 502 { 503 return (key.length() >= end.length()) && key.compare (key.length() - end.length(), end.length(), end) == 0; 504 } 505 bool split_sub_key (const std::string& key, const std::string& start, int& sub_key); 506 XFCC& search_xfcc (std::vector<XFCC>& xfcc_vec, int cc, int def); 507 CCInfo& update_cc_info (int cc); 508 KeyInfo& update_key_info (int key); 509 void set_key_value (const std::string& key, const std::string& value); 510 void set_key_value_control (const std::string& key, const std::string& value); 511 void set_key_value_curve (const std::string& key, const std::string& value); 512 void handle_tag (const std::string& tag); 513 void add_curve (const CurveSection& curve); 514 void init_default_curves(); 515 std::string location()516 location() 517 { 518 return string_printf ("%s: line %d:", current_line_info.filename.c_str(), current_line_info.number); 519 } 520 bool preprocess_file (const std::string& filename, std::vector<LineInfo>& lines, int level, const std::string& content_str = ""); 521 bool parse (const std::string& filename, SampleCache& sample_cache); 522 }; 523 524 } 525 526 #endif /* LIQUIDSFZ_LOADER_HH */ 527