Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/psx/mednadisc/cdrom/CDAFReader_MPC.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
#include <mednafen/mednafen.h>
19
#include "CDAFReader.h"
20
#include "CDAFReader_MPC.h"
21
22
#if 0
23
#include <mpc/mpcdec.h>
24
#else
25
#include <mednafen/mpcdec/mpcdec.h>
26
#endif
27
28
class CDAFReader_MPC final : public CDAFReader
29
{
30
public:
31
CDAFReader_MPC(Stream *fp);
32
~CDAFReader_MPC();
33
34
uint64 Read_(int16 *buffer, uint64 frames) override;
35
bool Seek_(uint64 frame_offset) override;
36
uint64 FrameCount(void) override;
37
38
private:
39
mpc_reader reader;
40
mpc_demux *demux;
41
mpc_streaminfo si;
42
43
MPC_SAMPLE_FORMAT MPCBuffer[MPC_DECODER_BUFFER_LENGTH];
44
45
uint32 MPCBufferIn;
46
uint32 MPCBufferOffs;
47
Stream *fw;
48
};
49
50
51
/// Reads size bytes of data into buffer at ptr.
52
static mpc_int32_t impc_read(mpc_reader *p_reader, void *ptr, mpc_int32_t size)
53
{
54
Stream *fw = (Stream*)(p_reader->data);
55
56
try
57
{
58
return fw->read(ptr, size, false);
59
}
60
catch(...)
61
{
62
return(MPC_STATUS_FAIL);
63
}
64
}
65
66
/// Seeks to byte position offset.
67
static mpc_bool_t impc_seek(mpc_reader *p_reader, mpc_int32_t offset)
68
{
69
Stream *fw = (Stream*)(p_reader->data);
70
71
try
72
{
73
fw->seek(offset, SEEK_SET);
74
return(MPC_TRUE);
75
}
76
catch(...)
77
{
78
return(MPC_FALSE);
79
}
80
}
81
82
/// Returns the current byte offset in the stream.
83
static mpc_int32_t impc_tell(mpc_reader *p_reader)
84
{
85
Stream *fw = (Stream*)(p_reader->data);
86
87
try
88
{
89
return fw->tell();
90
}
91
catch(...)
92
{
93
return(MPC_STATUS_FAIL);
94
}
95
}
96
97
/// Returns the total length of the source stream, in bytes.
98
static mpc_int32_t impc_get_size(mpc_reader *p_reader)
99
{
100
Stream *fw = (Stream*)(p_reader->data);
101
102
try
103
{
104
return fw->size();
105
}
106
catch(...)
107
{
108
return(MPC_STATUS_FAIL);
109
}
110
}
111
112
/// True if the stream is a seekable stream.
113
static mpc_bool_t impc_canseek(mpc_reader *p_reader)
114
{
115
return(MPC_TRUE);
116
}
117
118
CDAFReader_MPC::CDAFReader_MPC(Stream *fp) : fw(fp)
119
{
120
demux = NULL;
121
memset(&si, 0, sizeof(si));
122
memset(MPCBuffer, 0, sizeof(MPCBuffer));
123
MPCBufferOffs = 0;
124
MPCBufferIn = 0;
125
126
memset(&reader, 0, sizeof(reader));
127
reader.read = impc_read;
128
reader.seek = impc_seek;
129
reader.tell = impc_tell;
130
reader.get_size = impc_get_size;
131
reader.canseek = impc_canseek;
132
reader.data = (void*)fp;
133
134
if(!(demux = mpc_demux_init(&reader)))
135
{
136
throw(0);
137
}
138
mpc_demux_get_info(demux, &si);
139
140
if(si.channels != 2)
141
{
142
mpc_demux_exit(demux);
143
demux = NULL;
144
throw MDFN_Error(0, _("MusePack stream has wrong number of channels(%u); the correct number is 2."), si.channels);
145
}
146
147
if(si.sample_freq != 44100)
148
{
149
mpc_demux_exit(demux);
150
demux = NULL;
151
throw MDFN_Error(0, _("MusePack stream has wrong samplerate(%u Hz); the correct samplerate is 44100 Hz."), si.sample_freq);
152
}
153
}
154
155
CDAFReader_MPC::~CDAFReader_MPC()
156
{
157
if(demux)
158
{
159
mpc_demux_exit(demux);
160
demux = NULL;
161
}
162
}
163
164
uint64 CDAFReader_MPC::Read_(int16 *buffer, uint64 frames)
165
{
166
mpc_status err;
167
int16 *cowbuf = (int16 *)buffer;
168
int32 toread = frames * 2;
169
170
while(toread > 0)
171
{
172
int32 tmplen;
173
174
if(!MPCBufferIn)
175
{
176
mpc_frame_info fi;
177
memset(&fi, 0, sizeof(fi));
178
179
fi.buffer = MPCBuffer;
180
if((err = mpc_demux_decode(demux, &fi)) < 0 || fi.bits == -1)
181
return(frames - toread / 2);
182
183
MPCBufferIn = fi.samples * 2;
184
MPCBufferOffs = 0;
185
}
186
187
tmplen = MPCBufferIn;
188
189
if(tmplen >= toread)
190
tmplen = toread;
191
192
for(int x = 0; x < tmplen; x++)
193
{
194
#ifdef MPC_FIXED_POINT
195
int32 samp = MPCBuffer[MPCBufferOffs + x] >> MPC_FIXED_POINT_FRACTPART;
196
#else
197
#warning Floating-point MPC decoding path not tested.
198
int32 samp = (int32)(MPCBuffer[MPCBufferOffs + x] * 32767);
199
#endif
200
if(samp < -32768)
201
samp = -32768;
202
203
if(samp > 32767)
204
samp = 32767;
205
206
*cowbuf = (int16)samp;
207
cowbuf++;
208
}
209
210
MPCBufferOffs += tmplen;
211
toread -= tmplen;
212
MPCBufferIn -= tmplen;
213
}
214
215
return(frames - toread / 2);
216
}
217
218
bool CDAFReader_MPC::Seek_(uint64 frame_offset)
219
{
220
MPCBufferOffs = 0;
221
MPCBufferIn = 0;
222
223
if(mpc_demux_seek_sample(demux, frame_offset) < 0)
224
return(false);
225
226
return(true);
227
}
228
229
uint64 CDAFReader_MPC::FrameCount(void)
230
{
231
return(mpc_streaminfo_get_length_samples(&si));
232
}
233
234
235
CDAFReader* CDAFR_MPC_Open(Stream* fp)
236
{
237
return new CDAFReader_MPC(fp);
238
}
239
240