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