Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/psx/mednadisc/audioreader.cpp
2 views
1
/* Mednafen - Multi-system Emulator
2
*
3
* This program is free software; you can redistribute it and/or modify
4
* it under the terms of the GNU General Public License as published by
5
* the Free Software Foundation; either version 2 of the License, or
6
* (at your option) any later version.
7
*
8
* This program is distributed in the hope that it will be useful,
9
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
* GNU General Public License for more details.
12
*
13
* You should have received a copy of the GNU General Public License
14
* along with this program; if not, write to the Free Software
15
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16
*/
17
18
// AR_Open(), and AudioReader, will NOT take "ownership" of the Stream object(IE it won't ever delete it). Though it does assume it has exclusive access
19
// to it for as long as the AudioReader object exists.
20
21
// Don't allow exceptions to propagate into the vorbis/musepack/etc. libraries, as it could easily leave the state of the library's decoder "object" in an
22
// inconsistent state, which would cause all sorts of unfun when we try to destroy it while handling the exception farther up.
23
24
#include "../mednafen.h"
25
#include "audioreader.h"
26
27
#include <sys/types.h>
28
#include <sys/stat.h>
29
30
#include "../tremor/ivorbisfile.h"
31
#include "../mpcdec/mpcdec.h"
32
33
#ifdef HAVE_LIBSNDFILE
34
#include <sndfile.h>
35
#endif
36
37
#ifdef HAVE_OPUSFILE
38
#include "audioreader_opus.h"
39
#endif
40
41
#include <string.h>
42
#include <errno.h>
43
#include <time.h>
44
45
#include "../general.h"
46
#include "../endian.h"
47
48
AudioReader::AudioReader() : LastReadPos(0)
49
{
50
51
}
52
53
AudioReader::~AudioReader()
54
{
55
56
}
57
58
int64 AudioReader::Read_(int16 *buffer, int64 frames)
59
{
60
abort();
61
return(false);
62
}
63
64
bool AudioReader::Seek_(int64 frame_offset)
65
{
66
abort();
67
return(false);
68
}
69
70
int64 AudioReader::FrameCount(void)
71
{
72
abort();
73
return(0);
74
}
75
76
/*
77
**
78
**
79
**
80
**
81
**
82
**
83
**
84
**
85
**
86
*/
87
88
class OggVorbisReader : public AudioReader
89
{
90
public:
91
OggVorbisReader(Stream *fp);
92
~OggVorbisReader();
93
94
int64 Read_(int16 *buffer, int64 frames);
95
bool Seek_(int64 frame_offset);
96
int64 FrameCount(void);
97
98
private:
99
OggVorbis_File ovfile;
100
Stream *fw;
101
};
102
103
104
static size_t iov_read_func(void *ptr, size_t size, size_t nmemb, void *user_data)
105
{
106
Stream *fw = (Stream*)user_data;
107
108
if(!size)
109
return(0);
110
111
try
112
{
113
return fw->read(ptr, size * nmemb, false) / size;
114
}
115
catch(...)
116
{
117
return(0);
118
}
119
}
120
121
static int iov_seek_func(void *user_data, ogg_int64_t offset, int whence)
122
{
123
Stream *fw = (Stream*)user_data;
124
125
try
126
{
127
fw->seek(offset, whence);
128
return(0);
129
}
130
catch(...)
131
{
132
return(-1);
133
}
134
}
135
136
static int iov_close_func(void *user_data)
137
{
138
Stream *fw = (Stream*)user_data;
139
140
try
141
{
142
fw->close();
143
return(0);
144
}
145
catch(...)
146
{
147
return EOF;
148
}
149
}
150
151
static long iov_tell_func(void *user_data)
152
{
153
Stream *fw = (Stream*)user_data;
154
155
try
156
{
157
return fw->tell();
158
}
159
catch(...)
160
{
161
return(-1);
162
}
163
}
164
165
OggVorbisReader::OggVorbisReader(Stream *fp) : fw(fp)
166
{
167
ov_callbacks cb;
168
169
memset(&cb, 0, sizeof(cb));
170
cb.read_func = iov_read_func;
171
cb.seek_func = iov_seek_func;
172
cb.close_func = iov_close_func;
173
cb.tell_func = iov_tell_func;
174
175
fp->seek(0, SEEK_SET);
176
if(ov_open_callbacks(fp, &ovfile, NULL, 0, cb))
177
throw(0);
178
}
179
180
OggVorbisReader::~OggVorbisReader()
181
{
182
ov_clear(&ovfile);
183
}
184
185
int64 OggVorbisReader::Read_(int16 *buffer, int64 frames)
186
{
187
uint8 *tw_buf = (uint8 *)buffer;
188
int cursection = 0;
189
long toread = frames * sizeof(int16) * 2;
190
191
while(toread > 0)
192
{
193
long didread = ov_read(&ovfile, (char*)tw_buf, toread, &cursection);
194
195
if(didread == 0)
196
break;
197
198
tw_buf = (uint8 *)tw_buf + didread;
199
toread -= didread;
200
}
201
202
return(frames - toread / sizeof(int16) / 2);
203
}
204
205
bool OggVorbisReader::Seek_(int64 frame_offset)
206
{
207
ov_pcm_seek(&ovfile, frame_offset);
208
return(true);
209
}
210
211
int64 OggVorbisReader::FrameCount(void)
212
{
213
return(ov_pcm_total(&ovfile, -1));
214
}
215
216
class MPCReader : public AudioReader
217
{
218
public:
219
MPCReader(Stream *fp);
220
~MPCReader();
221
222
int64 Read_(int16 *buffer, int64 frames);
223
bool Seek_(int64 frame_offset);
224
int64 FrameCount(void);
225
226
private:
227
mpc_reader reader;
228
mpc_demux *demux;
229
mpc_streaminfo si;
230
231
MPC_SAMPLE_FORMAT MPCBuffer[MPC_DECODER_BUFFER_LENGTH];
232
233
uint32 MPCBufferIn;
234
uint32 MPCBufferOffs;
235
Stream *fw;
236
};
237
238
239
/// Reads size bytes of data into buffer at ptr.
240
static mpc_int32_t impc_read(mpc_reader *p_reader, void *ptr, mpc_int32_t size)
241
{
242
Stream *fw = (Stream*)(p_reader->data);
243
244
try
245
{
246
return fw->read(ptr, size, false);
247
}
248
catch(...)
249
{
250
return(MPC_STATUS_FAIL);
251
}
252
}
253
254
/// Seeks to byte position offset.
255
static mpc_bool_t impc_seek(mpc_reader *p_reader, mpc_int32_t offset)
256
{
257
Stream *fw = (Stream*)(p_reader->data);
258
259
try
260
{
261
fw->seek(offset, SEEK_SET);
262
return(MPC_TRUE);
263
}
264
catch(...)
265
{
266
return(MPC_FALSE);
267
}
268
}
269
270
/// Returns the current byte offset in the stream.
271
static mpc_int32_t impc_tell(mpc_reader *p_reader)
272
{
273
Stream *fw = (Stream*)(p_reader->data);
274
275
try
276
{
277
return fw->tell();
278
}
279
catch(...)
280
{
281
return(MPC_STATUS_FAIL);
282
}
283
}
284
285
/// Returns the total length of the source stream, in bytes.
286
static mpc_int32_t impc_get_size(mpc_reader *p_reader)
287
{
288
Stream *fw = (Stream*)(p_reader->data);
289
290
try
291
{
292
return fw->size();
293
}
294
catch(...)
295
{
296
return(MPC_STATUS_FAIL);
297
}
298
}
299
300
/// True if the stream is a seekable stream.
301
static mpc_bool_t impc_canseek(mpc_reader *p_reader)
302
{
303
return(MPC_TRUE);
304
}
305
306
MPCReader::MPCReader(Stream *fp) : fw(fp)
307
{
308
fp->seek(0, SEEK_SET);
309
310
demux = NULL;
311
memset(&si, 0, sizeof(si));
312
memset(MPCBuffer, 0, sizeof(MPCBuffer));
313
MPCBufferOffs = 0;
314
MPCBufferIn = 0;
315
316
memset(&reader, 0, sizeof(reader));
317
reader.read = impc_read;
318
reader.seek = impc_seek;
319
reader.tell = impc_tell;
320
reader.get_size = impc_get_size;
321
reader.canseek = impc_canseek;
322
reader.data = (void*)fp;
323
324
if(!(demux = mpc_demux_init(&reader)))
325
{
326
throw(0);
327
}
328
mpc_demux_get_info(demux, &si);
329
330
if(si.channels != 2)
331
{
332
mpc_demux_exit(demux);
333
demux = NULL;
334
throw MDFN_Error(0, _("MusePack stream has wrong number of channels(%u); the correct number is 2."), si.channels);
335
}
336
337
if(si.sample_freq != 44100)
338
{
339
mpc_demux_exit(demux);
340
demux = NULL;
341
throw MDFN_Error(0, _("MusePack stream has wrong samplerate(%u Hz); the correct samplerate is 44100 Hz."), si.sample_freq);
342
}
343
}
344
345
MPCReader::~MPCReader()
346
{
347
if(demux)
348
{
349
mpc_demux_exit(demux);
350
demux = NULL;
351
}
352
}
353
354
int64 MPCReader::Read_(int16 *buffer, int64 frames)
355
{
356
mpc_status err;
357
int16 *cowbuf = (int16 *)buffer;
358
int32 toread = frames * 2;
359
360
while(toread > 0)
361
{
362
int32 tmplen;
363
364
if(!MPCBufferIn)
365
{
366
mpc_frame_info fi;
367
memset(&fi, 0, sizeof(fi));
368
369
fi.buffer = MPCBuffer;
370
if((err = mpc_demux_decode(demux, &fi)) < 0 || fi.bits == -1)
371
return(frames - toread / 2);
372
373
MPCBufferIn = fi.samples * 2;
374
MPCBufferOffs = 0;
375
}
376
377
tmplen = MPCBufferIn;
378
379
if(tmplen >= toread)
380
tmplen = toread;
381
382
for(int x = 0; x < tmplen; x++)
383
{
384
#ifdef MPC_FIXED_POINT
385
int32 samp = MPCBuffer[MPCBufferOffs + x] >> MPC_FIXED_POINT_FRACTPART;
386
#else
387
#warning Floating-point MPC decoding path not tested.
388
int32 samp = (int32)(MPCBuffer[MPCBufferOffs + x] * 32767);
389
#endif
390
if(samp < -32768)
391
samp = -32768;
392
393
if(samp > 32767)
394
samp = 32767;
395
396
*cowbuf = (int16)samp;
397
cowbuf++;
398
}
399
400
MPCBufferOffs += tmplen;
401
toread -= tmplen;
402
MPCBufferIn -= tmplen;
403
}
404
405
return(frames - toread / 2);
406
}
407
408
bool MPCReader::Seek_(int64 frame_offset)
409
{
410
MPCBufferOffs = 0;
411
MPCBufferIn = 0;
412
413
if(mpc_demux_seek_sample(demux, frame_offset) < 0)
414
return(false);
415
416
return(true);
417
}
418
419
int64 MPCReader::FrameCount(void)
420
{
421
return(mpc_streaminfo_get_length_samples(&si));
422
}
423
424
/*
425
**
426
**
427
**
428
**
429
**
430
**
431
**
432
**
433
**
434
*/
435
436
#ifdef HAVE_LIBSNDFILE
437
class SFReader : public AudioReader
438
{
439
public:
440
441
SFReader(Stream *fp);
442
~SFReader();
443
444
int64 Read_(int16 *buffer, int64 frames);
445
bool Seek_(int64 frame_offset);
446
int64 FrameCount(void);
447
448
private:
449
SNDFILE *sf;
450
SF_INFO sfinfo;
451
SF_VIRTUAL_IO sfvf;
452
453
Stream *fw;
454
};
455
456
static sf_count_t isf_get_filelen(void *user_data)
457
{
458
Stream *fw = (Stream*)user_data;
459
460
try
461
{
462
return fw->size();
463
}
464
catch(...)
465
{
466
return(-1);
467
}
468
}
469
470
static sf_count_t isf_seek(sf_count_t offset, int whence, void *user_data)
471
{
472
Stream *fw = (Stream*)user_data;
473
474
try
475
{
476
//printf("Seek: offset=%lld, whence=%lld\n", (long long)offset, (long long)whence);
477
478
fw->seek(offset, whence);
479
return fw->tell();
480
}
481
catch(...)
482
{
483
//printf(" SEEK FAILED\n");
484
return(-1);
485
}
486
}
487
488
static sf_count_t isf_read(void *ptr, sf_count_t count, void *user_data)
489
{
490
Stream *fw = (Stream*)user_data;
491
492
try
493
{
494
sf_count_t ret = fw->read(ptr, count, false);
495
496
//printf("Read: count=%lld, ret=%lld\n", (long long)count, (long long)ret);
497
498
return ret;
499
}
500
catch(...)
501
{
502
//printf(" READ FAILED\n");
503
return(0);
504
}
505
}
506
507
static sf_count_t isf_write(const void *ptr, sf_count_t count, void *user_data)
508
{
509
return(0);
510
}
511
512
static sf_count_t isf_tell(void *user_data)
513
{
514
Stream *fw = (Stream*)user_data;
515
516
try
517
{
518
return fw->tell();
519
}
520
catch(...)
521
{
522
return(-1);
523
}
524
}
525
526
SFReader::SFReader(Stream *fp) : fw(fp)
527
{
528
fp->seek(0, SEEK_SET);
529
530
memset(&sfvf, 0, sizeof(sfvf));
531
sfvf.get_filelen = isf_get_filelen;
532
sfvf.seek = isf_seek;
533
sfvf.read = isf_read;
534
sfvf.write = isf_write;
535
sfvf.tell = isf_tell;
536
537
memset(&sfinfo, 0, sizeof(sfinfo));
538
if(!(sf = sf_open_virtual(&sfvf, SFM_READ, &sfinfo, (void*)fp)))
539
throw(0);
540
}
541
542
SFReader::~SFReader()
543
{
544
sf_close(sf);
545
}
546
547
int64 SFReader::Read_(int16 *buffer, int64 frames)
548
{
549
return(sf_read_short(sf, (short*)buffer, frames * 2) / 2);
550
}
551
552
bool SFReader::Seek_(int64 frame_offset)
553
{
554
// FIXME error condition
555
if(sf_seek(sf, frame_offset, SEEK_SET) != frame_offset)
556
return(false);
557
return(true);
558
}
559
560
int64 SFReader::FrameCount(void)
561
{
562
return(sfinfo.frames);
563
}
564
565
#endif
566
567
568
AudioReader *AR_Open(Stream *fp)
569
{
570
try
571
{
572
return new MPCReader(fp);
573
}
574
catch(int i)
575
{
576
}
577
578
#ifdef HAVE_OPUSFILE
579
try
580
{
581
return new OpusReader(fp);
582
}
583
catch(int i)
584
{
585
}
586
#endif
587
588
try
589
{
590
return new OggVorbisReader(fp);
591
}
592
catch(int i)
593
{
594
}
595
596
#ifdef HAVE_LIBSNDFILE
597
try
598
{
599
return new SFReader(fp);
600
}
601
catch(int i)
602
{
603
}
604
#endif
605
606
return(NULL);
607
}
608
609
610