1 // Licensed GNU LGPL v3 or later: http://www.gnu.org/licenses/lgpl.html
2
3 #include "smaudio.hh"
4 #include "smoutfile.hh"
5 #include "sminfile.hh"
6 #include "smstdioout.hh"
7 #include "smleakdebugger.hh"
8 #include "smmemout.hh"
9 #include "smmmapin.hh"
10 #include "smwavsetrepo.hh"
11 #include <fcntl.h>
12 #include <errno.h>
13 #include <stdio.h>
14 #include <assert.h>
15
16 using std::string;
17 using std::vector;
18
19 using namespace SpectMorph;
20
21 static LeakDebugger leak_debugger ("SpectMorph::Audio");
22
23 /**
24 * This function loads a SM-File.
25 *
26 * \param filename the name of the SM-File to be loaded
27 * \param load_options specify whether to load or skip debug information
28 * \returns a SpectMorph::Error indicating whether loading was successful
29 */
30 Error
load(const string & filename,AudioLoadOptions load_options)31 SpectMorph::Audio::load (const string& filename, AudioLoadOptions load_options)
32 {
33 GenericIn *file = GenericIn::open (filename);
34 if (!file)
35 return Error::Code::FILE_NOT_FOUND;
36
37 Error result = load (file, load_options);
38 delete file;
39
40 return result;
41 }
42
43 Error
load(GenericIn * file,AudioLoadOptions load_options)44 SpectMorph::Audio::load (GenericIn *file, AudioLoadOptions load_options)
45 {
46 SpectMorph::AudioBlock *audio_block = NULL;
47
48 InFile ifile (file);
49
50 string section;
51 size_t contents_pos = 0; /* init to get rid of gcc warning */
52
53 if (!ifile.open_ok())
54 return Error::Code::FILE_NOT_FOUND;
55
56 if (ifile.file_type() != "SpectMorph::Audio")
57 return Error::Code::FORMAT_INVALID;
58
59 if (ifile.file_version() != SPECTMORPH_BINARY_FILE_VERSION)
60 return Error::Code::FORMAT_INVALID;
61
62 if (load_options == AUDIO_SKIP_DEBUG)
63 {
64 ifile.add_skip_event ("original_fft");
65 ifile.add_skip_event ("debug_samples");
66 }
67
68 while (ifile.event() != InFile::END_OF_FILE)
69 {
70 if (ifile.event() == InFile::BEGIN_SECTION)
71 {
72 assert (section == "");
73 section = ifile.event_name();
74
75 if (section == "frame")
76 {
77 assert (audio_block == NULL);
78 assert (contents_pos < contents.size());
79
80 audio_block = &contents[contents_pos];
81 }
82 }
83 else if (ifile.event() == InFile::END_SECTION)
84 {
85 if (section == "frame")
86 {
87 assert (audio_block);
88
89 contents_pos++;
90 audio_block = NULL;
91 }
92
93 assert (section != "");
94 section = "";
95 }
96 else if (ifile.event() == InFile::INT)
97 {
98 if (section == "header")
99 {
100 if (ifile.event_name() == "zeropad")
101 zeropad = ifile.event_int();
102 else if (ifile.event_name() == "loop_start")
103 loop_start = ifile.event_int();
104 else if (ifile.event_name() == "loop_end")
105 loop_end = ifile.event_int();
106 else if (ifile.event_name() == "loop_type")
107 loop_type = static_cast<LoopType> (ifile.event_int());
108 else if (ifile.event_name() == "zero_values_at_start")
109 zero_values_at_start = ifile.event_int();
110 else if (ifile.event_name() == "sample_count")
111 sample_count = ifile.event_int();
112 else if (ifile.event_name() == "frame_count")
113 {
114 int frame_count = ifile.event_int();
115
116 contents.clear();
117 contents.resize (frame_count);
118 contents_pos = 0;
119 }
120 else
121 printf ("unhandled int %s %s\n", section.c_str(), ifile.event_name().c_str());
122 }
123 else
124 assert (false);
125 }
126 else if (ifile.event() == InFile::FLOAT)
127 {
128 if (section == "header")
129 {
130 if (ifile.event_name() == "mix_freq")
131 mix_freq = ifile.event_float();
132 else if (ifile.event_name() == "frame_size_ms")
133 frame_size_ms = ifile.event_float();
134 else if (ifile.event_name() == "frame_step_ms")
135 frame_step_ms = ifile.event_float();
136 else if (ifile.event_name() == "attack_start_ms")
137 attack_start_ms = ifile.event_float();
138 else if (ifile.event_name() == "attack_end_ms")
139 attack_end_ms = ifile.event_float();
140 else if (ifile.event_name() == "fundamental_freq")
141 fundamental_freq = ifile.event_float();
142 else if (ifile.event_name() == "original_samples_norm_db")
143 original_samples_norm_db = ifile.event_float();
144 else
145 printf ("unhandled float %s %s\n", section.c_str(), ifile.event_name().c_str());
146 }
147 else
148 assert (false);
149 }
150 else if (ifile.event() == InFile::FLOAT_BLOCK)
151 {
152 const vector<float>& fb = ifile.event_float_block();
153
154 if (section == "header")
155 {
156 if (ifile.event_name() == "original_samples")
157 {
158 original_samples = fb;
159 }
160 else
161 printf ("unhandled float block %s %s\n", section.c_str(), ifile.event_name().c_str());
162 }
163 else
164 {
165 assert (audio_block != NULL);
166 if (ifile.event_name() == "original_fft")
167 {
168 audio_block->original_fft = fb;
169 }
170 else if (ifile.event_name() == "debug_samples")
171 {
172 audio_block->debug_samples = fb;
173 }
174 else
175 {
176 printf ("unhandled fblock %s %s\n", section.c_str(), ifile.event_name().c_str());
177 assert (false);
178 }
179 }
180 }
181 else if (ifile.event() == InFile::UINT16_BLOCK)
182 {
183 const vector<uint16_t>& ib = ifile.event_uint16_block();
184 if (ifile.event_name() == "freqs")
185 {
186 audio_block->freqs = ib;
187
188 // ensure that freqs are sorted (we need that for LiveDecoder)
189 int old_freq = -1;
190
191 for (size_t i = 0; i < ib.size(); i++)
192 {
193 if (ib[i] < old_freq)
194 {
195 printf ("frequency data is not sorted, can't play file\n");
196 return Error::Code::PARSE_ERROR;
197 }
198 old_freq = ib[i];
199 }
200 }
201 else if (ifile.event_name() == "mags")
202 {
203 audio_block->mags = ib;
204 }
205 else if (ifile.event_name() == "phases")
206 {
207 audio_block->phases = ib;
208 }
209 else if (ifile.event_name() == "noise")
210 {
211 audio_block->noise = ib;
212 }
213 else
214 {
215 printf ("unhandled int16 block %s %s\n", section.c_str(), ifile.event_name().c_str());
216 assert (false);
217 }
218 }
219 else if (ifile.event() == InFile::READ_ERROR)
220 {
221 return Error::Code::PARSE_ERROR;
222 }
223 else
224 {
225 return Error::Code::PARSE_ERROR;
226 }
227 ifile.next_event();
228 }
229 return Error::Code::NONE;
230 }
231
Audio()232 SpectMorph::Audio::Audio()
233 {
234 leak_debugger.add (this);
235 }
236
~Audio()237 Audio::~Audio()
238 {
239 leak_debugger.del (this);
240 }
241
242 /**
243 * This function saves a SM-File.
244 *
245 * \param filename the name of the SM-File to be written
246 * \returns a SpectMorph::Error indicating saving loading was successful
247 */
248 Error
save(const string & filename) const249 SpectMorph::Audio::save (const string& filename) const
250 {
251 GenericOut *out = StdioOut::open (filename);
252 if (!out)
253 {
254 fprintf (stderr, "error: can't open output file '%s'.\n", filename.c_str());
255 exit (1);
256 }
257 Error result = save (out);
258 delete out; // close file
259
260 return result;
261 }
262
263 Error
save(GenericOut * file) const264 SpectMorph::Audio::save (GenericOut *file) const
265 {
266 OutFile of (file, "SpectMorph::Audio", SPECTMORPH_BINARY_FILE_VERSION);
267 assert (of.open_ok());
268
269 of.begin_section ("header");
270 of.write_float ("mix_freq", mix_freq);
271 of.write_float ("frame_size_ms", frame_size_ms);
272 of.write_float ("frame_step_ms", frame_step_ms);
273 of.write_float ("attack_start_ms", attack_start_ms);
274 of.write_float ("attack_end_ms", attack_end_ms);
275 of.write_float ("fundamental_freq", fundamental_freq);
276 of.write_float ("original_samples_norm_db", original_samples_norm_db);
277 of.write_int ("zeropad", zeropad);
278 of.write_int ("loop_type", loop_type);
279 of.write_int ("loop_start", loop_start);
280 of.write_int ("loop_end", loop_end);
281 of.write_int ("zero_values_at_start", zero_values_at_start);
282 of.write_int ("frame_count", contents.size());
283 of.write_int ("sample_count", sample_count);
284 of.write_float_block ("original_samples", original_samples);
285 of.end_section();
286
287 for (size_t i = 0; i < contents.size(); i++)
288 {
289 // ensure that freqs are sorted (we need that for LiveDecoder)
290 int old_freq = -1;
291
292 for (size_t f = 0; f < contents[i].freqs.size(); f++)
293 {
294 assert (contents[i].freqs[f] >= old_freq);
295 old_freq = contents[i].freqs[f];
296 }
297
298 of.begin_section ("frame");
299 of.write_uint16_block ("noise", contents[i].noise);
300 of.write_uint16_block ("freqs", contents[i].freqs);
301 of.write_uint16_block ("mags", contents[i].mags);
302 of.write_uint16_block ("phases", contents[i].phases);
303 of.write_float_block ("original_fft", contents[i].original_fft);
304 of.write_float_block ("debug_samples", contents[i].debug_samples);
305 of.end_section();
306 }
307 return Error::Code::NONE;
308 }
309
310 Audio *
clone() const311 Audio::clone() const
312 {
313 // create a deep copy (by saving/loading)
314 vector<unsigned char> audio_data;
315 MemOut audio_mo (&audio_data);
316
317 save (&audio_mo);
318
319 Audio *audio_clone = new Audio();
320 GenericIn *in = MMapIn::open_mem (&audio_data[0], &audio_data[audio_data.size()]);
321 audio_clone->load (in);
322 delete in;
323
324 return audio_clone;
325 }
326
327 bool
loop_type_to_string(LoopType loop_type,string & s)328 Audio::loop_type_to_string (LoopType loop_type, string& s)
329 {
330 switch (loop_type)
331 {
332 case LOOP_NONE:
333 {
334 s = "loop-none";
335 break;
336 }
337 case LOOP_FRAME_FORWARD:
338 {
339 s = "loop-frame-forward";
340 break;
341 }
342 case LOOP_FRAME_PING_PONG:
343 {
344 s = "loop-frame-ping-pong";
345 break;
346 }
347 case LOOP_TIME_FORWARD:
348 {
349 s = "loop-time-forward";
350 break;
351 }
352 case LOOP_TIME_PING_PONG:
353 {
354 s = "loop-time-ping-pong";
355 break;
356 }
357 default:
358 {
359 return false; // unknown loop type
360 }
361 }
362 return true;
363 }
364
365 bool
string_to_loop_type(const string & s,LoopType & loop_type)366 Audio::string_to_loop_type (const string& s, LoopType& loop_type)
367 {
368 if (s == "loop-none")
369 {
370 loop_type = LOOP_NONE;
371 }
372 else if (s == "loop-frame-forward")
373 {
374 loop_type = LOOP_FRAME_FORWARD;
375 }
376 else if (s == "loop-frame-ping-pong")
377 {
378 loop_type = LOOP_FRAME_PING_PONG;
379 }
380 else if (s == "loop-time-forward")
381 {
382 loop_type = LOOP_TIME_FORWARD;
383 }
384 else if (s == "loop-time-ping-pong")
385 {
386 loop_type = LOOP_TIME_PING_PONG;
387 }
388 else
389 {
390 return false; // unknown loop type
391 }
392 return true;
393 }
394
395 namespace
396 {
397
398 struct PartialData
399 {
400 uint16_t freq;
401 uint16_t mag;
402 };
403
404 static bool
pd_cmp(const PartialData & p1,const PartialData & p2)405 pd_cmp (const PartialData& p1, const PartialData& p2)
406 {
407 return p1.freq < p2.freq;
408 }
409
410 }
411
412 void
sort_freqs()413 AudioBlock::sort_freqs()
414 {
415 // sorting is required for morphing generated blocks only, which have no phase information
416 g_return_if_fail (phases.empty());
417
418 // sort partials by frequency
419 const size_t N = freqs.size();
420 PartialData pvec[N];
421
422 for (size_t p = 0; p < N; p++)
423 {
424 pvec[p].freq = freqs[p];
425 pvec[p].mag = mags[p];
426 }
427 std::sort (pvec, pvec + N, pd_cmp);
428
429 // replace partial data with sorted partial data
430 for (size_t p = 0; p < N; p++)
431 {
432 freqs[p] = pvec[p].freq;
433 mags[p] = pvec[p].mag;
434 }
435 }
436
437 double
estimate_fundamental(int n_partials,double * mag) const438 AudioBlock::estimate_fundamental (int n_partials, double *mag) const
439 {
440 g_return_val_if_fail (n_partials >= 1 && n_partials <= 3, 1.0);
441
442 double est_freq = 0, est_mag = 0;
443
444 auto update_estimate = [&] (int n, double freq_min, double freq_max)
445 {
446 if (n > n_partials)
447 return;
448
449 double best_freq = 0, best_mag = 0;
450
451 for (size_t p = 0; p < mags.size(); p++)
452 {
453 if (freqs_f (p) > freq_min && freqs_f (p) < freq_max && mags_f (p) > best_mag)
454 {
455 best_mag = mags_f (p);
456 best_freq = freqs_f (p) / n;
457 }
458 }
459 if (best_mag > 0)
460 {
461 est_mag += best_mag;
462 est_freq += best_freq * best_mag;
463 }
464 };
465
466 update_estimate (1, 0.8, 1.25);
467 update_estimate (2, 1.5, 2.5);
468 update_estimate (3, 2.5, 3.5);
469
470 if (mag)
471 *mag = est_mag;
472
473 if (est_mag > 0)
474 return est_freq / est_mag;
475 else
476 return 1;
477 }
478