~ubuntu-branches/ubuntu/trusty/aegisub/trusty

« back to all changes in this revision

Viewing changes to src/audio_provider_pcm.cpp

  • Committer: Package Import Robot
  • Author(s): Sebastian Reichel
  • Date: 2012-03-16 22:58:00 UTC
  • Revision ID: package-import@ubuntu.com-20120316225800-yfb8h9e5n04rk46a
Tags: upstream-2.1.9
ImportĀ upstreamĀ versionĀ 2.1.9

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright (c) 2007-2008, Niels Martin Hansen
 
2
// All rights reserved.
 
3
//
 
4
// Redistribution and use in source and binary forms, with or without
 
5
// modification, are permitted provided that the following conditions are met:
 
6
//
 
7
//   * Redistributions of source code must retain the above copyright notice,
 
8
//     this list of conditions and the following disclaimer.
 
9
//   * Redistributions in binary form must reproduce the above copyright notice,
 
10
//     this list of conditions and the following disclaimer in the documentation
 
11
//     and/or other materials provided with the distribution.
 
12
//   * Neither the name of the Aegisub Group nor the names of its contributors
 
13
//     may be used to endorse or promote products derived from this software
 
14
//     without specific prior written permission.
 
15
//
 
16
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 
17
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 
18
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 
19
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 
20
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 
21
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 
22
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 
23
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 
24
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 
25
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 
26
// POSSIBILITY OF SUCH DAMAGE.
 
27
//
 
28
// -----------------------------------------------------------------------------
 
29
//
 
30
// AEGISUB
 
31
//
 
32
// Website: http://aegisub.cellosoft.com
 
33
// Contact: mailto:jiifurusu@gmail.com
 
34
//
 
35
 
 
36
 
 
37
#include "config.h"
 
38
 
 
39
#include <wx/filename.h>
 
40
#include <wx/file.h>
 
41
#include "audio_provider_pcm.h"
 
42
#include "utils.h"
 
43
#include "aegisub_endian.h"
 
44
#include <stdint.h>
 
45
#include <assert.h>
 
46
 
 
47
#ifndef _WINDOWS
 
48
#include <sys/mman.h>
 
49
#include <sys/fcntl.h>
 
50
#include <sys/stat.h>
 
51
#endif
 
52
 
 
53
 
 
54
 
 
55
PCMAudioProvider::PCMAudioProvider(const wxString &filename)
 
56
{
 
57
#ifdef _WINDOWS
 
58
 
 
59
        file_handle = CreateFile(
 
60
                filename.c_str(),
 
61
                FILE_READ_DATA,
 
62
                FILE_SHARE_READ|FILE_SHARE_WRITE,
 
63
                0,
 
64
                OPEN_EXISTING,
 
65
                FILE_ATTRIBUTE_NORMAL|FILE_FLAG_RANDOM_ACCESS,
 
66
                0);
 
67
 
 
68
        if (file_handle == INVALID_HANDLE_VALUE) {
 
69
                wxLogWarning(_T("PCM audio provider: Could not open audio file for reading (%d)"), GetLastError());
 
70
                throw _T("PCM audio provider: Could not open audio file for reading");
 
71
        }
 
72
 
 
73
        LARGE_INTEGER li_file_size = {0};
 
74
        if (!GetFileSizeEx(file_handle, &li_file_size)) {
 
75
                CloseHandle(file_handle);
 
76
                throw _T("PCM audio provider: Failed getting file size");
 
77
        }
 
78
        file_size = li_file_size.QuadPart;
 
79
 
 
80
        file_mapping = CreateFileMapping(
 
81
                file_handle,
 
82
                0,
 
83
                PAGE_READONLY,
 
84
                0, 0,
 
85
                0);
 
86
 
 
87
        if (file_mapping == 0) {
 
88
                CloseHandle(file_handle);
 
89
                throw _T("PCM audio provider: Failed creating file mapping");
 
90
        }
 
91
 
 
92
        current_mapping = 0;
 
93
 
 
94
#else
 
95
 
 
96
        file_handle = open(filename.mb_str(*wxConvFileName), O_RDONLY);
 
97
 
 
98
        if (file_handle == -1) {
 
99
                throw _T("PCM audio provider: Could not open audio file for reading");
 
100
        }
 
101
 
 
102
        struct stat filestats;
 
103
        memset(&filestats, 0, sizeof(filestats));
 
104
        if (fstat(file_handle, &filestats)) {
 
105
                close(file_handle);
 
106
                throw _T("PCM audio provider: Could not stat file to get size");
 
107
        }
 
108
        file_size = filestats.st_size;
 
109
 
 
110
        current_mapping = 0;
 
111
 
 
112
#endif
 
113
}
 
114
 
 
115
 
 
116
PCMAudioProvider::~PCMAudioProvider()
 
117
{
 
118
#ifdef _WINDOWS
 
119
 
 
120
        if (current_mapping) {
 
121
                UnmapViewOfFile(current_mapping);
 
122
        }
 
123
 
 
124
        CloseHandle(file_mapping);
 
125
        CloseHandle(file_handle);
 
126
 
 
127
#else
 
128
 
 
129
        if (current_mapping) {
 
130
                munmap(current_mapping, mapping_length);
 
131
        }
 
132
 
 
133
        close(file_handle);
 
134
 
 
135
#endif
 
136
}
 
137
 
 
138
 
 
139
char * PCMAudioProvider::EnsureRangeAccessible(int64_t range_start, int64_t range_length)
 
140
{
 
141
        if (range_start + range_length > file_size) {
 
142
                throw _T("PCM audio provider: Attempted to map beyond end of file");
 
143
        }
 
144
 
 
145
        // Check whether the requested range is already visible
 
146
        if (!current_mapping || range_start < mapping_start || range_start+range_length > mapping_start+(int64_t)mapping_length) {
 
147
 
 
148
                // It's not visible, change the current mapping
 
149
                
 
150
                if (current_mapping) {
 
151
#ifdef _WINDOWS
 
152
                        UnmapViewOfFile(current_mapping);
 
153
#else
 
154
                        munmap(current_mapping, mapping_length);
 
155
#endif
 
156
                }
 
157
 
 
158
                // Align range start on a 1 MB boundary and go 16 MB back
 
159
                mapping_start = (range_start & ~0xFFFFF) - 0x1000000;
 
160
                if (mapping_start < 0) mapping_start = 0;
 
161
 
 
162
                if (sizeof(void*) > 4)
 
163
                        // Large address space, use a 2 GB mapping
 
164
                        mapping_length = 0x80000000;
 
165
                else
 
166
                        // Small (32 bit) address space, use a 256 MB mapping
 
167
                        mapping_length = 0x10000000;
 
168
 
 
169
                // Make sure to always make a mapping at least as large as the requested range
 
170
                if ((int64_t)mapping_length < range_length) {
 
171
                        if (range_length > (int64_t)(~(size_t)0))
 
172
                                throw _T("PCM audio provider: Requested range larger than max size_t, cannot create view of file");
 
173
                        else
 
174
                                mapping_length = range_length;
 
175
                }
 
176
                // But also make sure we don't try to make a mapping larger than the file
 
177
                if (mapping_start + (int64_t)mapping_length > file_size)
 
178
                        mapping_length = (size_t)(file_size - mapping_start);
 
179
                // We already checked that the requested range doesn't extend over the end of the file
 
180
                // Hopefully this should ensure that small files are always mapped in their entirety
 
181
 
 
182
#ifdef _WINDOWS
 
183
                LARGE_INTEGER mapping_start_li;
 
184
                mapping_start_li.QuadPart = mapping_start;
 
185
                current_mapping = MapViewOfFile(
 
186
                        file_mapping,   // Mapping handle
 
187
                        FILE_MAP_READ,  // Access type
 
188
                        mapping_start_li.HighPart,      // Offset high-part
 
189
                        mapping_start_li.LowPart,       // Offset low-part
 
190
                        mapping_length);        // Length of view
 
191
#else
 
192
                current_mapping = mmap(0, mapping_length, PROT_READ, MAP_PRIVATE, file_handle, mapping_start);
 
193
#endif
 
194
 
 
195
                if (!current_mapping) {
 
196
                        throw _T("PCM audio provider: Failed mapping a view of the file");
 
197
                }
 
198
 
 
199
        }
 
200
 
 
201
        assert(current_mapping);
 
202
        assert(range_start >= mapping_start);
 
203
 
 
204
        // Difference between actual current mapping start and requested range start
 
205
        ptrdiff_t rel_ofs = (ptrdiff_t)(range_start - mapping_start);
 
206
 
 
207
        // Calculate a pointer into current mapping for the requested range
 
208
        return ((char*)current_mapping) + rel_ofs;
 
209
}
 
210
 
 
211
 
 
212
void PCMAudioProvider::GetAudio(void *buf, int64_t start, int64_t count)
 
213
{
 
214
        // Read blocks from the file
 
215
        size_t index = 0;
 
216
        while (count > 0 && index < index_points.size()) {
 
217
                // Check if this index contains the samples we're looking for
 
218
                IndexPoint &ip = index_points[index];
 
219
                if (ip.start_sample <= start && ip.start_sample+ip.num_samples > start) {
 
220
 
 
221
                        // How many samples we can maximum take from this block
 
222
                        int64_t samples_can_do = ip.num_samples - start + ip.start_sample;
 
223
                        if (samples_can_do > count) samples_can_do = count;
 
224
 
 
225
                        // Read as many samples we can
 
226
                        char *src = EnsureRangeAccessible(
 
227
                                ip.start_byte + (start - ip.start_sample) * bytes_per_sample * channels,
 
228
                                samples_can_do * bytes_per_sample * channels);
 
229
                        memcpy(buf, src, samples_can_do * bytes_per_sample * channels);
 
230
 
 
231
                        // Update data
 
232
                        buf = (char*)buf + samples_can_do * bytes_per_sample * channels;
 
233
                        start += samples_can_do;
 
234
                        count -= samples_can_do;
 
235
 
 
236
                }
 
237
 
 
238
                index++;
 
239
        }
 
240
 
 
241
        // If we exhausted all sample sections zerofill the rest
 
242
        if (count > 0) {
 
243
                if (bytes_per_sample == 1)
 
244
                        // 8 bit formats are usually unsigned with bias 127
 
245
                        memset(buf, 127, count*channels);
 
246
                else
 
247
                        // While everything else is signed
 
248
                        memset(buf, 0, count*bytes_per_sample*channels);
 
249
        }
 
250
}
 
251
 
 
252
 
 
253
// RIFF WAV PCM provider
 
254
// Overview of RIFF WAV: <http://www.sonicspot.com/guide/wavefiles.html>
 
255
 
 
256
class  RiffWavPCMAudioProvider : public PCMAudioProvider {
 
257
private:
 
258
        struct ChunkHeader {
 
259
                char type[4];
 
260
                uint32_t size;
 
261
        };
 
262
        struct RIFFChunk {
 
263
                ChunkHeader ch;
 
264
                char format[4];
 
265
        };
 
266
        struct fmtChunk {
 
267
                // Skip the chunk header here, it's processed separately
 
268
                uint16_t compression; // compression format used -- 0x0001 = PCM
 
269
                uint16_t channels;
 
270
                uint32_t samplerate;
 
271
                uint32_t avg_bytes_sec; // can't always be trusted
 
272
                uint16_t block_align;
 
273
                uint16_t significant_bits_sample;
 
274
                // Here was supposed to be some more fields but we don't need them
 
275
                // and just skipping by the size of the struct wouldn't be safe
 
276
                // either way, as the fields can depend on the compression.
 
277
        };
 
278
 
 
279
        static bool CheckFourcc(const char str1[], const char str2[])
 
280
        {
 
281
                assert(str1);
 
282
                assert(str2);
 
283
                return
 
284
                        (str1[0] == str2[0]) &&
 
285
                        (str1[1] == str2[1]) &&
 
286
                        (str1[2] == str2[2]) &&
 
287
                        (str1[3] == str2[3]);
 
288
        }
 
289
 
 
290
public:
 
291
        RiffWavPCMAudioProvider(const wxString &_filename)
 
292
                : PCMAudioProvider(_filename)
 
293
        {
 
294
                filename = _filename;
 
295
 
 
296
                // Read header
 
297
                // This should throw an exception if the mapping fails
 
298
                void *filestart = EnsureRangeAccessible(0, sizeof(RIFFChunk));
 
299
                assert(filestart);
 
300
                RIFFChunk &header = *(RIFFChunk*)filestart;
 
301
 
 
302
                // Check magic values
 
303
                if (!CheckFourcc(header.ch.type, "RIFF"))
 
304
                        throw _T("RIFF PCM WAV audio provider: File is not a RIFF file");
 
305
                if (!CheckFourcc(header.format, "WAVE"))
 
306
                        throw _T("RIFF PCM WAV audio provider: File is not a RIFF WAV file");
 
307
 
 
308
                // Count how much more data we can have in the entire file
 
309
                // The first 4 bytes are already eaten by the header.format field
 
310
                uint32_t data_left = Endian::LittleToMachine(header.ch.size) - 4;
 
311
                // How far into the file we have processed.
 
312
                // Must be incremented by the riff chunk size fields.
 
313
                uint32_t filepos = sizeof(header);
 
314
 
 
315
                bool got_fmt_header = false;
 
316
 
 
317
                // Inherited from AudioProvider
 
318
                num_samples = 0;
 
319
 
 
320
                // Continue reading chunks until out of data
 
321
                while (data_left) {
 
322
                        ChunkHeader &ch = *(ChunkHeader*)EnsureRangeAccessible(filepos, sizeof(ChunkHeader));
 
323
 
 
324
                        // Update counters
 
325
                        data_left -= sizeof(ch);
 
326
                        filepos += sizeof(ch);
 
327
 
 
328
                        if (CheckFourcc(ch.type, "fmt ")) {
 
329
                                if (got_fmt_header) throw _T("RIFF PCM WAV audio provider: Invalid file, multiple 'fmt ' chunks");
 
330
                                got_fmt_header = true;
 
331
 
 
332
                                fmtChunk &fmt = *(fmtChunk*)EnsureRangeAccessible(filepos, sizeof(fmtChunk));
 
333
 
 
334
                                if (Endian::LittleToMachine(fmt.compression) != 1) throw _T("RIFF PCM WAV audio provider: Can't use file, not PCM encoding");
 
335
 
 
336
                                // Set stuff inherited from the AudioProvider class
 
337
                                sample_rate = Endian::LittleToMachine(fmt.samplerate);
 
338
                                channels = Endian::LittleToMachine(fmt.channels);
 
339
                                bytes_per_sample = (Endian::LittleToMachine(fmt.significant_bits_sample) + 7) / 8; // round up to nearest whole byte
 
340
                        }
 
341
 
 
342
                        else if (CheckFourcc(ch.type, "data")) {
 
343
                                // This won't pick up 'data' chunks inside 'wavl' chunks
 
344
                                // since the 'wavl' chunks wrap those.
 
345
 
 
346
                                if (!got_fmt_header) throw _T("RIFF PCM WAV audio provider: Found 'data' chunk before 'fmt ' chunk, file is invalid.");
 
347
 
 
348
                                int64_t samples = Endian::LittleToMachine(ch.size) / bytes_per_sample;
 
349
                                int64_t frames = samples / channels;
 
350
 
 
351
                                IndexPoint ip;
 
352
                                ip.start_sample = num_samples;
 
353
                                ip.num_samples = frames;
 
354
                                ip.start_byte = filepos;
 
355
                                index_points.push_back(ip);
 
356
 
 
357
                                num_samples += frames;
 
358
                        }
 
359
 
 
360
                        // Support wavl (wave list) chunks too?
 
361
 
 
362
                        // Update counters
 
363
                        // Make sure they're word aligned
 
364
                        data_left -= (Endian::LittleToMachine(ch.size) + 1) & ~1;
 
365
                        filepos += (Endian::LittleToMachine(ch.size) + 1) & ~1;
 
366
                }
 
367
        }
 
368
 
 
369
 
 
370
        bool AreSamplesNativeEndian()
 
371
        {
 
372
                // 8 bit samples don't consider endianness
 
373
                if (bytes_per_sample < 2) return true;
 
374
                // Otherwise test whether we're little endian
 
375
                uint32_t testvalue = 0x008800ff;
 
376
                return testvalue == Endian::LittleToMachine(testvalue);
 
377
        }
 
378
};
 
379
 
 
380
 
 
381
 
 
382
// Sony Wave64 audio provider
 
383
// Specs obtained at: <http://www.vcs.de/fileadmin/user_upload/MBS/PDF/Whitepaper/Informations_about_Sony_Wave64.pdf>
 
384
 
 
385
static const uint8_t w64GuidRIFF[16] = {
 
386
        // {66666972-912E-11CF-A5D6-28DB04C10000}
 
387
        0x72, 0x69, 0x66, 0x66, 0x2E, 0x91, 0xCF, 0x11, 0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00
 
388
};
 
389
 
 
390
static const uint8_t w64GuidWAVE[16] = {
 
391
        // {65766177-ACF3-11D3-8CD1-00C04F8EDB8A}
 
392
        0x77, 0x61, 0x76, 0x65, 0xF3, 0xAC, 0xD3, 0x11, 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A
 
393
};
 
394
 
 
395
static const uint8_t w64Guidfmt[16] = {
 
396
        // {20746D66-ACF3-11D3-8CD1-00C04F8EDB8A}
 
397
        0x66, 0x6D, 0x74, 0x20, 0xF3, 0xAC, 0xD3, 0x11, 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A
 
398
};
 
399
 
 
400
static const uint8_t w64Guiddata[16] = {
 
401
        // {61746164-ACF3-11D3-8CD1-00C04F8EDB8A}
 
402
        0x64, 0x61, 0x74, 0x61, 0xF3, 0xAC, 0xD3, 0x11, 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A
 
403
};
 
404
 
 
405
class Wave64AudioProvider : public PCMAudioProvider {
 
406
private:
 
407
        // Here's some copy-paste from the FFmpegSource2 code
 
408
 
 
409
        struct WaveFormatEx { 
 
410
                uint16_t wFormatTag; 
 
411
                uint16_t nChannels; 
 
412
                uint32_t nSamplesPerSec; 
 
413
                uint32_t nAvgBytesPerSec; 
 
414
                uint16_t nBlockAlign; 
 
415
                uint16_t wBitsPerSample; 
 
416
                uint16_t cbSize; 
 
417
        };
 
418
 
 
419
        struct RiffChunk {
 
420
                uint8_t riff_guid[16];
 
421
                uint64_t file_size;
 
422
                uint8_t format_guid[16];
 
423
        };
 
424
 
 
425
        struct FormatChunk {
 
426
                uint8_t chunk_guid[16];
 
427
                uint64_t chunk_size;
 
428
                WaveFormatEx format;
 
429
                uint8_t padding[6];
 
430
        };
 
431
 
 
432
        struct DataChunk {
 
433
                uint8_t chunk_guid[16];
 
434
                uint64_t chunk_size;
 
435
        };
 
436
 
 
437
        inline bool CheckGuid(const uint8_t *guid1, const uint8_t *guid2)
 
438
        {
 
439
                return memcmp(guid1, guid2, 16) == 0;
 
440
        }
 
441
 
 
442
public:
 
443
        Wave64AudioProvider(const wxString &_filename)
 
444
                : PCMAudioProvider(_filename)
 
445
        {
 
446
                filename = _filename;
 
447
 
 
448
                int64_t smallest_possible_file = sizeof(RiffChunk) + sizeof(FormatChunk) + sizeof(DataChunk);
 
449
 
 
450
                if (file_size < smallest_possible_file)
 
451
                        throw _T("Wave64 audio provider: File is too small to be a Wave64 file");
 
452
 
 
453
                // Read header
 
454
                // This should throw an exception if the mapping fails
 
455
                void *filestart = EnsureRangeAccessible(0, sizeof(RiffChunk));
 
456
                assert(filestart);
 
457
                RiffChunk &header = *(RiffChunk*)filestart;
 
458
 
 
459
                // Check magic values
 
460
                if (!CheckGuid(header.riff_guid, w64GuidRIFF))
 
461
                        throw _T("Wave64 audio provider: File is not a Wave64 RIFF file");
 
462
                if (!CheckGuid(header.format_guid, w64GuidWAVE))
 
463
                        throw _T("Wave64 audio provider: File is not a Wave64 WAVE file");
 
464
 
 
465
                // Count how much more data we can have in the entire file
 
466
                uint64_t data_left = Endian::LittleToMachine(header.file_size) - sizeof(RiffChunk);
 
467
                // How far into the file we have processed.
 
468
                // Must be incremented by the riff chunk size fields.
 
469
                uint64_t filepos = sizeof(header);
 
470
 
 
471
                bool got_fmt_header = false;
 
472
 
 
473
                // Inherited from AudioProvider
 
474
                num_samples = 0;
 
475
 
 
476
                // Continue reading chunks until out of data
 
477
                while (data_left) {
 
478
                        uint8_t *chunk_guid = (uint8_t*)EnsureRangeAccessible(filepos, 16);
 
479
                        uint64_t chunk_size = Endian::LittleToMachine(*(uint64_t*)EnsureRangeAccessible(filepos+16, sizeof(uint64_t)));
 
480
 
 
481
                        if (CheckGuid(chunk_guid, w64Guidfmt)) {
 
482
                                if (got_fmt_header)
 
483
                                        throw _T("Wave64 audio provider: Bad file, found more than one 'fmt' chunk");
 
484
 
 
485
                                FormatChunk &fmt = *(FormatChunk*)EnsureRangeAccessible(filepos, sizeof(FormatChunk));
 
486
                                got_fmt_header = true;
 
487
 
 
488
                                if (Endian::LittleToMachine(fmt.format.wFormatTag) == 3)
 
489
                                        throw _T("Wave64 audio provider: File is IEEE 32 bit float format which isn't supported. Bug the developers if this matters.");
 
490
                                if (Endian::LittleToMachine(fmt.format.wFormatTag) != 1)
 
491
                                        throw _T("Wave64 audio provider: Can't use file, not PCM encoding");
 
492
 
 
493
                                // Set stuff inherited from the AudioProvider class
 
494
                                sample_rate = Endian::LittleToMachine(fmt.format.nSamplesPerSec);
 
495
                                channels = Endian::LittleToMachine(fmt.format.nChannels);
 
496
                                bytes_per_sample = (Endian::LittleToMachine(fmt.format.wBitsPerSample) + 7) / 8; // round up to nearest whole byte
 
497
                        }
 
498
 
 
499
                        else if (CheckGuid(chunk_guid, w64Guiddata)) {
 
500
                                if (!got_fmt_header)
 
501
                                        throw _T("Wave64 audio provider: Found 'data' chunk before 'fmt ' chunk, file is invalid.");
 
502
 
 
503
                                int64_t samples = chunk_size / bytes_per_sample;
 
504
                                int64_t frames = samples / channels;
 
505
 
 
506
                                IndexPoint ip;
 
507
                                ip.start_sample = num_samples;
 
508
                                ip.num_samples = frames;
 
509
                                ip.start_byte = filepos;
 
510
                                index_points.push_back(ip);
 
511
 
 
512
                                num_samples += frames;
 
513
                        }
 
514
 
 
515
                        // Update counters
 
516
                        // Make sure they're 64 bit aligned
 
517
                        data_left -= (chunk_size + 7) & ~7;
 
518
                        filepos += (chunk_size + 7) & ~7;
 
519
                }
 
520
        }
 
521
 
 
522
 
 
523
        bool AreSamplesNativeEndian()
 
524
        {
 
525
                // 8 bit samples don't consider endianness
 
526
                if (bytes_per_sample < 2) return true;
 
527
                // Otherwise test whether we're little endian
 
528
                uint32_t testvalue = 0x008800ff;
 
529
                return testvalue == Endian::LittleToMachine(testvalue);
 
530
        }
 
531
};
 
532
 
 
533
 
 
534
AudioProvider *CreatePCMAudioProvider(const wxString &filename)
 
535
{
 
536
        AudioProvider *provider = 0;
 
537
 
 
538
        // Try Microsoft/IBM RIFF WAV
 
539
        try {
 
540
                provider = new RiffWavPCMAudioProvider(filename);
 
541
                // don't bother trying with anything else if this works
 
542
                return provider;
 
543
        }
 
544
        catch (const wxChar *) {
 
545
                provider = 0;
 
546
        }
 
547
 
 
548
        // Try Sony Wave64
 
549
        try {
 
550
                provider = new Wave64AudioProvider(filename);
 
551
                return provider;
 
552
        }
 
553
        catch (const wxChar *) {
 
554
                provider = 0;
 
555
        }
 
556
 
 
557
        // no providers could be created
 
558
        return NULL;
 
559
}