1 /*
2  * Copyright (C) 2020 Linux Studio Plugins Project <https://lsp-plug.in/>
3  *           (C) 2020 Vladimir Sadovnikov <sadko4u@gmail.com>
4  *
5  * This file is part of lsp-plugins
6  * Created on: 28 янв. 2016 г.
7  *
8  * lsp-plugins is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU Lesser General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * any later version.
12  *
13  * lsp-plugins is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with lsp-plugins. If not, see <https://www.gnu.org/licenses/>.
20  */
21 
22 #include <dsp/dsp.h>
23 #include <dsp/endian.h>
24 #include <core/types.h>
25 #include <core/debug.h>
26 #include <core/files/LSPCFile.h>
27 #include <core/files/AudioFile.h>
28 #include <core/files/lspc/LSPCAudioReader.h>
29 #include <core/alloc.h>
30 
31 #ifdef PLATFORM_WINDOWS
32 /*
33   Need to implement MMIO support
34   https://github.com/Microsoft/Windows-classic-samples/blob/master/Samples/Win7Samples/multimedia/directshow/dmo/dmodemo/wave.c
35  */
36 
37     #include <shtypes.h>
38     #include <shlwapi.h>
39     #ifdef __cplusplus
40         extern "C" {
41     #endif
42             #include <propvarutil.h>
43     #ifdef __cplusplus
44         }
45     #endif
46 
47     #include <guiddef.h>
48     #include <propidl.h>
49     #include <propvarutil.h>
50     #include <mfapi.h>
51     #include <mfidl.h>
52     #include <mferror.h>
53     #include <mfreadwrite.h>
54 
55     #include <mmsystem.h>
56     #include <msacm.h>
57 
58 // Define some missing values from GNU <mfidl.h>
59 #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
60     EXTERN_GUID( MF_TRANSCODE_CONTAINERTYPE, 0x150ff23f, 0x4abc, 0x478b, 0xac, 0x4f, 0xe1, 0x91, 0x6f, 0xba, 0x1c, 0xca );
61     EXTERN_GUID( MFTranscodeContainerType_ASF, 0x430f6f6e, 0xb6bf, 0x4fc1, 0xa0, 0xbd, 0x9e, 0xe4, 0x6e, 0xee, 0x2a, 0xfb );
62     EXTERN_GUID( MFTranscodeContainerType_MPEG4, 0xdc6cd05d, 0xb9d0, 0x40ef, 0xbd, 0x35, 0xfa, 0x62, 0x2c, 0x1a, 0xb2, 0x8a );
63     EXTERN_GUID( MFTranscodeContainerType_MP3, 0xe438b912, 0x83f1, 0x4de6, 0x9e, 0x3a, 0x9f, 0xfb, 0xc6, 0xdd, 0x24, 0xd1 );
64     EXTERN_GUID( MFTranscodeContainerType_FLAC, 0x31344aa3, 0x05a9, 0x42b5, 0x90, 0x1b, 0x8e, 0x9d, 0x42, 0x57, 0xf7, 0x5e );
65     EXTERN_GUID( MFTranscodeContainerType_3GP, 0x34c50167, 0x4472, 0x4f34, 0x9e, 0xa0, 0xc4, 0x9f, 0xba, 0xcf, 0x03, 0x7d );
66     EXTERN_GUID( MFTranscodeContainerType_AC3, 0x6d8d91c3, 0x8c91, 0x4ed1, 0x87, 0x42, 0x8c, 0x34, 0x7d, 0x5b, 0x44, 0xd0 );
67     EXTERN_GUID( MFTranscodeContainerType_ADTS, 0x132fd27d, 0x0f02, 0x43de, 0xa3, 0x01, 0x38, 0xfb, 0xbb, 0xb3, 0x83, 0x4e );
68     EXTERN_GUID( MFTranscodeContainerType_MPEG2, 0xbfc2dbf9, 0x7bb4, 0x4f8f, 0xaf, 0xde, 0xe1, 0x12, 0xc4, 0x4b, 0xa8, 0x82 );
69     EXTERN_GUID( MFTranscodeContainerType_WAVE, 0x64c3453c, 0x0f26, 0x4741, 0xbe, 0x63, 0x87, 0xbd, 0xf8, 0xbb, 0x93, 0x5b );
70     EXTERN_GUID( MFTranscodeContainerType_AVI, 0x7edfe8af, 0x402f, 0x4d76, 0xa3, 0x3c, 0x61, 0x9f, 0xd1, 0x57, 0xd0, 0xf1 );
71 
72     #if (WINVER >= _WIN32_WINNT_WIN8)
73         EXTERN_GUID( MFTranscodeContainerType_FMPEG4, 0x9ba876f1, 0x419f, 0x4b77, 0xa1, 0xe0, 0x35, 0x95, 0x9d, 0x9d, 0x40, 0x4 );
74     #endif // (WINVER >= _WIN32_WINNT_WIN8)
75 
76     EXTERN_GUID( MFTranscodeContainerType_AMR, 0x25d5ad3, 0x621a, 0x475b, 0x96, 0x4d, 0x66, 0xb1, 0xc8, 0x24, 0xf0, 0x79 );
77 #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) */
78 
79 #else
80     #include <sndfile.h>
81 #endif /* PLATFORM_WINDOWS */
82 
83 #define TMP_BUFFER_SIZE         1024
84 #define RESAMPLING_PERIODS      8
85 #define ACM_INPUT_BUFSIZE       0x1000
86 
87 namespace lsp
88 {
gcd_euclid(size_t a,size_t b)89     static size_t gcd_euclid(size_t a, size_t b)
90     {
91         while (b)
92         {
93             size_t c = a % b;
94             a = b;
95             b = c;
96         }
97         return a;
98     }
99 
AudioFile()100     AudioFile::AudioFile()
101     {
102         pData       = NULL;
103     }
104 
~AudioFile()105     AudioFile::~AudioFile()
106     {
107         destroy();
108     }
109 
destroy()110     void AudioFile::destroy()
111     {
112         lsp_trace("Destroy this=%p, pData=%p", this, pData);
113         if (pData != NULL)
114         {
115             destroy_file_content(pData);
116             pData       = NULL;
117         }
118     }
119 
create_file_content(size_t channels,size_t samples)120     AudioFile::file_content_t *AudioFile::create_file_content(size_t channels, size_t samples)
121     {
122         // Make number of samples multiple of 0x20 bytes
123         size_t buffer_len   = (samples + 0x03) & (~size_t(0x03));
124         size_t buffer_size  = (buffer_len * sizeof(float) + 0x1f) & (~size_t(0x1f)); // +3 - for convolution alignment
125         // Make header size multiple of 0x20 bytes
126         size_t header_size  = (sizeof(file_content_t) + sizeof(float *) * channels + 0x1f) & (~size_t(0x1f));
127         // Calculate total size
128         size_t total_size   = header_size + buffer_size * channels;
129 
130         // Allocate structure
131         uint8_t *ptr        = lsp_tmalloc(uint8_t, total_size);
132         if (ptr == NULL)
133             return NULL;
134 
135         // Initialize content
136         file_content_t *ct  = reinterpret_cast<file_content_t *>(ptr);
137         ct->nChannels       = channels;
138         ct->nSamples        = buffer_len;
139         ct->nSampleRate     = 0;
140         ptr                += header_size;
141 
142         for (size_t i=0; i < channels; ++i)
143         {
144             ct->vChannels[i]    = reinterpret_cast<float *>(ptr);
145             dsp::fill_zero(ct->vChannels[i], buffer_len);
146 
147             ptr                += buffer_size;
148         }
149 
150         return ct;
151     }
152 
grow_file_content(file_content_t * src,size_t samples)153     AudioFile::file_content_t *AudioFile::grow_file_content(file_content_t *src, size_t samples)
154     {
155         // We have enough space to store samples?
156         if (src->nSamples >= samples)
157             return src;
158 
159         // Allocate new file content
160         size_t new_cap = src->nSamples + (src->nSamples >> 1);
161         if (new_cap < samples)
162             new_cap     = samples + (samples >> 1);
163         file_content_t *dst = create_file_content(src->nSamples, new_cap);
164         if (dst == NULL)
165             return NULL;
166 
167         // Copy data from previous file content
168         for (size_t i=0; i < src->nChannels; ++i)
169             dsp::copy(dst->vChannels[i], src->vChannels[i], src->nSamples);
170 
171         // Drop previously used content and return new content
172         destroy_file_content(src);
173         return dst;
174     }
175 
destroy_file_content(file_content_t * content)176     void AudioFile::destroy_file_content(file_content_t *content)
177     {
178         if (content != NULL)
179             lsp_free(content);
180     }
181 
create_temporary_buffer(file_content_t * content,size_t from)182     AudioFile::temporary_buffer_t *AudioFile::create_temporary_buffer(file_content_t *content, size_t from)
183     {
184         // Make number of samples multiple of 0x20 bytes
185         size_t buffer_bytes     = content->nChannels * TMP_BUFFER_SIZE * sizeof(float);
186         size_t buffer_size      = ALIGN_SIZE(buffer_bytes, 0x20);
187         // Make header size multiple of 0x20 bytes
188         size_t header_size      = ALIGN_SIZE(sizeof(temporary_buffer_t) + sizeof(float *) * content->nChannels, 0x20);
189         // Calculate total size
190         size_t total_size       = header_size + buffer_size;
191 
192         // Allocate structure
193         uint8_t *ptr            = lsp_tmalloc(uint8_t, total_size);
194         if (ptr == NULL)
195             return NULL;
196 
197         // Initialize structure
198         temporary_buffer_t *tb  = reinterpret_cast<temporary_buffer_t *>(ptr);
199         ptr                    += header_size;
200 
201         tb->nSize               = 0;
202         tb->nCapacity           = buffer_bytes;
203         tb->nFrameSize          = content->nChannels * sizeof(float);
204         tb->nChannels           = content->nChannels;
205         tb->bData               = ptr;
206         for (size_t i=0; i<content->nChannels; ++i)
207         {
208             float *chPtr            = content->vChannels[i];
209             tb->vChannels[i]        = &chPtr[from];
210         }
211 
212         return tb;
213     }
214 
flush_temporary_buffer(temporary_buffer_t * tb)215     void AudioFile::flush_temporary_buffer(temporary_buffer_t *tb)
216     {
217         // Estimate number of bytes in buffer
218         size_t avail    = tb->nSize;
219         float *src      = reinterpret_cast<float *>(tb->bData);
220 
221         // Process all fully-read frames
222         while (avail >= tb->nFrameSize)
223         {
224             // Decode frame
225             for (size_t i=0; i<tb->nChannels; ++i)
226                 *(tb->vChannels[i]++)   = *(src++);
227             avail  -= tb->nFrameSize;
228         }
229 
230         // Update buffer contents
231         if (avail > 0)
232             ::memmove(tb->bData, src, avail);
233         tb->nSize           = avail;
234     }
235 
fill_temporary_buffer(temporary_buffer_t * tb,size_t max_samples)236     size_t AudioFile::fill_temporary_buffer(temporary_buffer_t *tb, size_t max_samples)
237     {
238         size_t avail    = tb->nCapacity - tb->nSize;
239         size_t count    = 0;
240         float *dst      = reinterpret_cast<float *>(&tb->bData[tb->nSize]);
241 
242         while ((avail >= tb->nFrameSize) && (count < max_samples))
243         {
244             // Encode frame
245             for (size_t i=0; i<tb->nChannels; ++i)
246                 *(dst++)    = *(tb->vChannels[i]++);
247             avail      -= tb->nFrameSize;
248             ++count;
249         }
250 
251         tb->nSize       = tb->nCapacity - avail;
252         return count;
253     }
254 
destroy_temporary_buffer(temporary_buffer_t * buffer)255     void AudioFile::destroy_temporary_buffer(temporary_buffer_t *buffer)
256     {
257         if (buffer != NULL)
258             lsp_free(buffer);
259     }
260 
create_samples(size_t channels,size_t sample_rate,size_t count)261     status_t AudioFile::create_samples(size_t channels, size_t sample_rate, size_t count)
262     {
263         // Allocate content
264         file_content_t *fc  = create_file_content(channels, count);
265         if (fc == NULL)
266             return STATUS_NO_MEM;
267 
268         // Cleanup content
269         fc->nSampleRate     = sample_rate;
270         for (size_t i=0; i<channels; ++i)
271             dsp::fill_zero(fc->vChannels[i], count);
272 
273         // Destroy previously used content and store new
274         if (pData != NULL)
275             destroy_file_content(pData);
276         pData               = fc;
277         return STATUS_OK;
278     }
279 
create(const Sample * sample,size_t sample_rate)280     status_t AudioFile::create(const Sample *sample, size_t sample_rate)
281     {
282         if (sample == NULL)
283             return STATUS_BAD_ARGUMENTS;
284 
285         // Allocate content
286         size_t channels     = sample->channels();
287         size_t length       = sample->length();
288         file_content_t *fc  = create_file_content(channels, length);
289         if (fc == NULL)
290             return STATUS_NO_MEM;
291 
292         // Cleanup content
293         fc->nSampleRate     = sample_rate;
294         for (size_t i=0; i<channels; ++i)
295             dsp::copy(fc->vChannels[i], sample->getBuffer(i), length);
296 
297         // Destroy previously used content and store new
298         if (pData != NULL)
299             destroy_file_content(pData);
300         pData               = fc;
301         return STATUS_OK;
302     }
303 
create(size_t channels,size_t sample_rate,float duration)304     status_t AudioFile::create(size_t channels, size_t sample_rate, float duration)
305     {
306         // Calculate the file length (in samples) and call the previous method
307         size_t count        = sample_rate * duration;
308         return create_samples(channels, sample_rate, count);
309     }
310 
load_lspc(const LSPString * path,float max_duration)311     status_t AudioFile::load_lspc(const LSPString *path, float max_duration)
312     {
313         LSPCFile fd;
314         status_t res = fd.open(path->get_native());
315         if (res != STATUS_OK)
316         {
317             fd.close();
318             return res;
319         }
320 
321         uint32_t chunk_id = 0;
322 
323         // Read profile (if present)
324         size_t skip         = 0;
325         size_t profVersion  = 1;
326         LSPCChunkReader *prof = fd.find_chunk(LSPC_CHUNK_PROFILE);
327         if (prof != NULL)
328         {
329             // Read profile header and check version
330             lspc_chunk_audio_profile_t p;
331             ssize_t n = prof->read_header(&p, sizeof(lspc_chunk_audio_profile_t));
332             if (n < 0)
333                 res     = status_t(-n);
334             else if ((p.common.version < 1) || (p.common.size < sizeof(lspc_chunk_audio_profile_t)))
335                 res     = STATUS_CORRUPTED_FILE;
336 
337             // Get related chunk identifier
338             chunk_id = BE_TO_CPU(p.chunk_id);
339             if ((res == STATUS_OK) && (chunk_id == 0))
340                 res = STATUS_CORRUPTED_FILE;
341 
342             // Get skip value:
343             profVersion = p.common.version;
344             if (profVersion >= 2)
345                 skip = BE_TO_CPU(p.skip);
346 
347             // Analyze final status
348             status_t res2 = prof->close();
349             if (res == STATUS_OK)
350                 res = res2;
351             delete prof;
352 
353             // Analyze status
354             if (res != STATUS_OK)
355             {
356                 fd.close();
357                 return res;
358             }
359         }
360 
361         // Try to open audio file chunk
362         LSPCAudioReader ar;
363         res = (chunk_id > 0) ? ar.open(&fd, chunk_id) : ar.open(&fd);
364         if (res != STATUS_OK)
365         {
366             ar.close();
367             fd.close();
368             return STATUS_BAD_FORMAT;
369         }
370 
371         // Read audio chunk header and check its size
372         lspc_audio_parameters_t aparams;
373         res = ar.get_parameters(&aparams);
374         if (res != STATUS_OK)
375         {
376             ar.close();
377             fd.close();
378             return res;
379         }
380 
381         // Setting up skip value for version 1 headers
382         if (profVersion < 2)
383         {
384             LSPCChunkReader *rd     = fd.read_chunk(ar.unique_id()); // Read the chunk with same ID as audio stream reader found
385             lspc_chunk_audio_header_t hdr;
386 
387             ssize_t res = rd->read_header(&hdr, sizeof(lspc_chunk_audio_header_t));
388             if ((res >= 0) && (hdr.common.version < 2)) // Field 'offset' is deprecated in header since version 2
389             {
390                 ssize_t offset      = BE_TO_CPU(hdr.offset);
391 
392                 size_t middle       = aparams.frames / 2 - 1;
393                 size_t skipNoOffset = middle - 1;
394                 size_t maxAhead     = aparams.frames - skipNoOffset;
395 
396                 if (offset >= 0)
397                 {
398                     size_t nOffset  = offset;
399                     nOffset         = (nOffset > maxAhead)? maxAhead : nOffset;
400                     skip            = skipNoOffset + nOffset;
401                 }
402                 else
403                 {
404                     size_t nOffset  = -offset;
405                     nOffset         = (nOffset > skipNoOffset)? skipNoOffset : nOffset;
406                     skip            = skipNoOffset - nOffset;
407                 }
408             }
409 
410             // Close reader and free resource
411             res = rd->close();
412             if (res != STATUS_OK)
413             {
414                 rd->close();
415                 delete rd;
416                 ar.close();
417                 fd.close();
418                 return res;
419             }
420             delete rd;
421             rd = NULL;
422         }
423 
424         skip                = (skip > aparams.frames)? aparams.frames : skip;
425         size_t max_samples  = (max_duration >= 0.0f) ? seconds_to_samples(aparams.sample_rate, max_duration) : -1;
426         lsp_trace("file parameters: frames=%d, channels=%d, sample_rate=%d max_duration=%.3f, max_samples=%d",
427                     int(aparams.frames), int(aparams.channels), int(aparams.sample_rate), max_duration, int(max_samples));
428 
429         aparams.frames     -= skip; // Remove number of frames to skip from audio parameters
430 
431         // Patch audio header
432         if ((max_samples >= 0) && (aparams.frames > max_samples))
433             aparams.frames     = max_samples;
434 
435         // Skip set of frames
436         if (skip > 0)
437         {
438             ssize_t skipped = ar.skip_frames(skip);
439             if (skipped != ssize_t(skip))
440             {
441                 ar.close();
442                 fd.close();
443                 return (skipped >= 0) ? STATUS_CORRUPTED_FILE : -skipped;
444             }
445         }
446 
447         // Create file content
448         file_content_t *fc      = NULL;
449         if (res == STATUS_OK)
450         {
451             fc = create_file_content(aparams.channels, aparams.frames);
452             if (fc == NULL)
453             {
454                 ar.close();
455                 fd.close();
456                 return STATUS_NO_MEM;
457             }
458 
459             fc->nSampleRate         = aparams.sample_rate;
460         }
461 
462         // Allocate temporary buffer
463         temporary_buffer_t *tb  = create_temporary_buffer(fc);
464         if (tb == NULL)
465         {
466             destroy_file_content(fc);
467             ar.close();
468             fd.close();
469             return STATUS_NO_MEM;
470         }
471 
472         // Read frames
473         skip = aparams.frames;
474         while (skip > 0)
475         {
476             // Determine how many data is available to read
477             size_t can_read     = (tb->nCapacity - tb->nSize)/tb->nFrameSize;
478             if (can_read <= 0)
479             {
480                 flush_temporary_buffer(tb);
481                 can_read            = (tb->nCapacity - tb->nSize)/tb->nFrameSize;
482             }
483 
484             // Calculate amount of samples to read
485             size_t to_read      = (skip > can_read) ? can_read : skip;
486 
487             ssize_t n           = ar.read_frames(reinterpret_cast<float *>(&tb->bData[tb->nSize]), to_read);
488             if (n < 0)
489             {
490                 destroy_temporary_buffer(tb);
491                 destroy_file_content(fc);
492                 ar.close();
493                 fd.close();
494                 return -n;
495             }
496 
497             // Update counters
498             tb->nSize          += n * tb->nFrameSize;
499             skip               -= n;
500         }
501 
502         // Flush last read data (if present)
503         flush_temporary_buffer(tb);
504 
505         // Destroy temporary buffer
506         if (tb != NULL)
507         {
508             destroy_temporary_buffer(tb);
509             tb = NULL;
510         }
511 
512         // Close chunk reader
513         res = ar.close();
514         if (res != STATUS_OK)
515         {
516             destroy_file_content(fc);
517             ar.close();
518             fd.close();
519             return res;
520         }
521 
522         // Close LSPC file
523         res = fd.close();
524         if (res != STATUS_OK)
525         {
526             destroy_file_content(fc);
527             fd.close();
528             return res;
529         }
530 
531         // Destroy previously used content and store new
532         if (pData != NULL)
533             destroy_file_content(pData);
534         pData               = fc;
535 
536         return STATUS_OK;
537     }
538 
load(const char * path,float max_duration)539     status_t AudioFile::load(const char *path, float max_duration)
540     {
541         if (path == NULL)
542             return STATUS_BAD_ARGUMENTS;
543 
544         LSPString spath;
545         if (!spath.set_utf8(path))
546             return STATUS_NO_MEM;
547 
548         return load(&spath, max_duration);
549     }
550 
load(const LSPString * path,float max_duration)551     status_t AudioFile::load(const LSPString *path, float max_duration)
552     {
553         if (path == NULL)
554             return STATUS_BAD_ARGUMENTS;
555 
556         status_t res = load_lspc(path, max_duration);
557         if (res != STATUS_OK)
558         {
559             #ifdef PLATFORM_WINDOWS
560 //                res = load_mfapi(path, max_duration);
561 //                if (res == STATUS_BAD_FORMAT)
562                     res = load_mmio(path, max_duration);
563             #else
564                 res = load_sndfile(path, max_duration);
565             #endif /* PLATFORM_WINDOWS */
566         }
567         return res;
568     }
569 
store_samples(const LSPString * path,size_t from,size_t max_count)570     status_t AudioFile::store_samples(const LSPString *path, size_t from, size_t max_count)
571     {
572         if (pData == NULL)
573             return STATUS_NO_DATA;
574 
575         #ifdef PLATFORM_WINDOWS
576             status_t res = save_mfapi(path, from, max_count);
577             if (res == STATUS_BAD_FORMAT)
578                 res = save_mmio(path, from, max_count);
579         #else
580             status_t res = save_sndfile(path, from, max_count);
581         #endif
582 
583         return res;
584     }
585 
load(const io::Path * path,float max_duration)586     status_t AudioFile::load(const io::Path *path, float max_duration)
587     {
588         if (path == NULL)
589             return STATUS_BAD_ARGUMENTS;
590         return load(path->as_string(), max_duration);
591     }
592 
store_samples(const io::Path * path,size_t from,size_t max_count)593     status_t AudioFile::store_samples(const io::Path *path, size_t from, size_t max_count) {
594         if (path == NULL)
595             return STATUS_BAD_ARGUMENTS;
596         return store_samples(path->as_string(), from, max_count);
597     }
598 
store_samples(const char * path,size_t from,size_t max_count)599     status_t AudioFile::store_samples(const char *path, size_t from, size_t max_count)
600     {
601         if (path == NULL)
602             return STATUS_BAD_ARGUMENTS;
603         LSPString spath;
604         if (!spath.set_utf8(path))
605             return STATUS_NO_MEM;
606         return store_samples(&spath, from, max_count);
607     }
608 
store_samples(const char * path,size_t max_count)609     status_t AudioFile::store_samples(const char *path, size_t max_count)
610     {
611         if (path == NULL)
612             return STATUS_BAD_ARGUMENTS;
613         LSPString spath;
614         if (!spath.set_utf8(path))
615             return STATUS_NO_MEM;
616         return store_samples(&spath, 0, max_count);
617     }
618 
store_samples(const LSPString * path,size_t max_count)619     status_t AudioFile::store_samples(const LSPString *path, size_t max_count)
620     {
621         return store_samples(path, 0, max_count);
622     }
623 
store_samples(const io::Path * path,size_t max_count)624     status_t AudioFile::store_samples(const io::Path *path, size_t max_count)
625     {
626         if (path == NULL)
627             return STATUS_BAD_ARGUMENTS;
628         return store_samples(path->as_string(), 0, max_count);
629     }
630 
store(const char * path,float max_duration)631     status_t AudioFile::store(const char *path, float max_duration)
632     {
633         if (path == NULL)
634             return STATUS_BAD_ARGUMENTS;
635 
636         // Calculate the file length (in samples) and call the previous method
637         size_t max_count = (max_duration < 0) ? pData->nSamples : max_duration * pData->nSampleRate;
638         LSPString spath;
639         if (!spath.set_utf8(path))
640             return STATUS_NO_MEM;
641 
642         return store_samples(&spath, 0, max_count);
643     }
644 
store(const LSPString * path,float max_duration)645     status_t AudioFile::store(const LSPString *path, float max_duration)
646     {
647         if (path == NULL)
648             return STATUS_BAD_ARGUMENTS;
649 
650         // Calculate the file length (in samples) and call the previous method
651         size_t max_count = (max_duration < 0) ? pData->nSamples : max_duration * pData->nSampleRate;
652         return store_samples(path, 0, max_count);
653     }
654 
store(const io::Path * path,float max_duration)655     status_t AudioFile::store(const io::Path *path, float max_duration)
656     {
657         if (path == NULL)
658             return STATUS_BAD_ARGUMENTS;
659 
660         // Calculate the file length (in samples) and call the previous method
661         size_t max_count = (max_duration < 0) ? pData->nSamples : max_duration * pData->nSampleRate;
662         return store_samples(path->as_string(), 0, max_count);
663     }
664 
reverse(ssize_t track_id)665     bool AudioFile::reverse(ssize_t track_id)
666     {
667         if (pData == NULL)
668             return false;
669 
670         if (track_id >= 0)
671         {
672             if (size_t(track_id) >= pData->nChannels)
673                 return false;
674             lsp_trace("reverse %p, %d", pData->vChannels[track_id], int(pData->nSamples));
675             dsp::reverse1(pData->vChannels[track_id], pData->nSamples);
676         }
677         else
678         {
679             size_t count = pData->nChannels;
680             if (count <= 0)
681                 return false;
682             for (size_t i=0; i<count; ++i)
683             {
684                 lsp_trace("reverse %p, %d", pData->vChannels[i], int(pData->nSamples));
685                 dsp::reverse1(pData->vChannels[i], pData->nSamples);
686             }
687         }
688 
689         return true;
690     }
691 
channels() const692     size_t AudioFile::channels() const
693     {
694         return (pData != NULL) ? pData->nChannels : 0;
695     }
696 
samples() const697     size_t AudioFile::samples() const
698     {
699         return (pData != NULL) ? pData->nSamples : 0;
700     }
701 
sample_rate() const702     size_t AudioFile::sample_rate() const
703     {
704         return (pData != NULL) ? pData->nSampleRate : 0;
705     }
706 
resample(size_t new_sample_rate)707     status_t AudioFile::resample(size_t new_sample_rate)
708     {
709         // Check that resampling is actually needed
710         if (new_sample_rate > pData->nSampleRate)
711         {
712             // Need to up-sample data
713             if ((new_sample_rate % pData->nSampleRate) == 0)
714                 return fast_upsample(new_sample_rate);
715             else
716                 return complex_upsample(new_sample_rate);
717         }
718         else if (new_sample_rate < pData->nSampleRate)
719         {
720             // Need to down-sample data
721             if ((pData->nSampleRate % new_sample_rate) == 0)
722                 return fast_downsample(new_sample_rate);
723             else
724                 return complex_downsample(new_sample_rate);
725         }
726 
727         // Return OK status
728         return STATUS_OK;
729     }
730 
fast_downsample(size_t new_sample_rate)731     status_t AudioFile::fast_downsample(size_t new_sample_rate)
732     {
733         size_t rkf          = pData->nSampleRate / new_sample_rate;
734         size_t new_samples  = pData->nSamples / rkf;
735 
736         // Prepare new data structure to store resampled data
737         file_content_t *fc  = create_file_content(pData->nChannels, new_samples);
738         if (fc == NULL)
739             return STATUS_NO_MEM;
740         fc->nSampleRate     = new_sample_rate;
741 
742         // Iterate each channel
743         for (size_t c=0; c<fc->nChannels; ++c)
744         {
745             const float *src    = pData->vChannels[c];
746             float *dst          = fc->vChannels[c];
747 
748             for (size_t i=0, p=0; i < pData->nSamples; i += rkf, p++)
749                 dst[p]              = src[i];
750         }
751 
752         // Destroy old data content
753         destroy_file_content(pData);
754 
755         // Store new file content
756         pData       = fc;
757 
758         return STATUS_OK;
759     }
760 
fast_upsample(size_t new_sample_rate)761     status_t AudioFile::fast_upsample(size_t new_sample_rate)
762     {
763         // Calculate parameters of transformation
764         ssize_t kf          = new_sample_rate / pData->nSampleRate;
765         float rkf           = 1.0f / kf;
766 
767         // Prepare kernel for resampling
768         ssize_t k_periods   = RESAMPLING_PERIODS; // * (kf >> 1);
769         ssize_t k_base      = k_periods * kf;
770         ssize_t k_center    = k_base + 1;
771         ssize_t k_len       = (k_center << 1) + 1;
772         ssize_t k_size      = ALIGN_SIZE(k_len + 1, 4); // Additional sample for time offset
773         float *k            = lsp_tmalloc(float, k_size);
774         if (k == NULL)
775             return STATUS_NO_MEM;
776 
777         // Prepare temporary buffer for resampling
778         size_t new_samples  = kf * pData->nSamples;
779         size_t b_len        = new_samples + k_size;
780         size_t b_size       = ALIGN_SIZE(b_len, 4);
781         float *b            = lsp_tmalloc(float, b_size);
782         if (b == NULL)
783         {
784             lsp_free(k);
785             return STATUS_NO_MEM;
786         }
787 
788         // Prepare new data structure to store resampled data
789         file_content_t *fc  = create_file_content(pData->nChannels, new_samples);
790         if (fc == NULL)
791         {
792             lsp_free(b);
793             lsp_free(k);
794             return STATUS_NO_MEM;
795         }
796         fc->nSampleRate     = new_sample_rate;
797 
798         // Generate Lanczos kernel
799         for (ssize_t j=0; j<k_size; ++j)
800         {
801             float t         = (j - k_center) * rkf;
802 
803             if ((t > -k_periods) && (t < k_periods))
804             {
805                 if (t != 0)
806                 {
807                     float t2    = M_PI * t;
808                     k[j]        = k_periods * sinf(t2) * sinf(t2 / k_periods) / (t2 * t2);
809                 }
810                 else
811                     k[j]        = 1.0f;
812             }
813             else
814                 k[j]        = 0.0f;
815         }
816 
817         // Output dump
818 //        printf("----------------------\n");
819 //        printf("j;t;k(j);\n");
820 //        for (ssize_t j=0; j<k_len; ++j)
821 //        {
822 //            float t         = (j - k_center) * rkf;
823 //            printf("%d;%f;%f;\n", int(j), t, k[j]);
824 //        }
825 //        printf("----------------------\n");
826 
827         // Iterate each channel
828         for (size_t c=0; c<fc->nChannels; ++c)
829         {
830             const float *src    = pData->vChannels[c];
831             dsp::fill_zero(b, b_size);  // Clear the temporary buffer
832 
833             // Perform convolutions
834             for (size_t i=0, p=0; i<pData->nSamples; i++, p += kf)
835                 dsp::fmadd_k3(&b[p], k, src[i], k_size);
836 
837             // Copy the data to the file content
838             dsp::copy(fc->vChannels[c], &b[k_center], fc->nSamples);
839         }
840 
841         // Delete  temporary buffers
842         destroy_file_content(pData);
843         lsp_free(b);
844         lsp_free(k);
845 
846         // Store new file content
847         pData       = fc;
848 
849         return STATUS_OK;
850     }
851 
complex_upsample(size_t new_sample_rate)852     status_t AudioFile::complex_upsample(size_t new_sample_rate)
853     {
854         // Calculate parameters of transformation
855         ssize_t gcd         = gcd_euclid(new_sample_rate, pData->nSampleRate);
856         ssize_t src_step    = pData->nSampleRate / gcd;
857         ssize_t dst_step    = new_sample_rate / gcd;
858         float kf            = float(dst_step) / float(src_step);
859         float rkf           = float(src_step) / float(dst_step);
860 
861         // Prepare kernel for resampling
862         ssize_t k_periods   = RESAMPLING_PERIODS; // Number of periods
863         ssize_t k_base      = k_periods * kf;
864         ssize_t k_center    = k_base + 1;
865         ssize_t k_len       = (k_center << 1) + 1; // Centered impulse response
866         ssize_t k_size      = ALIGN_SIZE(k_len + 1, 4); // Additional sample for time offset
867         float *k            = lsp_tmalloc(float, k_size);
868         if (k == NULL)
869             return STATUS_NO_MEM;
870 
871         // Prepare temporary buffer for resampling
872         size_t new_samples  = kf * pData->nSamples;
873         size_t b_len        = new_samples + k_size;
874         size_t b_size       = ALIGN_SIZE(b_len, 4);
875         float *b            = lsp_tmalloc(float, b_size);
876         if (b == NULL)
877         {
878             lsp_free(k);
879             return STATUS_NO_MEM;
880         }
881 
882         // Prepare new data structure to store resampled data
883         file_content_t *fc  = create_file_content(pData->nChannels, new_samples);
884         if (fc == NULL)
885         {
886             lsp_free(b);
887             lsp_free(k);
888             return STATUS_NO_MEM;
889         }
890         fc->nSampleRate     = new_sample_rate;
891 
892         // Iterate each channel
893         for (size_t c=0; c<fc->nChannels; ++c)
894         {
895             const float *src    = pData->vChannels[c];
896             dsp::fill_zero(b, b_size);  // Clear the temporary buffer
897 
898             for (ssize_t i=0; i<src_step; ++i)
899             {
900                 // calculate the offset between nearest samples
901                 ssize_t p       = kf * i;
902                 float dt        = i*kf - p;
903 
904                 // Generate Lanczos kernel
905                 for (ssize_t j=0; j<k_size; ++j)
906                 {
907                     float t         = (j - k_center - dt) * rkf;
908 
909                     if ((t > -k_periods) && (t < k_periods))
910                     {
911                         if (t != 0.0f)
912                         {
913                             float t2    = M_PI * t;
914                             k[j]        = k_periods * sinf(t2) * sinf(t2 / k_periods) / (t2 * t2);
915                         }
916                         else
917                             k[j]        = 1.0f;
918                     }
919                     else
920                         k[j]        = 0.0f;
921                 }
922 
923                 // Output dump
924 //                printf("----------------------\n");
925 //                printf("j;t;k(j);\n");
926 //                for (ssize_t j=0; j<k_len; ++j)
927 //                {
928 //                    float t         = (j - k_center - dt) * kt;
929 //                    printf("%d;%f;%f;\n", int(j), t, k[j]);
930 //                }
931 //                printf("----------------------\n");
932 
933                 // Perform convolutions
934                 for (size_t j=i; j<pData->nSamples; j += src_step)
935                 {
936                     dsp::fmadd_k3(&b[p], k, src[j], k_size);
937                     p   += dst_step;
938                 }
939             }
940 
941             // Copy the data to the file content
942             dsp::copy(fc->vChannels[c], &b[k_center], fc->nSamples);
943         }
944 
945         // Delete  temporary buffers
946         destroy_file_content(pData);
947         lsp_free(b);
948         lsp_free(k);
949 
950         // Store new file content
951         pData       = fc;
952 
953         return STATUS_OK;
954     }
955 
complex_downsample(size_t new_sample_rate)956     status_t AudioFile::complex_downsample(size_t new_sample_rate)
957     {
958         // Calculate parameters of transformation
959         ssize_t gcd         = gcd_euclid(new_sample_rate, pData->nSampleRate);
960         ssize_t src_step    = pData->nSampleRate / gcd;
961         ssize_t dst_step    = new_sample_rate / gcd;
962         float kf            = float(dst_step) / float(src_step);
963         float rkf           = float(src_step) / float(dst_step);
964 
965         // Prepare kernel for resampling
966         ssize_t k_base      = RESAMPLING_PERIODS;
967         ssize_t k_periods   = k_base * rkf; // Number of periods
968         ssize_t k_center    = k_base + 1;
969         ssize_t k_len       = (k_center << 1) + rkf + 1; // Centered impulse response
970         ssize_t k_size      = ALIGN_SIZE(k_len + 1, 4); // Additional sample for time offset
971         float *k            = lsp_tmalloc(float, k_size);
972         if (k == NULL)
973             return STATUS_NO_MEM;
974 
975         // Prepare temporary buffer for resampling
976         size_t new_samples  = kf * pData->nSamples;
977         size_t b_len        = new_samples + k_size;
978         size_t b_size       = ALIGN_SIZE(b_len, 4);
979         float *b            = lsp_tmalloc(float, b_size);
980         if (b == NULL)
981         {
982             lsp_free(k);
983             return STATUS_NO_MEM;
984         }
985 
986         // Prepare new data structure to store resampled data
987         file_content_t *fc  = create_file_content(pData->nChannels, new_samples);
988         if (fc == NULL)
989         {
990             lsp_free(b);
991             lsp_free(k);
992             return STATUS_NO_MEM;
993         }
994         fc->nSampleRate     = new_sample_rate;
995 
996         // Iterate each channel
997         for (size_t c=0; c<fc->nChannels; ++c)
998         {
999             const float *src    = pData->vChannels[c];
1000             dsp::fill_zero(b, b_size);  // Clear the temporary buffer
1001 
1002             for (ssize_t i=0; i<src_step; ++i)
1003             {
1004                 // calculate the offset between nearest samples
1005                 ssize_t p       = kf * i;
1006                 float dt        = i*kf - p; // Always positive, in range of [0..1]
1007 
1008                 // Generate Lanczos kernel
1009                 for (ssize_t j=0; j<k_size; ++j)
1010                 {
1011                     float t         = (j - k_center - dt) * rkf;
1012 
1013                     if ((t > -k_periods) && (t < k_periods))
1014                     {
1015                         if (t != 0.0f)
1016                         {
1017                             float t2    = M_PI * t;
1018                             k[j]        = k_periods * sinf(t2) * sinf(t2 / k_periods) / (t2 * t2);
1019                         }
1020                         else
1021                             k[j]        = 1.0f;
1022                     }
1023                     else
1024                         k[j]        = 0.0f;
1025                 }
1026 
1027                 // Output dump
1028 //                printf("----------------------\n");
1029 //                printf("j;t;k(j);\n");
1030 //                for (ssize_t j=0; j<k_size; ++j)
1031 //                {
1032 //                    float t         = (j - k_center - dt) * kt;
1033 //                    printf("%d;%f;%f;\n", int(j), t, k[j]);
1034 //                }
1035 //                printf("----------------------\n");
1036 
1037                 // Perform convolutions
1038                 for (size_t j=i; j<pData->nSamples; j += src_step)
1039                 {
1040                     dsp::fmadd_k3(&b[p], k, src[j], k_size);
1041                     p   += dst_step;
1042                 }
1043             }
1044 
1045             // Copy the data to the file content
1046             dsp::copy(fc->vChannels[c], &b[k_center], fc->nSamples);
1047         }
1048 
1049         // Delete  temporary buffers
1050         destroy_file_content(pData);
1051         lsp_free(b);
1052         lsp_free(k);
1053 
1054         // Store new file content
1055         pData       = fc;
1056 
1057         return STATUS_OK;
1058     }
1059 
channel(size_t track)1060     float *AudioFile::channel(size_t track)
1061     {
1062         if (pData == NULL)
1063             return NULL;
1064         if (track >= pData->nChannels)
1065             return NULL;
1066         return pData->vChannels[track];
1067     }
1068 
convert_to_sample(Sample * dst)1069     status_t AudioFile::convert_to_sample(Sample *dst)
1070     {
1071         if (dst == NULL)
1072             return STATUS_BAD_ARGUMENTS;
1073         if (pData == NULL)
1074             return STATUS_BAD_STATE;
1075 
1076         // Create and initialize temorary sample instance
1077         Sample tmp;
1078         if (!tmp.init(pData->nChannels, pData->nSamples, pData->nSamples))
1079             return STATUS_NO_MEM;
1080 
1081         // Copy file contents to sample
1082         for (size_t i=0; i<pData->nChannels; ++i)
1083             dsp::copy(tmp.getBuffer(i), pData->vChannels[i], pData->nSamples);
1084 
1085         tmp.swap(dst);
1086         tmp.destroy();
1087         return STATUS_OK;
1088     }
1089 
1090 #ifdef PLATFORM_WINDOWS
1091     typedef struct stream_info_t
1092     {
1093         UINT64  frames;     // Number of frames
1094         UINT32  srate;      // Sample rate
1095         UINT32  channels;   // Number of channels
1096         DWORD   stream;     // Identifier of the stream
1097     } stream_info_t;
1098 
create_riff_file(const WCHAR * path,WAVEFORMATEX * pwfxDest,HMMIO * phmmioOut,MMCKINFO * pckOut,MMCKINFO * pckOutRIFF)1099     status_t create_riff_file(
1100             const WCHAR *path,
1101             WAVEFORMATEX *pwfxDest,
1102             HMMIO *phmmioOut,
1103             MMCKINFO *pckOut,
1104             MMCKINFO *pckOutRIFF
1105         )
1106     {
1107         int code;
1108         size_t written;
1109         MMCKINFO ckOut1;
1110         DWORD dwFactChunk = DWORD(-1);
1111 
1112         HMMIO fd = ::mmioOpenW(const_cast<WCHAR *>(path), NULL, MMIO_ALLOCBUF | MMIO_READWRITE | MMIO_CREATE);
1113         if (fd == NULL)
1114             return STATUS_IO_ERROR;
1115 
1116         // Create the output file RIFF chunk of form type 'WAVE'
1117         pckOutRIFF->fccType    = mmioFOURCC('W', 'A', 'V', 'E');
1118         pckOutRIFF->cksize     = 0;
1119         if ((code = ::mmioCreateChunk(fd, pckOutRIFF, MMIO_CREATERIFF)) != 0)
1120         {
1121             ::mmioClose(fd, 0);
1122             return STATUS_IO_ERROR;
1123         }
1124 
1125         // Now create the 'fmt ' chunk. Since we know the size of this chunk,
1126         pckOut->ckid    = mmioFOURCC('f', 'm', 't', ' ');
1127         pckOut->cksize  = sizeof(PCMWAVEFORMAT);   // we know the size of this ck.
1128         if ((code = mmioCreateChunk(fd, pckOut, 0)) != 0)
1129         {
1130             ::mmioClose(fd, 0);
1131             return STATUS_IO_ERROR;
1132         }
1133 
1134         // Write the PCMWAVEFORMAT structure to the 'fmt ' chunk
1135         written = ::mmioWrite(fd, reinterpret_cast<HPSTR>(pwfxDest), sizeof(PCMWAVEFORMAT));
1136         if (written != sizeof(PCMWAVEFORMAT))
1137         {
1138             ::mmioClose(fd, 0);
1139             return STATUS_IO_ERROR;
1140         }
1141 
1142         // Ascend out of the 'fmt ' chunk, back into the 'RIFF' chunk.
1143         if ((code = ::mmioAscend(fd, pckOut, 0)) != 0)
1144         {
1145             ::mmioClose(fd, 0);
1146             return STATUS_IO_ERROR;
1147         }
1148 
1149         // Now create the fact chunk, not required for PCM but nice to have.
1150         ckOut1.ckid     = mmioFOURCC('f', 'a', 'c', 't');
1151         ckOut1.cksize   = 0;
1152         if ((code = ::mmioCreateChunk(fd, &ckOut1, 0)) != 0)
1153         {
1154             ::mmioClose(fd, 0);
1155             return STATUS_IO_ERROR;
1156         }
1157 
1158         written = ::mmioWrite(fd, reinterpret_cast<HPSTR>(&dwFactChunk), sizeof(dwFactChunk));
1159         if (written != sizeof(dwFactChunk))
1160         {
1161             ::mmioClose(fd, 0);
1162             return STATUS_IO_ERROR;
1163         }
1164 
1165         // Now ascend out of the fact chunk...
1166         if ((code = ::mmioAscend(fd, &ckOut1, 0)) != 0)
1167         {
1168             ::mmioClose(fd, 0);
1169             return STATUS_IO_ERROR;
1170         }
1171 
1172         // Save pointer and return success status
1173         *phmmioOut = fd;
1174         return STATUS_OK;
1175     }
1176 
open_riff_file(const WCHAR * path,HMMIO * phmmioIn,WAVEFORMATEX ** ppwfxInfo,MMCKINFO * pckInRIFF)1177     status_t open_riff_file(
1178             const WCHAR *path,
1179             HMMIO *phmmioIn,
1180             WAVEFORMATEX **ppwfxInfo,
1181             MMCKINFO *pckInRIFF
1182         )
1183     {
1184         HMMIO           hmmioIn;
1185         MMCKINFO        ckIn;
1186         PCMWAVEFORMAT   pcmWaveFormat;
1187         int             error;
1188 
1189         if ((hmmioIn = ::mmioOpenW(const_cast<WCHAR *>(path), NULL, MMIO_ALLOCBUF | MMIO_READ)) == NULL)
1190             return STATUS_PERMISSION_DENIED;
1191 
1192         if ((error = int(::mmioDescend(hmmioIn, pckInRIFF, NULL, 0))) != 0)
1193         {
1194             ::mmioClose(hmmioIn, 0);
1195             return STATUS_BAD_FORMAT;
1196         }
1197 
1198         if ((pckInRIFF->ckid != FOURCC_RIFF) || (pckInRIFF->fccType != mmioFOURCC('W', 'A', 'V', 'E')))
1199         {
1200             ::mmioClose(hmmioIn, 0);
1201             return STATUS_BAD_FORMAT;
1202         }
1203 
1204         ckIn.ckid = mmioFOURCC('f', 'm', 't', ' ');
1205         if ((error = int(::mmioDescend(hmmioIn, &ckIn, pckInRIFF, MMIO_FINDCHUNK))) != 0)
1206         {
1207             ::mmioClose(hmmioIn, 0);
1208             return STATUS_BAD_FORMAT;
1209         }
1210 
1211         // Expect the 'fmt' chunk to be at least as large as sizeof(PCMWAVEFORMAT)
1212         if (ckIn.cksize < sizeof(PCMWAVEFORMAT))
1213         {
1214             ::mmioClose(hmmioIn, 0);
1215             return STATUS_BAD_FORMAT;
1216         }
1217 
1218         // Read the 'fmt ' chunk
1219         size_t bytes = ::mmioRead(hmmioIn, (HPSTR) &pcmWaveFormat, sizeof(PCMWAVEFORMAT));
1220         if (bytes != sizeof(PCMWAVEFORMAT))
1221         {
1222             ::mmioClose(hmmioIn, 0);
1223             return STATUS_BAD_FORMAT;
1224         }
1225 
1226         // Estimate number of bytes to allocate for the format descriptor
1227         WAVEFORMATEX *wfex = NULL;
1228 
1229         if (LE_TO_CPU(pcmWaveFormat.wf.wFormatTag) != WAVE_FORMAT_PCM)
1230         {
1231             WORD cbSize;
1232             size_t alloc = sizeof(WAVEFORMATEX);
1233 
1234             // Read in length of extra bytes.
1235             bytes = ::mmioRead(hmmioIn, reinterpret_cast<HPSTR>(&cbSize), sizeof(WORD));
1236             if (bytes != sizeof(WORD))
1237             {
1238                 ::mmioClose(hmmioIn, 0);
1239                 return STATUS_BAD_FORMAT;
1240             }
1241             alloc += LE_TO_CPU(cbSize);
1242 
1243             // Allocate memory
1244             wfex = reinterpret_cast<WAVEFORMATEX *>(::malloc(alloc));
1245             if (wfex == NULL)
1246             {
1247                 ::mmioClose(hmmioIn, 0);
1248                 return STATUS_BAD_FORMAT;
1249             }
1250 
1251             // Return back to 'fmt ' chunk
1252             if ((error = int(::mmioDescend(hmmioIn, &ckIn, pckInRIFF, MMIO_FINDCHUNK))) != 0)
1253             {
1254                 ::mmioClose(hmmioIn, 0);
1255                 return STATUS_BAD_FORMAT;
1256             }
1257 
1258             // Read the whole structure again
1259             bytes = ::mmioRead(hmmioIn, reinterpret_cast<HPSTR>(wfex), alloc);
1260             if (bytes != alloc)
1261             {
1262                 ::mmioClose(hmmioIn, 0);
1263                 return STATUS_BAD_FORMAT;
1264             }
1265         }
1266         else
1267         {
1268             // Allocate memory
1269             wfex = reinterpret_cast<WAVEFORMATEX *>(::malloc(sizeof(WAVEFORMATEX)));
1270             if (wfex == NULL)
1271             {
1272                 ::mmioClose(hmmioIn, 0);
1273                 return STATUS_BAD_FORMAT;
1274             }
1275             ::memcpy(wfex, &pcmWaveFormat, sizeof(PCMWAVEFORMAT));
1276             wfex->cbSize = 0;
1277         }
1278 
1279         /* Ascend the input file out of the 'fmt ' chunk. */
1280         if ((error = ::mmioAscend(hmmioIn, &ckIn, 0)) != 0)
1281         {
1282             ::mmioClose(hmmioIn, 0);
1283             return STATUS_BAD_FORMAT;
1284         }
1285 
1286         // Return success result
1287         *phmmioIn   = hmmioIn;
1288         *ppwfxInfo  = wfex;
1289 
1290         return STATUS_OK;
1291     }
1292 
complete_riff_file(HMMIO * phmmioOut,MMCKINFO * pckOut,MMCKINFO * pckOutRIFF,MMIOINFO * pmmioinfoOut,size_t samples)1293     status_t complete_riff_file(
1294             HMMIO *phmmioOut,
1295             MMCKINFO *pckOut,
1296             MMCKINFO *pckOutRIFF,
1297             MMIOINFO *pmmioinfoOut,
1298             size_t samples
1299         )
1300     {
1301         int code;
1302 
1303         // Ascend the output file out of the 'data' chunk
1304         // this will cause the chunk size of the 'data' chunk to be written.
1305         if ((code = ::mmioAscend(*phmmioOut, pckOut, 0)) != 0)
1306         {
1307             ::mmioClose(*phmmioOut, 0);
1308             return STATUS_IO_ERROR;
1309         }
1310 
1311         // Do this here instead...
1312         if ((code = ::mmioAscend(*phmmioOut, pckOutRIFF, 0)) != 0)
1313         {
1314             ::mmioClose(*phmmioOut, 0);
1315             return STATUS_IO_ERROR;
1316         }
1317 
1318         // Seek to the beginning of the file
1319         code = ::mmioSeek(*phmmioOut, 0, SEEK_SET);
1320         if ((code = int(::mmioDescend(*phmmioOut, pckOutRIFF, NULL, 0))) != 0)
1321         {
1322             ::mmioClose(*phmmioOut, 0);
1323             return STATUS_IO_ERROR;
1324         }
1325 
1326         // Update fact
1327         pckOut->ckid = mmioFOURCC('f', 'a', 'c', 't');
1328         if ((code = ::mmioDescend(*phmmioOut, pckOut, pckOutRIFF, MMIO_FINDCHUNK)) == 0)
1329         {
1330             DWORD cSamples = CPU_TO_LE(DWORD(samples));
1331             ::mmioWrite(*phmmioOut, reinterpret_cast<HPSTR>(&cSamples), sizeof(DWORD));
1332             ::mmioAscend(*phmmioOut, pckOut, 0);
1333         }
1334 
1335         if ((code = ::mmioAscend(*phmmioOut, pckOutRIFF, 0)) != 0)
1336         {
1337             ::mmioClose(*phmmioOut, 0);
1338             return STATUS_IO_ERROR;
1339         }
1340 
1341         // Close MMIO and return
1342         ::mmioClose(*phmmioOut, 0);
1343         return STATUS_OK;
1344     }
1345 
mfapi_copy_media_type(IMFMediaType * src,stream_info_t * cfg)1346     static IMFMediaType *mfapi_copy_media_type(IMFMediaType *src, stream_info_t *cfg)
1347     {
1348         // Obtain media type
1349         HRESULT hr = src->GetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, &cfg->srate);
1350         if (SUCCEEDED(hr))
1351             hr = src->GetUINT32(MF_MT_AUDIO_NUM_CHANNELS, &cfg->channels);
1352         if (!SUCCEEDED(hr))
1353             return NULL;
1354 
1355         // Create target media type
1356         IMFMediaType *dst = NULL;
1357         hr = ::MFCreateMediaType(&dst);
1358         if (!SUCCEEDED(hr))
1359             return NULL;
1360 
1361         // Configure and set media type for reader
1362         hr = dst->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio);
1363         if (SUCCEEDED(hr))
1364             hr = dst->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_Float);
1365         if (SUCCEEDED(hr))
1366             hr = dst->SetUINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, sizeof(float) * 8);
1367         if (SUCCEEDED(hr))
1368             hr = dst->SetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, cfg->srate);
1369         if (SUCCEEDED(hr))
1370             hr = dst->SetUINT32(MF_MT_FRAME_SIZE, cfg->channels);
1371 
1372         // Check the final result
1373         if (SUCCEEDED(hr))
1374             return dst;
1375 
1376         // Return error
1377         dst->Release();
1378         return NULL;
1379     }
1380 
open_mfapi_reader(const WCHAR * path,stream_info_t * info,IMFSourceReader ** reader)1381     status_t open_mfapi_reader(const WCHAR *path, stream_info_t *info, IMFSourceReader **reader)
1382     {
1383         // Create source reader
1384         IMFSourceReader *pReader = NULL;
1385         HRESULT hr = ::MFCreateSourceReaderFromURL(path, NULL, &pReader);
1386         if ((!SUCCEEDED(hr)) || (pReader == NULL))
1387             return STATUS_UNKNOWN_ERR;
1388 
1389         // Obtain the length of stream in nanoseconds
1390         INT64 nsDuration;
1391         PROPVARIANT var;
1392         hr = pReader->GetPresentationAttribute(MF_SOURCE_READER_MEDIASOURCE,
1393             MF_PD_DURATION, &var);
1394         if (SUCCEEDED(hr))
1395         {
1396             hr = ::PropVariantToInt64(var, &nsDuration);
1397             ::PropVariantClear(&var);
1398         }
1399 
1400         if (!SUCCEEDED(hr))
1401         {
1402             pReader->Release();
1403             return STATUS_UNKNOWN_ERR;
1404         }
1405 
1406         // Find the audio stream
1407         IMFMediaType *pNativeType = NULL;
1408         DWORD dwStreamIndex = 0;
1409 
1410         while (true)
1411         {
1412             hr = pReader->GetNativeMediaType(dwStreamIndex, 0, &pNativeType);
1413             if (hr == MF_E_NO_MORE_TYPES)
1414             {
1415                 pReader->Release();
1416                 return STATUS_BAD_FORMAT;
1417             }
1418             else if (SUCCEEDED(hr))
1419             {
1420                 GUID guid;
1421                 hr = pNativeType->GetGUID(MF_MT_MAJOR_TYPE, &guid);
1422                 if ((SUCCEEDED(hr)) && (::IsEqualGUID(guid, MFMediaType_Audio)))
1423                     break;
1424                 pNativeType->Release();
1425             }
1426             ++dwStreamIndex;
1427         }
1428 
1429         // Create media type for decoding
1430         IMFMediaType *pMediaType = mfapi_copy_media_type(pNativeType, info);
1431         pNativeType->Release();
1432         if (pMediaType == NULL)
1433         {
1434             pReader->Release();
1435             return STATUS_UNKNOWN_ERR;
1436         }
1437 
1438         // Set current media type for decoding
1439         hr = pReader->SetCurrentMediaType(dwStreamIndex, NULL, pMediaType);
1440         pMediaType->Release();
1441 
1442         if (!SUCCEEDED(hr))
1443         {
1444             pReader->Release();
1445             return STATUS_UNKNOWN_ERR;
1446         }
1447 
1448         // Return success status
1449         info->frames    = (nsDuration * info->srate) / 10000000;
1450         info->stream    = dwStreamIndex;
1451         *reader         = pReader;
1452         return STATUS_OK;
1453     }
1454 
load_mfapi(const LSPString * path,float max_duration)1455     status_t AudioFile::load_mfapi(const LSPString *path, float max_duration)
1456     {
1457         stream_info_t sf_info;
1458         IMFSourceReader *pReader = NULL;
1459 
1460         // Open sound file
1461         lsp_trace("loading file: %s\n", path->get_native());
1462         status_t res = open_mfapi_reader(path->get_utf16(), &sf_info, &pReader);
1463         if (res != STATUS_OK)
1464             return res;
1465 
1466         // Read sample file
1467         ssize_t max_samples     = (max_duration >= 0.0f) ? seconds_to_samples(sf_info.srate, max_duration) : -1;
1468         lsp_trace("file parameters: frames=%d, channels=%d, sample_rate=%d max_duration=%.3f\n, max_samples=%d",
1469             int(sf_info.frames), int(sf_info.channels), int(sf_info.srate), max_duration, int(max_samples));
1470 
1471         // Patch sf_info
1472         if ((max_samples >= 0) && (sf_info.frames > UINT64(max_samples)))
1473             sf_info.frames  = max_samples;
1474 
1475         // Create file content
1476         file_content_t *fc      = create_file_content(sf_info.channels, sf_info.frames);
1477         if (fc == NULL)
1478         {
1479             pReader->Release();
1480             return STATUS_NO_MEM;
1481         }
1482         fc->nSampleRate         = sf_info.srate;
1483 
1484         // Allocate temporary buffer
1485         temporary_buffer_t *tb  = create_temporary_buffer(fc);
1486         if (tb == NULL)
1487         {
1488             destroy_file_content(fc);
1489             pReader->Release();
1490             return STATUS_NO_MEM;
1491         }
1492 
1493         size_t count = sf_info.frames;
1494         while (count > 0)
1495         {
1496             // Read sample
1497             IMFSample *pSample = NULL;
1498             DWORD streamIndex, flags;
1499             LONGLONG llTimeStamp;
1500 
1501             HRESULT hr = pReader->ReadSample(
1502                 sf_info.stream,                 // Stream index.
1503                 0,                              // Flags.
1504                 &streamIndex,                   // Receives the actual stream index.
1505                 &flags,                         // Receives status flags.
1506                 &llTimeStamp,                   // Receives the time stamp.
1507                 &pSample                        // Receives the sample or NULL.
1508                 );
1509 
1510             if (!SUCCEEDED(hr))
1511             {
1512                 destroy_temporary_buffer(tb);
1513                 destroy_file_content(fc);
1514                 pReader->Release();
1515                 return STATUS_CORRUPTED_FILE;
1516             }
1517 
1518             // Obtain number of buffers
1519             DWORD cBuffers = 0;
1520             hr = pSample->GetBufferCount(&cBuffers);
1521             if (!SUCCEEDED(hr))
1522             {
1523                 destroy_temporary_buffer(tb);
1524                 destroy_file_content(fc);
1525                 pSample->Release();
1526                 pReader->Release();
1527                 return STATUS_CORRUPTED_FILE;
1528             }
1529 
1530             // Iterate each buffer
1531             for (DWORD i = 0; (i < cBuffers) && (count > 0); i++)
1532             {
1533                 IMFMediaBuffer *pBuffer = NULL;
1534                 hr = pSample->GetBufferByIndex(i, &pBuffer);
1535                 if (!SUCCEEDED(hr))
1536                 {
1537                     destroy_temporary_buffer(tb);
1538                     destroy_file_content(fc);
1539                     pSample->Release();
1540                     pReader->Release();
1541                     return STATUS_CORRUPTED_FILE;
1542                 }
1543 
1544                 // Use buffer
1545                 BYTE *pData = NULL;
1546                 DWORD nBufLength = 0;
1547                 hr = pBuffer->Lock(&pData, NULL, &nBufLength);
1548                 if (!SUCCEEDED(hr))
1549                 {
1550                     destroy_temporary_buffer(tb);
1551                     destroy_file_content(fc);
1552                     pSample->Release();
1553                     pReader->Release();
1554                     return STATUS_CORRUPTED_FILE;
1555                 }
1556 
1557                 while ((count > 0) && (nBufLength > 0))
1558                 {
1559                     // Determine how many data is available to read
1560                     size_t can_read     = tb->nCapacity - tb->nSize;
1561                     if (can_read <= 0)
1562                     {
1563                         flush_temporary_buffer(tb);
1564                         can_read            = tb->nCapacity - tb->nSize;
1565                     }
1566                     if (can_read > nBufLength)
1567                         can_read        = nBufLength;
1568                     ::memcpy(&tb->bData[tb->nSize], pData, can_read);
1569                     pData      += can_read;
1570                     tb->nSize  += can_read;
1571                     nBufLength -= can_read;
1572                 }
1573 
1574                 // Release buffer
1575                 pBuffer->Unlock();
1576                 pBuffer->Release();
1577             }
1578 
1579             // Release sample
1580             pSample->Release();
1581         }
1582 
1583         // Flush last read data (if present)
1584         flush_temporary_buffer(tb);
1585 
1586         // Free allocated resources
1587         destroy_temporary_buffer(tb);
1588         pReader->Release();
1589 
1590         // Destroy previously used content and store new
1591         if (pData != NULL)
1592             destroy_file_content(pData);
1593         pData               = fc;
1594 
1595         return STATUS_OK;
1596     }
1597 
1598 
mfapi_create_sample(void * data,size_t bytes)1599     static IMFSample *mfapi_create_sample(void *data, size_t bytes)
1600     {
1601         // Create media buffer
1602         IMFMediaBuffer *pBuffer = NULL;
1603         HRESULT hr = ::MFCreateMemoryBuffer(bytes, &pBuffer);
1604         if (!SUCCEEDED(hr))
1605             return NULL;
1606 
1607         // Lock the buffer and copy the video frame to the buffer.
1608         BYTE *pData = NULL;
1609         if (SUCCEEDED(hr))
1610             hr = pBuffer->Lock(&pData, NULL, NULL);
1611         if (SUCCEEDED(hr))
1612         {
1613             ::memcpy(pData, data, bytes);
1614             hr = pBuffer->Unlock();
1615         }
1616         if (SUCCEEDED(hr))
1617             hr = pBuffer->SetCurrentLength(bytes);
1618 
1619         if (!SUCCEEDED(hr))
1620         {
1621             pBuffer->Release();
1622             return NULL;
1623         }
1624 
1625         // Create sample
1626         IMFSample *pSample = NULL;
1627         hr = ::MFCreateSample(&pSample);
1628         if (!SUCCEEDED(hr))
1629         {
1630             pBuffer->Release();
1631             return NULL;
1632         }
1633 
1634         // Bind buffer to sample and set sample parameters
1635         hr = pSample->AddBuffer(pBuffer);
1636         pBuffer->Release();
1637         if (!SUCCEEDED(hr))
1638         {
1639             pSample->Release();
1640             return NULL;
1641         }
1642 
1643         return pSample;
1644     }
1645 
save_mfapi(const LSPString * path,size_t from,size_t max_count)1646     status_t AudioFile::save_mfapi(const LSPString *path, size_t from, size_t max_count)
1647     {
1648         // Create SinkWriter
1649         HRESULT hr;
1650         IMFSinkWriter *pSinkWriter = NULL;
1651         const WCHAR *wpath = path->get_utf16();
1652 
1653         // Create attributes
1654         IMFAttributes *pAttributes = NULL;
1655         hr = ::MFCreateAttributes(&pAttributes, 16);
1656         if (!SUCCEEDED(hr))
1657             return STATUS_UNKNOWN_ERR;
1658 
1659         if (SUCCEEDED(hr))
1660             hr = pAttributes->SetGUID(MF_TRANSCODE_CONTAINERTYPE, MFTranscodeContainerType_WAVE);
1661         if (!SUCCEEDED(hr))
1662         {
1663             pAttributes->Release();
1664             return STATUS_UNKNOWN_ERR;
1665         }
1666 
1667         // Create sink writer
1668         hr = ::MFCreateSinkWriterFromURL(wpath, NULL, pAttributes, &pSinkWriter);
1669         pAttributes->Release();
1670         if (!SUCCEEDED(hr))
1671             return STATUS_BAD_FORMAT;
1672 
1673         // Initialize media type
1674         IMFMediaType    *pMediaType = NULL;
1675         hr = ::MFCreateMediaType(&pMediaType);
1676         if (SUCCEEDED(hr))
1677             hr = pMediaType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio);
1678         if (SUCCEEDED(hr))
1679             hr = pMediaType->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_Float);
1680         if (SUCCEEDED(hr))
1681             hr = pMediaType->SetUINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, sizeof(float) * 8);
1682         if (SUCCEEDED(hr))
1683             hr = pMediaType->SetUINT32(MF_MT_AUDIO_NUM_CHANNELS, pData->nChannels);
1684         if (SUCCEEDED(hr))
1685             hr = pMediaType->SetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, pData->nSampleRate);
1686         if (SUCCEEDED(hr))
1687             hr = pMediaType->SetUINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, pData->nChannels * sizeof(float) * pData->nSampleRate);
1688 
1689         //        hr = mt_aud_speech_in->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio);
1690         //        hr = mt_aud_speech_in->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_PCM);
1691         //        hr = mt_aud_speech_in->SetUINT32(MF_MT_AUDIO_NUM_CHANNELS, 2);
1692         //        hr = mt_aud_speech_in->SetUINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 16);
1693         //        hr = mt_aud_speech_in->SetUINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, 4);
1694         //        hr = mt_aud_speech_in->SetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 44100);
1695         //        hr = mt_aud_speech_in->SetUINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 44100*2*2);
1696 
1697         // Initialize output stream and input data format
1698         DWORD           streamIndex;
1699         if (SUCCEEDED(hr))
1700             hr = pSinkWriter->AddStream(pMediaType, &streamIndex);
1701         if (SUCCEEDED(hr))
1702             hr = pSinkWriter->SetInputMediaType(streamIndex, pMediaType, NULL);
1703         if (pMediaType != NULL)
1704             pMediaType->Release();
1705 
1706         // Start writing
1707         if (SUCCEEDED(hr))
1708             hr = pSinkWriter->BeginWriting();
1709 
1710         if (!SUCCEEDED(hr))
1711         {
1712             pSinkWriter->Release();
1713             return STATUS_BAD_FORMAT;
1714         }
1715 
1716         // Allocate temporary buffer
1717         temporary_buffer_t *tb  = create_temporary_buffer(pData, from);
1718         if (tb == NULL)
1719         {
1720             pSinkWriter->Release();
1721             return STATUS_NO_MEM;
1722         }
1723 
1724         wsize_t frame_id = 0;
1725         while ((max_count > 0) || (tb->nSize > 0))
1726         {
1727             // Fill buffer
1728             max_count   -=  fill_temporary_buffer(tb, max_count);
1729 
1730             // Flush buffer
1731             if (tb->nSize <= 0)
1732                 continue;
1733 
1734             // Write buffer to file
1735             size_t offset = 0;
1736             size_t frames = tb->nSize / tb->nFrameSize;
1737             while (offset < tb->nSize)
1738             {
1739                 // Create audio sample for writing
1740                 IMFSample *sample = mfapi_create_sample(&tb->bData[offset], frames * tb->nFrameSize);
1741                 if (sample == NULL)
1742                 {
1743                     pSinkWriter->Release();
1744                     destroy_temporary_buffer(tb);
1745                     return STATUS_UNKNOWN_ERR;
1746                 }
1747 
1748                 // Update sample parameters
1749                 hr = sample->SetSampleTime((frame_id * 100000000)/pData->nSampleRate);
1750                 if (SUCCEEDED(hr))
1751                     hr = sample->SetSampleDuration((frames * 100000000)/pData->nSampleRate);
1752                 if (SUCCEEDED(hr))
1753                     hr = pSinkWriter->WriteSample(streamIndex, sample);
1754                 sample->Release();
1755 
1756                 // Send the sample to the Sink Writer.
1757                 if (!SUCCEEDED(hr))
1758                 {
1759                     pSinkWriter->Release();
1760                     destroy_temporary_buffer(tb);
1761                     return STATUS_UNKNOWN_ERR;
1762                 }
1763 
1764                 // Update offsets
1765                 offset     += frames * tb->nFrameSize;
1766                 frames     -= frames;
1767                 frame_id   += frames;
1768             }
1769 
1770             // Update buffer contents
1771             frames  = tb->nSize - offset;
1772             if (frames > 0)
1773                 ::memmove(tb->bData, &tb->bData[offset], frames);
1774             tb->nSize   = frames;
1775         }
1776 
1777         // Free allocated resources
1778         hr = pSinkWriter->Release();
1779         destroy_temporary_buffer(tb);
1780 
1781         return (SUCCEEDED(hr)) ? STATUS_OK : STATUS_UNKNOWN_ERR;
1782     }
1783 
save_mmio(const LSPString * path,size_t from,size_t max_count)1784     status_t AudioFile::save_mmio(const LSPString *path, size_t from, size_t max_count)
1785     {
1786         WAVEFORMATEX    fmt;
1787         HMMIO           hmmioOut;
1788         MMCKINFO        ckOut;
1789         MMCKINFO        ckOutRIFF;
1790         MMIOINFO        mmioinfoOut;
1791         int             code;
1792 
1793         // Initialize format descriptor
1794         fmt.wFormatTag      = WAVE_FORMAT_IEEE_FLOAT;
1795         fmt.nChannels       = pData->nChannels;
1796         fmt.nSamplesPerSec  = pData->nSampleRate;
1797         fmt.nAvgBytesPerSec = pData->nChannels * pData->nSampleRate * sizeof(float);
1798         fmt.nBlockAlign     = pData->nChannels * sizeof(float);
1799         fmt.wBitsPerSample  = sizeof(float) * 8;
1800         fmt.cbSize          = 0;
1801 
1802         fmt.wFormatTag      = CPU_TO_LE(fmt.wFormatTag);
1803         fmt.nChannels       = CPU_TO_LE(fmt.nChannels);
1804         fmt.nSamplesPerSec  = CPU_TO_LE(fmt.nSamplesPerSec);
1805         fmt.nAvgBytesPerSec = CPU_TO_LE(fmt.nAvgBytesPerSec);
1806         fmt.nBlockAlign     = CPU_TO_LE(fmt.nBlockAlign);
1807         fmt.wBitsPerSample  = CPU_TO_LE(fmt.wBitsPerSample);
1808         fmt.cbSize          = CPU_TO_LE(fmt.cbSize);
1809 
1810         // Create RIFF file
1811         status_t res    = create_riff_file(path->get_utf16(), &fmt, &hmmioOut, &ckOut, &ckOutRIFF);
1812         if (res != STATUS_OK)
1813             return res;
1814 
1815         // Create the 'data' chunk that holds the waveform samples.
1816         ckOut.ckid          = mmioFOURCC('d', 'a', 't', 'a');
1817         ckOut.cksize        = 0;
1818         code    = ::mmioCreateChunk(hmmioOut, &ckOut, 0);
1819         if (code == 0)
1820             code    = ::mmioGetInfo(hmmioOut, &mmioinfoOut, 0);
1821         if (code != 0)
1822         {
1823             ::mmioClose(hmmioOut, 0);
1824             return STATUS_IO_ERROR;
1825         }
1826 
1827         // Allocate temporary buffer
1828         temporary_buffer_t *tb  = create_temporary_buffer(pData, from);
1829         if (tb == NULL)
1830         {
1831             ::mmioClose(hmmioOut, 0);
1832             return STATUS_NO_MEM;
1833         }
1834 
1835         // Write file contents
1836         size_t samples = 0;
1837 
1838         while ((max_count > 0) || (tb->nSize > 0))
1839         {
1840             // Fill buffer
1841             size_t frames   = fill_temporary_buffer(tb, max_count);
1842             max_count      -= frames;
1843             if (tb->nSize <= 0)
1844                 continue;
1845 
1846             // Data is little-endian
1847             __IF_BE( byte_swap(reinterpret_cast<uint32_t *>(tb->bData), tb->nSize/sizeof(float)); )
1848 
1849             // Write temporary buffer
1850             size_t offset = 0;
1851             while (offset < tb->nSize)
1852             {
1853                 // Write buffer to file
1854                 size_t to_write     = reinterpret_cast<uint8_t *>(mmioinfoOut.pchEndWrite)
1855                                     - reinterpret_cast<uint8_t *>(mmioinfoOut.pchNext);
1856                 if (to_write <= 0) // We need to flush output buffer ?
1857                 {
1858                     mmioinfoOut.dwFlags |= MMIO_DIRTY;
1859                     code    = ::mmioAdvance(hmmioOut, &mmioinfoOut, MMIO_WRITE);
1860                     if (code != 0)
1861                     {
1862                         destroy_temporary_buffer(tb);
1863                         ::mmioClose(hmmioOut, 0);
1864                         return STATUS_IO_ERROR;
1865                     }
1866 
1867                     to_write            = reinterpret_cast<uint8_t *>(mmioinfoOut.pchEndWrite)
1868                                         - reinterpret_cast<uint8_t *>(mmioinfoOut.pchNext);
1869                 }
1870 
1871                 // Fill buffer with new data
1872                 size_t bytes    = tb->nSize - offset;
1873                 if (to_write > bytes)
1874                     to_write        = bytes;
1875                 uint8_t *dst    = reinterpret_cast<uint8_t *>(mmioinfoOut.pchNext);
1876                 ::memcpy(dst, &tb->bData[offset], to_write);
1877                 mmioinfoOut.pchNext = reinterpret_cast<HPSTR>(dst + to_write);
1878                 offset         += to_write;
1879             }
1880 
1881             // Clear size of temporary buffer
1882             samples    += frames;
1883             tb->nSize   = 0;
1884         }
1885 
1886         // Destroy temporary buffer and flush file contents
1887         destroy_temporary_buffer(tb);
1888         mmioinfoOut.dwFlags |= MMIO_DIRTY;
1889         if ((code = ::mmioSetInfo(hmmioOut, &mmioinfoOut, 0)) != 0)
1890         {
1891             ::mmioClose(hmmioOut, 0);
1892             return STATUS_IO_ERROR;
1893         }
1894 
1895         // Close file and complete write
1896         return complete_riff_file(&hmmioOut, &ckOut, &ckOutRIFF, &mmioinfoOut, samples);
1897     }
1898 
load_mmio(const LSPString * path,float max_duration)1899     status_t AudioFile::load_mmio(const LSPString *path, float max_duration)
1900     {
1901         HMMIO               hmmioIn;
1902         MMIOINFO            mmioInfoIn;
1903         MMCKINFO            ckInRiff;
1904         MMCKINFO            ckIn;
1905         int                 error;
1906         status_t            res;
1907         WAVEFORMATEX       *pwfxInfo;
1908         WAVEFORMATEX        dstInfo;
1909         HACMSTREAM          acmStream;
1910 
1911         // Open RIFF file
1912         res = open_riff_file(path->get_utf16(), &hmmioIn, &pwfxInfo, &ckInRiff);
1913         if (res != STATUS_OK)
1914             return res;
1915 
1916         // Estimate maximum number of samples to read
1917         size_t srate        = LE_TO_CPU(pwfxInfo->nSamplesPerSec);
1918         size_t samples      = (max_duration >= 0.0f) ? seconds_to_samples(srate, max_duration) : size_t(-1);
1919         lsp_trace("file parameters: channels=%d, sample_rate=%d max_duration=%.3f",
1920             int(LE_TO_CPU(pwfxInfo->nChannels)),
1921             int(LE_TO_CPU(pwfxInfo->nSamplesPerSec)),
1922             max_duration
1923         );
1924 
1925         // Perform a seek to data
1926         if ((error = ::mmioSeek(hmmioIn, LE_TO_CPU(ckInRiff.dwDataOffset) + sizeof(FOURCC), SEEK_SET)) == -1)
1927         {
1928             ::mmioClose(hmmioIn, 0);
1929             return STATUS_BAD_FORMAT;
1930         }
1931         ckIn.ckid   = mmioFOURCC('d', 'a', 't', 'a');
1932         if ((error = ::mmioDescend(hmmioIn, &ckIn, &ckInRiff, MMIO_FINDCHUNK)) != 0)
1933         {
1934             ::mmioClose(hmmioIn, 0);
1935             return STATUS_BAD_FORMAT;
1936         }
1937         if ((error = ::mmioGetInfo(hmmioIn, &mmioInfoIn, 0)) != 0)
1938         {
1939             ::mmioClose(hmmioIn, 0);
1940             return STATUS_IO_ERROR;
1941         }
1942 
1943         // Some magic with computing
1944         size_t bytes            = LE_TO_CPU(ckIn.cksize);
1945         size_t channels         = LE_TO_CPU(pwfxInfo->nChannels);
1946         if (bytes > LE_TO_CPU(ckIn.cksize))
1947             bytes       = LE_TO_CPU(ckIn.cksize);
1948 
1949         // We are ready to read but first initialize ACM stream
1950         dstInfo.wFormatTag      = WAVE_FORMAT_IEEE_FLOAT;
1951         dstInfo.nChannels       = channels;
1952         dstInfo.nSamplesPerSec  = LE_TO_CPU(pwfxInfo->nSamplesPerSec);
1953         dstInfo.nAvgBytesPerSec = dstInfo.nSamplesPerSec * dstInfo.nChannels * sizeof(float);
1954         dstInfo.nBlockAlign     = dstInfo.nChannels * sizeof(float);
1955         dstInfo.wBitsPerSample  = sizeof(float) * 8;
1956         dstInfo.cbSize          = 0;
1957 
1958         dstInfo.wFormatTag      = CPU_TO_LE(dstInfo.wFormatTag);
1959         dstInfo.nChannels       = CPU_TO_LE(dstInfo.nChannels);
1960         dstInfo.nSamplesPerSec  = CPU_TO_LE(dstInfo.nSamplesPerSec);
1961         dstInfo.nAvgBytesPerSec = CPU_TO_LE(dstInfo.nAvgBytesPerSec);
1962         dstInfo.nBlockAlign     = CPU_TO_LE(dstInfo.nBlockAlign);
1963         dstInfo.wBitsPerSample  = CPU_TO_LE(dstInfo.wBitsPerSample);
1964         dstInfo.cbSize          = CPU_TO_LE(dstInfo.cbSize);
1965 
1966         // Open and configure ACM stream
1967         if ((error = ::acmStreamOpen(&acmStream, NULL, pwfxInfo, &dstInfo, NULL, 0, 0, ACM_STREAMOPENF_NONREALTIME)) != 0)
1968         {
1969             ::mmioClose(hmmioIn, 0);
1970             switch (error)
1971             {
1972                 case ACMERR_NOTPOSSIBLE: return STATUS_BAD_FORMAT;
1973                 case STATUS_NO_MEM: return STATUS_NO_MEM;
1974                 default: return STATUS_UNKNOWN_ERR;
1975             }
1976         }
1977 
1978         ACMSTREAMHEADER streamHead;
1979         ::bzero(&streamHead, sizeof(ACMSTREAMHEADER));
1980 
1981         streamHead.cbStruct         = sizeof(ACMSTREAMHEADER);
1982         streamHead.cbSrcLength      = ACM_INPUT_BUFSIZE;
1983         streamHead.pbSrc            = reinterpret_cast<PBYTE>(::malloc(streamHead.cbSrcLength));
1984         if (streamHead.pbSrc == NULL)
1985         {
1986             ::acmStreamClose(acmStream, 0);
1987             ::mmioClose(hmmioIn, 0);
1988             return STATUS_NO_MEM;
1989         }
1990 
1991         error = ::acmStreamSize(acmStream, ACM_INPUT_BUFSIZE, &streamHead.cbDstLength, ACM_STREAMSIZEF_SOURCE);
1992         if ((error != 0) || (streamHead.cbDstLength <= 0))
1993         {
1994             ::free(streamHead.pbSrc);
1995             ::acmStreamClose(acmStream, 0);
1996             ::mmioClose(hmmioIn, 0);
1997             return STATUS_UNKNOWN_ERR;
1998         }
1999 
2000         streamHead.pbDst            = reinterpret_cast<PBYTE>(::malloc(streamHead.cbDstLength));
2001         if (streamHead.pbDst == NULL)
2002         {
2003             ::free(streamHead.pbSrc);
2004             ::acmStreamClose(acmStream, 0);
2005             ::mmioClose(hmmioIn, 0);
2006             return STATUS_NO_MEM;
2007         }
2008 
2009         if ((error = acmStreamPrepareHeader( acmStream, &streamHead, 0 )) != 0)
2010         {
2011             ::free(streamHead.pbSrc);
2012             ::free(streamHead.pbDst);
2013             ::acmStreamClose(acmStream, 0);
2014             ::mmioClose(hmmioIn, 0);
2015             return STATUS_BAD_FORMAT;
2016         }
2017 
2018         // Create file content for storage
2019         file_content_t *data = create_file_content(channels, 1024);
2020         if (!data)
2021         {
2022             ::free(streamHead.pbSrc);
2023             ::free(streamHead.pbDst);
2024             ::acmStreamClose(acmStream, 0);
2025             ::mmioClose(hmmioIn, 0);
2026             return STATUS_NO_MEM;
2027         }
2028 
2029         // Perform read + decode
2030         // https://gist.github.com/dweekly/633367
2031         size_t bread = 0, fread = 0; // Number of bytes read, number of frames read
2032         bool eof     = false;
2033 
2034         while (true)
2035         {
2036             // We have read enough data?
2037             if ((max_duration >= 0.0f) && (fread >= samples))
2038                 break;
2039 
2040             // Try to maximize input buffer size
2041             if ((streamHead.cbSrcLength < ACM_INPUT_BUFSIZE) && (!eof))
2042             {
2043                 size_t avail    = reinterpret_cast<uint8_t *>(mmioInfoIn.pchEndRead)
2044                                 - reinterpret_cast<uint8_t *>(mmioInfoIn.pchNext);
2045                 if (avail > 0)
2046                 {
2047                     // Fill buffer
2048                     size_t to_copy      = ACM_INPUT_BUFSIZE - streamHead.cbSrcLength;
2049                     if (to_copy > avail)
2050                         to_copy     = avail;
2051                     ::memcpy(&streamHead.pbSrc[streamHead.cbSrcLength], mmioInfoIn.pchNext, to_copy);
2052                     mmioInfoIn.pchNext  = reinterpret_cast<HPSTR>(reinterpret_cast<uint8_t *>(mmioInfoIn.pchNext) + to_copy);
2053                     continue;
2054                 }
2055                 else if (bread >= bytes)
2056                 {
2057                     eof     = true;
2058                     continue;
2059                 }
2060 
2061                 // Try to read from MMIO
2062                 error = ::mmioAdvance(hmmioIn, &mmioInfoIn, MMIO_READ);
2063                 if ((error != 0) || (mmioInfoIn.pchNext == mmioInfoIn.pchEndRead))
2064                 {
2065                     destroy_file_content(data);
2066                     ::free(streamHead.pbSrc);
2067                     ::free(streamHead.pbDst);
2068                     ::acmStreamUnprepareHeader(acmStream, &streamHead, 0);
2069                     ::acmStreamClose(acmStream, 0);
2070                     ::mmioClose(hmmioIn, 0);
2071                     return STATUS_BAD_FORMAT;
2072                 }
2073 
2074                 // Update number of bytes read from RIFF file
2075                 bread      += reinterpret_cast<uint8_t *>(mmioInfoIn.pchEndRead)
2076                             - reinterpret_cast<uint8_t *>(mmioInfoIn.pchNext);
2077             }
2078             else if (streamHead.cbSrcLength > 0)
2079             {
2080                 // Perform conversion
2081                 size_t flags = (eof) ? 0 : ACM_STREAMCONVERTF_BLOCKALIGN;
2082                 if ((error = ::acmStreamConvert(acmStream, &streamHead, flags)) != 0)
2083                 {
2084                     destroy_file_content(data);
2085                     ::free(streamHead.pbSrc);
2086                     ::free(streamHead.pbDst);
2087                     ::acmStreamUnprepareHeader(acmStream, &streamHead, 0);
2088                     ::acmStreamClose(acmStream, 0);
2089                     ::mmioClose(hmmioIn, 0);
2090                     return STATUS_UNKNOWN_ERR;
2091                 }
2092 
2093                 // Advance the input buffer pointer
2094                 size_t delta = streamHead.cbSrcLength - streamHead.cbSrcLengthUsed;
2095                 if (delta > 0)
2096                     ::memmove(streamHead.pbSrc, &streamHead.pbSrc[streamHead.cbSrcLengthUsed], delta);
2097                 streamHead.cbSrcLength      = delta;
2098                 streamHead.cbSrcLengthUsed  = 0;
2099 
2100                 // Invalid data at output?
2101                 size_t frames   = streamHead.cbDstLengthUsed / (sizeof(float) * channels);
2102                 if ((frames * sizeof(float) * channels) != streamHead.cbDstLengthUsed)
2103                 {
2104                     destroy_file_content(data);
2105                     ::free(streamHead.pbSrc);
2106                     ::free(streamHead.pbDst);
2107                     ::acmStreamUnprepareHeader(acmStream, &streamHead, 0);
2108                     ::acmStreamClose(acmStream, 0);
2109                     ::mmioClose(hmmioIn, 0);
2110                     return STATUS_CORRUPTED_FILE;
2111                 }
2112 
2113                 // Commit decoded data to the output file
2114                 float *fsamples = reinterpret_cast<float *>(streamHead.pbDst);
2115                 __IF_BE( dsp::swap_bytes(fsamples, frames * channels) );
2116                 if ((max_duration >= 0.0f) && (frames > samples))
2117                     frames      = samples;
2118                 size_t nfread       = fread + frames;
2119 
2120                 // Ensure that we have enough space for growing
2121                 file_content_t *ndata   = grow_file_content(data, nfread);
2122                 if (ndata == NULL)
2123                 {
2124                     destroy_file_content(data);
2125                     ::free(streamHead.pbSrc);
2126                     ::free(streamHead.pbDst);
2127                     ::acmStreamUnprepareHeader(acmStream, &streamHead, 0);
2128                     ::acmStreamClose(acmStream, 0);
2129                     ::mmioClose(hmmioIn, 0);
2130                     return STATUS_NO_MEM;
2131                 }
2132                 data        = ndata;
2133 
2134                 // Process each frame (de-interleave)
2135                 for (size_t i=0; i<channels; ++i)
2136                 {
2137                     const float *src = &fsamples[i];
2138                     float *dst = data->vChannels[i];
2139                     for (size_t j=0; j<frames; ++j, src += channels, ++dst)
2140                         *dst = *src;
2141                 }
2142                 fread       = nfread; // Update number of read frames
2143 
2144                 // Advance the output buffer pointer
2145                 delta   = streamHead.cbDstLengthUsed - frames * (sizeof(float) * channels);
2146                 if (delta > 0)
2147                     ::memmove(streamHead.pbDst, &streamHead.pbDst[streamHead.cbDstLengthUsed], delta);
2148                 streamHead.cbSrcLength      = delta;
2149                 streamHead.cbDstLengthUsed  = 0;
2150             }
2151             else // No more data to convert?
2152             {
2153                 eof     = true;
2154                 break;
2155             }
2156         }
2157 
2158         // Free ACM headers and close ACM stream
2159         ::free(streamHead.pbSrc);
2160         ::free(streamHead.pbDst);
2161         if ((error = ::acmStreamUnprepareHeader(acmStream, &streamHead, 0)) != 0)
2162         {
2163             destroy_file_content(data);
2164             ::acmStreamClose(acmStream, 0);
2165             ::mmioClose(hmmioIn, 0);
2166             return STATUS_UNKNOWN_ERR;
2167         }
2168         if ((error = ::acmStreamUnprepareHeader(acmStream, &streamHead, 0)) != 0)
2169         {
2170             destroy_file_content(data);
2171             ::mmioClose(hmmioIn, 0);
2172             return STATUS_UNKNOWN_ERR;
2173         }
2174 
2175         // Complete reading
2176         if ((error = ::mmioSetInfo(hmmioIn, &mmioInfoIn, 0)) != 0)
2177         {
2178             destroy_file_content(data);
2179             ::mmioClose(hmmioIn, 0);
2180             return STATUS_IO_ERROR;
2181         }
2182         if ((error = ::mmioClose(hmmioIn, 0)) != 0)
2183         {
2184             destroy_file_content(data);
2185             return STATUS_IO_ERROR;
2186         }
2187 
2188         // Success read, destroy previously used content and store new
2189         if (pData != NULL)
2190             destroy_file_content(pData);
2191         pData               = data;
2192 
2193         return STATUS_OK;
2194     }
2195 
2196 #else
2197 
decode_sf_error(SNDFILE * fd)2198     static status_t decode_sf_error(SNDFILE *fd)
2199     {
2200         switch (sf_error(NULL))
2201         {
2202             case SF_ERR_NO_ERROR:
2203                 return STATUS_OK;
2204             case SF_ERR_UNRECOGNISED_FORMAT:
2205                 return STATUS_BAD_FORMAT;
2206             case SF_ERR_MALFORMED_FILE:
2207                 return STATUS_CORRUPTED_FILE;
2208             case SF_ERR_UNSUPPORTED_ENCODING:
2209                 return STATUS_BAD_FORMAT;
2210             default:
2211                 return STATUS_UNKNOWN_ERR;
2212         }
2213     }
2214 
load_sndfile(const LSPString * path,float max_duration)2215     status_t AudioFile::load_sndfile(const LSPString *path, float max_duration)
2216     {
2217         // Load sound file
2218         SNDFILE *sf_obj;
2219         SF_INFO sf_info;
2220 
2221         // Open sound file
2222         lsp_trace("loading file: %s\n", path->get_native());
2223         if ((sf_obj = sf_open(path->get_native(), SFM_READ, &sf_info)) == NULL)
2224             return decode_sf_error(sf_obj);
2225 
2226         // Read sample file
2227         ssize_t max_samples     = (max_duration >= 0.0f) ? seconds_to_samples(sf_info.samplerate, max_duration) : -1;
2228         lsp_trace("file parameters: frames=%d, channels=%d, sample_rate=%d max_duration=%.3f\n, max_samples=%d",
2229             int(sf_info.frames), int(sf_info.channels), int(sf_info.samplerate), max_duration, int(max_samples));
2230 
2231         // Patch sf_info
2232         if ((max_samples >= 0) && (sf_info.frames > sf_count_t(max_samples)))
2233             sf_info.frames  = max_samples;
2234 
2235         // Create file content
2236         file_content_t *fc      = create_file_content(sf_info.channels, sf_info.frames);
2237         if (fc == NULL)
2238         {
2239             sf_close(sf_obj);
2240             return STATUS_NO_MEM;
2241         }
2242         fc->nSampleRate         = sf_info.samplerate;
2243 
2244         // Allocate temporary buffer
2245         temporary_buffer_t *tb  = create_temporary_buffer(fc);
2246         if (tb == NULL)
2247         {
2248             destroy_file_content(fc);
2249             sf_close(sf_obj);
2250             return STATUS_NO_MEM;
2251         }
2252 
2253         size_t count = sf_info.frames;
2254         while (count > 0)
2255         {
2256             // Determine how many data is available to read
2257             size_t can_read     = (tb->nCapacity - tb->nSize) / tb->nFrameSize;
2258             if (can_read <= 0)
2259             {
2260                 flush_temporary_buffer(tb);
2261                 can_read            = (tb->nCapacity - tb->nSize) / tb->nFrameSize;
2262             }
2263 
2264             // Calculate amount of samples to read
2265             size_t to_read      = (count > can_read) ? can_read : count;
2266             sf_count_t amount   = sf_readf_float(sf_obj, reinterpret_cast<float *>(&tb->bData[tb->nSize]), to_read);
2267             if (amount <= 0)
2268             {
2269                 status_t status     = decode_sf_error(sf_obj);
2270 
2271                 destroy_temporary_buffer(tb);
2272                 destroy_file_content(fc);
2273                 sf_close(sf_obj);
2274 
2275                 return status;
2276             }
2277 
2278             // Update counters
2279             tb->nSize          += amount * tb->nFrameSize;
2280             count              -= amount;
2281         }
2282 
2283         // Flush last read data (if present)
2284         flush_temporary_buffer(tb);
2285 
2286         // Free allocated resources
2287         destroy_temporary_buffer(tb);
2288         sf_close(sf_obj);
2289 
2290         // Destroy previously used content and store new
2291         if (pData != NULL)
2292             destroy_file_content(pData);
2293         pData               = fc;
2294 
2295         return STATUS_OK;
2296     }
2297 
save_sndfile(const LSPString * path,size_t from,size_t max_count)2298     status_t AudioFile::save_sndfile(const LSPString *path, size_t from, size_t max_count)
2299     {
2300         if (pData == NULL)
2301             return STATUS_NO_DATA;
2302 
2303         // Load sound file
2304         SNDFILE *sf_obj;
2305         SF_INFO sf_info;
2306 
2307         sf_info.frames      = max_count;
2308         sf_info.samplerate  = pData->nSampleRate;
2309         sf_info.channels    = pData->nChannels;
2310         sf_info.format      = SF_FORMAT_WAV | SF_FORMAT_FLOAT | SF_ENDIAN_LITTLE;
2311         sf_info.sections    = 0;
2312         sf_info.seekable    = 0;
2313 
2314         if (sf_info.frames > sf_count_t(pData->nSamples - from))
2315             sf_info.frames      = pData->nSamples - from;
2316 
2317         // Open sound file
2318         lsp_trace("storing file: %s\n", path->get_native());
2319         if ((sf_obj = sf_open(path->get_native(), SFM_WRITE, &sf_info)) == NULL)
2320         {
2321             lsp_trace("Error: %s", sf_strerror(sf_obj));
2322             return decode_sf_error(NULL);
2323         }
2324 
2325         // Allocate temporary buffer
2326         temporary_buffer_t *tb  = create_temporary_buffer(pData, from);
2327         if (tb == NULL)
2328             return STATUS_NO_MEM;
2329 
2330         while ((max_count > 0) || (tb->nSize > 0))
2331         {
2332             // Fill buffer
2333             max_count   -=  fill_temporary_buffer(tb, max_count);
2334 
2335             // Flush buffer
2336             if (tb->nSize > 0)
2337             {
2338                 // Write buffer to file
2339                 size_t offset = 0;
2340                 size_t frames = tb->nSize / tb->nFrameSize;
2341                 while (offset < tb->nSize)
2342                 {
2343                     sf_count_t written  = sf_writef_float(sf_obj, reinterpret_cast<float *>(&tb->bData[offset]), frames);
2344                     if (written < 0)
2345                     {
2346                         status_t status     = decode_sf_error(sf_obj);
2347                         sf_close(sf_obj);
2348                         destroy_temporary_buffer(tb);
2349                         return status;
2350                     }
2351                     offset +=  written * tb->nFrameSize;
2352                     frames -=  written;
2353                 }
2354 
2355                 // Update buffer contents
2356                 frames  = tb->nSize - offset;
2357                 if (frames > 0)
2358                     ::memmove(tb->bData, &tb->bData[offset], frames);
2359                 tb->nSize   = frames;
2360             }
2361         }
2362 
2363         // Free allocated resources
2364         sf_close(sf_obj);
2365         destroy_temporary_buffer(tb);
2366 
2367         return STATUS_OK;
2368     }
2369 #endif /* PLATFORM_WINDOWS */
2370 
2371 } /* namespace lsp */
2372