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