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