1
2 /*
3 * REminiscence - Flashback interpreter
4 * Copyright (C) 2005-2019 Gregory Montoir (cyx@users.sourceforge.net)
5 */
6
7 #ifdef USE_TREMOR
8 #include <tremor/ivorbisfile.h>
9 #endif
10 #ifdef USE_STB_VORBIS
11 #include "stb_vorbis.c"
12 #endif
13 #include "file.h"
14 #include "mixer.h"
15 #include "ogg_player.h"
16 #include "util.h"
17
18 #ifdef USE_TREMOR
19 struct VorbisFile: File {
20 uint32_t offset;
21
readHelperVorbisFile22 static size_t readHelper(void *ptr, size_t size, size_t nmemb, void *datasource) {
23 VorbisFile *vf = (VorbisFile *)datasource;
24 if (size != 0 && nmemb != 0) {
25 const int n = vf->read(ptr, size * nmemb);
26 if (n > 0) {
27 vf->offset += n;
28 return n / size;
29 }
30 }
31 return 0;
32 }
seekHelperVorbisFile33 static int seekHelper(void *datasource, ogg_int64_t offset, int whence) {
34 VorbisFile *vf = (VorbisFile *)datasource;
35 switch (whence) {
36 case SEEK_SET:
37 vf->offset = offset;
38 break;
39 case SEEK_CUR:
40 vf->offset += offset;
41 break;
42 case SEEK_END:
43 vf->offset = vf->size() + offset;
44 break;
45 }
46 vf->seek(vf->offset);
47 return 0;
48 }
closeHelperVorbisFile49 static int closeHelper(void *datasource) {
50 VorbisFile *vf = (VorbisFile *)datasource;
51 vf->close();
52 delete vf;
53 return 0;
54 }
tellHelperVorbisFile55 static long tellHelper(void *datasource) {
56 VorbisFile *vf = (VorbisFile *)datasource;
57 return vf->offset;
58 }
59 };
60
61 struct OggDecoder_impl {
OggDecoder_implOggDecoder_impl62 OggDecoder_impl()
63 : _open(false), _readBuf(0), _readBufSize(0) {
64 }
~OggDecoder_implOggDecoder_impl65 ~OggDecoder_impl() {
66 free(_readBuf);
67 _readBuf = 0;
68 if (_open) {
69 ov_clear(&_ovf);
70 }
71 }
72
loadOggDecoder_impl73 bool load(const char *name, FileSystem *fs, int mixerSampleRate) {
74 if (!_f.open(name, "rb", fs)) {
75 return false;
76 }
77 _f.offset = 0;
78 ov_callbacks ovcb;
79 ovcb.read_func = VorbisFile::readHelper;
80 ovcb.seek_func = VorbisFile::seekHelper;
81 ovcb.close_func = VorbisFile::closeHelper;
82 ovcb.tell_func = VorbisFile::tellHelper;
83 if (ov_open_callbacks(&_f, &_ovf, 0, 0, ovcb) < 0) {
84 warning("Invalid .ogg file");
85 return false;
86 }
87 _open = true;
88 vorbis_info *vi = ov_info(&_ovf, -1);
89 if ((vi->channels != 1 && vi->channels != 2) || vi->rate != mixerSampleRate) {
90 warning("Unhandled ogg/pcm format ch %d rate %d", vi->channels, vi->rate);
91 return false;
92 }
93 _channels = vi->channels;
94 return true;
95 }
readOggDecoder_impl96 int read(int16_t *dst, int samples) {
97 int size = samples * _channels * sizeof(int16_t);
98 if (size > _readBufSize) {
99 _readBufSize = size;
100 free(_readBuf);
101 _readBuf = (int16_t *)malloc(_readBufSize);
102 if (!_readBuf) {
103 return 0;
104 }
105 }
106 int count = 0;
107 while (size > 0) {
108 const int len = ov_read(&_ovf, (char *)_readBuf, size, 0);
109 if (len < 0) {
110 // error in decoder
111 return count;
112 } else if (len == 0) {
113 // loop
114 ov_raw_seek(&_ovf, 0);
115 continue;
116 }
117 assert((len & 1) == 0);
118 switch (_channels) {
119 case 2:
120 assert((len & 3) == 0);
121 for (int i = 0; i < len / 2; i += 2) {
122 const int16_t s16 = (_readBuf[i] + _readBuf[i + 1]) / 2;
123 *dst = ADDC_S16(*dst, s16);
124 ++dst;
125 }
126 break;
127 case 1:
128 for (int i = 0; i < len / 2; ++i) {
129 *dst = ADDC_S16(*dst, _readBuf[i]);
130 ++dst;
131 }
132 break;
133 }
134 size -= len;
135 count += len;
136 }
137 assert(size == 0);
138 return count;
139 }
140
141 VorbisFile _f;
142 OggVorbis_File _ovf;
143 int _channels;
144 bool _open;
145 int16_t *_readBuf;
146 int _readBufSize;
147 };
148 #endif
149
150 #ifdef USE_STB_VORBIS
151 static const int kMusicVolume = 192;
152
153 struct OggDecoder_impl {
OggDecoder_implOggDecoder_impl154 OggDecoder_impl()
155 : _v(0) {
156 }
~OggDecoder_implOggDecoder_impl157 ~OggDecoder_impl() {
158 if (_v) {
159 stb_vorbis_close(_v);
160 _v = 0;
161 }
162 }
loadOggDecoder_impl163 bool load(const char *name, FileSystem *fs, int mixerSampleRate) {
164 if (!_f.open(name, "rb", fs)) {
165 return false;
166 }
167 _count = _f.read(_buffer, sizeof(_buffer));
168 if (_count > 0) {
169 int bytes = 0;
170 int error = 0;
171 _v = stb_vorbis_open_pushdata(_buffer, _count, &bytes, &error, 0);
172 if (_v) {
173 _offset = bytes;
174 stb_vorbis_info info = stb_vorbis_get_info(_v);
175 if (info.channels != 2 || (int)info.sample_rate != mixerSampleRate) {
176 warning("Unhandled ogg/pcm format ch %d rate %d", info.channels, info.sample_rate);
177 return false;
178 }
179 _decodedSamplesLen = 0;
180 return true;
181 }
182 }
183 return false;
184 }
readOggDecoder_impl185 int read(int16_t *dst, int samples) {
186 int total = 0;
187 if (_decodedSamplesLen != 0) {
188 const int len = MIN(_decodedSamplesLen, samples);
189 for (int i = 0; i < len; ++i) {
190 const int sample = (_decodedSamples[0][i] + _decodedSamples[1][i]) / 2;
191 *dst = ADDC_S16(*dst, ((sample * kMusicVolume) >> 8));
192 ++dst;
193 }
194 total += len;
195 _decodedSamplesLen -= len;
196 }
197 while (total < samples) {
198 int channels = 0;
199 float **outputs;
200 int count;
201 int bytes = stb_vorbis_decode_frame_pushdata(_v, _buffer + _offset, _count - _offset, &channels, &outputs, &count);
202 if (bytes == 0) {
203 if (_offset != _count) {
204 memmove(_buffer, _buffer + _offset, _count - _offset);
205 _offset = _count - _offset;
206 } else {
207 _offset = 0;
208 }
209 _count = sizeof(_buffer) - _offset;
210 bytes = _f.read(_buffer + _offset, _count);
211 if (bytes < 0) {
212 break;
213 }
214 if (bytes == 0) {
215 // rewind
216 _f.seek(0);
217 _count = _f.read(_buffer, sizeof(_buffer));
218 stb_vorbis_flush_pushdata(_v);
219 } else {
220 _count = _offset + bytes;
221 }
222 _offset = 0;
223 continue;
224 }
225 _offset += bytes;
226 if (channels == 2) {
227 const int remain = samples - total;
228 const int len = MIN(count, remain);
229 for (int i = 0; i < len; ++i) {
230 const int l = int(outputs[0][i] * 32768 + .5);
231 const int r = int(outputs[1][i] * 32768 + .5);
232 const int sample = (l + r) / 2;
233 *dst = ADDC_S16(*dst, ((sample * kMusicVolume) >> 8));
234 ++dst;
235 }
236 if (count > remain) {
237 _decodedSamplesLen = count - remain;
238 assert(_decodedSamplesLen < 1024);
239 for (int i = 0; i < _decodedSamplesLen; ++i) {
240 _decodedSamples[0][i] = int(outputs[0][len + i] * 32768 + .5);
241 _decodedSamples[1][i] = int(outputs[1][len + i] * 32768 + .5);
242 }
243 total = samples;
244 break;
245 }
246 } else {
247 warning("Invalid decoded data channels %d count %d", channels, count);
248 }
249 total += count;
250 }
251 return total;
252 }
253
254 uint8_t _buffer[8192];
255 int16_t _decodedSamples[2][1024];
256 int _decodedSamplesLen;
257 uint32_t _offset, _count;
258 stb_vorbis *_v;
259 File _f;
260 };
261 #endif
262
OggPlayer(Mixer * mixer,FileSystem * fs)263 OggPlayer::OggPlayer(Mixer *mixer, FileSystem *fs)
264 : _mix(mixer), _fs(fs) {
265 _impl = new OggDecoder_impl;
266 }
267
~OggPlayer()268 OggPlayer::~OggPlayer() {
269 delete _impl;
270 _impl = 0;
271 }
272
playTrack(int num)273 bool OggPlayer::playTrack(int num) {
274 stopTrack();
275 char buf[16];
276 snprintf(buf, sizeof(buf), "track%02d.ogg", num);
277 if (_impl->load(buf, _fs, _mix->getSampleRate())) {
278 debug(DBG_INFO, "Playing '%s'", buf);
279 _mix->setPremixHook(mixCallback, this);
280 return true;
281 }
282 return false;
283 }
284
stopTrack()285 void OggPlayer::stopTrack() {
286 if (_impl) {
287 _mix->setPremixHook(0, 0);
288 }
289 }
290
pauseTrack()291 void OggPlayer::pauseTrack() {
292 if (_impl) {
293 _mix->setPremixHook(0, 0);
294 }
295 }
296
resumeTrack()297 void OggPlayer::resumeTrack() {
298 if (_impl) {
299 _mix->setPremixHook(mixCallback, this);
300 }
301 }
302
mix(int16_t * buf,int len)303 bool OggPlayer::mix(int16_t *buf, int len) {
304 if (_impl) {
305 return _impl->read(buf, len) != 0;
306 }
307 return false;
308 }
309
mixCallback(void * param,int16_t * buf,int len)310 bool OggPlayer::mixCallback(void *param, int16_t *buf, int len) {
311 return ((OggPlayer *)param)->mix(buf, len);
312 }
313
314