1 // Licensed GNU LGPL v3 or later: http://www.gnu.org/licenses/lgpl.html
2 
3 #include "smmorphlinearmodule.hh"
4 #include "smmorphlinear.hh"
5 #include "smmorphplan.hh"
6 #include "smmorphplanvoice.hh"
7 #include "smmath.hh"
8 #include "smleakdebugger.hh"
9 #include "smlivedecoder.hh"
10 #include "smmorphutils.hh"
11 #include "smutils.hh"
12 #include <glib.h>
13 #include <assert.h>
14 
15 using namespace SpectMorph;
16 
17 using std::string;
18 using std::vector;
19 using std::min;
20 using std::max;
21 using std::sort;
22 
23 static LeakDebugger leak_debugger ("SpectMorph::MorphLinearModule");
24 
25 #define DEBUG (0)
26 
MorphLinearModule(MorphPlanVoice * voice)27 MorphLinearModule::MorphLinearModule (MorphPlanVoice *voice) :
28   MorphOperatorModule (voice)
29 {
30   my_source.module = this;
31 
32   audio.fundamental_freq     = 440;
33   audio.mix_freq             = 48000;
34   audio.frame_size_ms        = 1;
35   audio.frame_step_ms        = 1;
36   audio.zeropad              = 4;
37   audio.loop_type            = Audio::LOOP_NONE;
38 
39   leak_debugger.add (this);
40 }
41 
~MorphLinearModule()42 MorphLinearModule::~MorphLinearModule()
43 {
44   leak_debugger.del (this);
45 }
46 
47 void
set_config(MorphOperator * op)48 MorphLinearModule::set_config (MorphOperator *op)
49 {
50   MorphLinear *linear = dynamic_cast<MorphLinear *> (op);
51   MorphOperator *left_op = linear->left_op();
52   MorphOperator *right_op = linear->right_op();
53   MorphOperator *control_op = linear->control_op();
54 
55   if (left_op)
56     left_mod = morph_plan_voice->module (left_op);
57   else
58     left_mod = NULL;
59 
60   if (right_op)
61     right_mod = morph_plan_voice->module (right_op);
62   else
63     right_mod = NULL;
64 
65   string left_smset = linear->left_smset();
66   string right_smset = linear->right_smset();
67 
68   have_left_source = (left_smset != "");
69   if (have_left_source)
70     {
71       string smset_dir = linear->morph_plan()->index()->smset_dir();
72       string path = smset_dir + "/" + left_smset;
73 
74       left_source.set_wav_set (path);
75     }
76 
77   have_right_source = (right_smset != "");
78   if (have_right_source)
79     {
80       string smset_dir = linear->morph_plan()->index()->smset_dir();
81       string path = smset_dir + "/" + right_smset;
82 
83       right_source.set_wav_set (path);
84     }
85 
86   if (control_op)
87     control_mod = morph_plan_voice->module (control_op);
88   else
89     control_mod = NULL;
90 
91   clear_dependencies();
92   add_dependency (left_mod);
93   add_dependency (right_mod);
94   add_dependency (control_mod);
95 
96   morphing = linear->morphing();
97   control_type = linear->control_type();
98   db_linear = linear->db_linear();
99 }
100 
101 void
retrigger(int channel,float freq,int midi_velocity,float mix_freq)102 MorphLinearModule::MySource::retrigger (int channel, float freq, int midi_velocity, float mix_freq)
103 {
104   if (module->left_mod && module->left_mod->source())
105     {
106       module->left_mod->source()->retrigger (channel, freq, midi_velocity, mix_freq);
107     }
108 
109   if (module->right_mod && module->right_mod->source())
110     {
111       module->right_mod->source()->retrigger (channel, freq, midi_velocity, mix_freq);
112     }
113 
114   if (module->have_left_source)
115     {
116       module->left_source.retrigger (channel, freq, midi_velocity, mix_freq);
117     }
118 
119   if (module->have_right_source)
120     {
121       module->right_source.retrigger (channel, freq, midi_velocity, mix_freq);
122     }
123 }
124 
125 Audio*
audio()126 MorphLinearModule::MySource::audio()
127 {
128   return &module->audio;
129 }
130 
131 static void
dump_block(size_t index,const char * what,const AudioBlock & block)132 dump_block (size_t index, const char *what, const AudioBlock& block)
133 {
134   if (DEBUG)
135     {
136       for (size_t i = 0; i < block.freqs.size(); i++)
137         sm_printf ("%zd:%s %.17g %.17g\n", index, what, block.freqs_f (i), block.mags_f (i));
138     }
139 }
140 
141 static void
dump_line(size_t index,const char * what,double start,double end)142 dump_line (size_t index, const char *what, double start, double end)
143 {
144   if (DEBUG)
145     {
146       sm_printf ("%zd:%s %.17g %.17g\n", index, what, start, end);
147     }
148 }
149 
150 struct MagData
151 {
152   enum {
153     BLOCK_LEFT  = 0,
154     BLOCK_RIGHT = 1
155   }        block;
156   size_t   index;
157   uint16_t mag;
158 };
159 
160 static bool
md_cmp(const MagData & m1,const MagData & m2)161 md_cmp (const MagData& m1, const MagData& m2)
162 {
163   return m1.mag > m2.mag;  // sort with biggest magnitude first
164 }
165 
166 void
interp_mag_one(double interp,uint16_t * left,uint16_t * right)167 MorphLinearModule::MySource::interp_mag_one (double interp, uint16_t *left, uint16_t *right)
168 {
169   if (module->db_linear)
170     {
171       const uint16_t lmag_idb = max<uint16_t> (left ? *left : 0, SM_IDB_CONST_M96);
172       const uint16_t rmag_idb = max<uint16_t> (right ? *right : 0, SM_IDB_CONST_M96);
173 
174       const uint16_t mag_idb = sm_round_positive ((1 - interp) * lmag_idb + interp * rmag_idb);
175 
176       if (left)
177         *left = mag_idb;
178       if (right)
179         *right = mag_idb;
180     }
181   else
182     {
183       if (left)
184         *left = sm_factor2idb ((1 - interp) * sm_idb2factor (*left));
185       if (right)
186         *right = sm_factor2idb (interp * sm_idb2factor (*right));
187     }
188 }
189 
190 AudioBlock *
audio_block(size_t index)191 MorphLinearModule::MySource::audio_block (size_t index)
192 {
193   bool have_left = false, have_right = false;
194 
195   const double morphing = module->morph_plan_voice->control_input (module->morphing, module->control_type, module->control_mod);
196   const double interp = (morphing + 1) / 2; /* examples => 0: only left; 0.5 both equally; 1: only right */
197   const double time_ms = index; // 1ms frame step
198 
199   Audio *left_audio = nullptr;
200   Audio *right_audio = nullptr;
201   if (module->left_mod && module->left_mod->source())
202     {
203       have_left = MorphUtils::get_normalized_block (module->left_mod->source(), time_ms, left_block);
204       left_audio = module->left_mod->source()->audio();
205     }
206 
207   if (module->right_mod && module->right_mod->source())
208     {
209       have_right = MorphUtils::get_normalized_block (module->right_mod->source(), time_ms, right_block);
210       right_audio = module->right_mod->source()->audio();
211     }
212 
213   if (module->have_left_source)
214     {
215       have_left = MorphUtils::get_normalized_block (&module->left_source, time_ms, left_block);
216       left_audio = module->left_source.audio();
217     }
218 
219   if (module->have_right_source)
220     {
221       have_right = MorphUtils::get_normalized_block (&module->right_source, time_ms, right_block);
222       right_audio = module->right_source.audio();
223     }
224 
225   if (have_left && have_right) // true morph: both sources present
226     {
227       assert (left_audio && right_audio);
228 
229       module->audio_block.freqs.clear();
230       module->audio_block.mags.clear();
231 
232       dump_block (index, "A", left_block);
233       dump_block (index, "B", right_block);
234 
235       MagData mds[left_block.freqs.size() + right_block.freqs.size()];
236       size_t  mds_size = 0;
237       for (size_t i = 0; i < left_block.freqs.size(); i++)
238         {
239           MagData& md = mds[mds_size];
240 
241           md.block = MagData::BLOCK_LEFT;
242           md.index = i;
243           md.mag   = left_block.mags[i];
244           mds_size++;
245         }
246       for (size_t i = 0; i < right_block.freqs.size(); i++)
247         {
248           MagData& md = mds[mds_size];
249 
250           md.block = MagData::BLOCK_RIGHT;
251           md.index = i;
252           md.mag   = right_block.mags[i];
253           mds_size++;
254         }
255       sort (mds, mds + mds_size, md_cmp);
256 
257       size_t    left_freqs_size = left_block.freqs.size();
258       size_t    right_freqs_size = right_block.freqs.size();
259 
260       MorphUtils::FreqState   left_freqs[left_freqs_size];
261       MorphUtils::FreqState   right_freqs[right_freqs_size];
262 
263       init_freq_state (left_block.freqs, left_freqs);
264       init_freq_state (right_block.freqs, right_freqs);
265 
266       for (size_t m = 0; m < mds_size; m++)
267         {
268           size_t i, j;
269           bool match = false;
270           if (mds[m].block == MagData::BLOCK_LEFT)
271             {
272               i = mds[m].index;
273 
274               if (!left_freqs[i].used)
275                 match = MorphUtils::find_match (left_freqs[i].freq_f, right_freqs, right_freqs_size, &j);
276             }
277           else // (mds[m].block == MagData::BLOCK_RIGHT)
278             {
279               j = mds[m].index;
280               if (!right_freqs[j].used)
281                 match = MorphUtils::find_match (right_freqs[j].freq_f, left_freqs, left_freqs_size, &i);
282             }
283           if (match)
284             {
285               double freq;
286 
287               /* prefer frequency of louder partial */
288               const double lfreq = left_block.freqs[i];
289               const double rfreq = right_block.freqs[j];
290 
291               if (left_block.mags[i] > right_block.mags[j])
292                 {
293                   const double mfact = right_block.mags_f (j) / left_block.mags_f (i);
294 
295                   freq = lfreq + mfact * interp * (rfreq - lfreq);
296                 }
297               else
298                 {
299                   const double mfact = left_block.mags_f (i) / right_block.mags_f (j);
300 
301                   freq = rfreq + mfact * (1 - interp) * (lfreq - rfreq);
302                 }
303 
304               double mag;
305               if (module->db_linear)
306                 {
307                   // FIXME: this could be faster if we avoided db conversion (see grid morph)
308 
309                   double lmag_db = db_from_factor (left_block.mags_f (i), -100);
310                   double rmag_db = db_from_factor (right_block.mags_f (j), -100);
311 
312                   double mag_db = (1 - interp) * lmag_db + interp * rmag_db;
313 
314                   mag = db_to_factor (mag_db);
315                 }
316               else
317                 {
318                   mag = (1 - interp) * left_block.mags_f (i) + interp * right_block.mags_f (j);
319                 }
320               module->audio_block.freqs.push_back (freq);
321               module->audio_block.mags.push_back (sm_factor2idb (mag));
322 
323               dump_line (index, "L", left_block.freqs[i], right_block.freqs[j]);
324               left_freqs[i].used = 1;
325               right_freqs[j].used = 1;
326             }
327         }
328       for (size_t i = 0; i < left_block.freqs.size(); i++)
329         {
330           if (!left_freqs[i].used)
331             {
332               module->audio_block.freqs.push_back (left_block.freqs[i]);
333               module->audio_block.mags.push_back (left_block.mags[i]);
334 
335               interp_mag_one (interp, &module->audio_block.mags.back(), NULL);
336             }
337         }
338       for (size_t i = 0; i < right_block.freqs.size(); i++)
339         {
340           if (!right_freqs[i].used)
341             {
342               module->audio_block.freqs.push_back (right_block.freqs[i]);
343               module->audio_block.mags.push_back (right_block.mags[i]);
344 
345               interp_mag_one (interp, NULL, &module->audio_block.mags.back());
346             }
347         }
348       assert (left_block.noise.size() == right_block.noise.size());
349 
350       module->audio_block.noise.clear();
351       for (size_t i = 0; i < left_block.noise.size(); i++)
352         module->audio_block.noise.push_back (sm_factor2idb ((1 - interp) * left_block.noise_f (i) + interp * right_block.noise_f (i)));
353 
354       module->audio_block.sort_freqs();
355 
356       return &module->audio_block;
357     }
358   else if (have_left) // only left source output present
359     {
360       module->audio_block = left_block;
361       for (size_t i = 0; i < module->audio_block.noise.size(); i++)
362         module->audio_block.noise[i] = sm_factor2idb (module->audio_block.noise_f (i) * (1 - interp));
363       for (size_t i = 0; i < module->audio_block.freqs.size(); i++)
364         interp_mag_one (interp, &module->audio_block.mags[i], NULL);
365 
366       return &module->audio_block;
367     }
368   else if (have_right) // only right source output present
369     {
370       module->audio_block = right_block;
371       for (size_t i = 0; i < module->audio_block.noise.size(); i++)
372         module->audio_block.noise[i] = sm_factor2idb (module->audio_block.noise_f (i) * interp);
373       for (size_t i = 0; i < module->audio_block.freqs.size(); i++)
374         interp_mag_one (interp, NULL, &module->audio_block.mags[i]);
375 
376       return &module->audio_block;
377     }
378   return NULL;
379 }
380 
381 LiveDecoderSource *
source()382 MorphLinearModule::source()
383 {
384   return &my_source;
385 }
386