diff options
Diffstat (limited to 'src/audio')
-rw-r--r-- | src/audio/player.c | 111 |
1 files changed, 100 insertions, 11 deletions
diff --git a/src/audio/player.c b/src/audio/player.c index b2a6ae15..ef238378 100644 --- a/src/audio/player.c +++ b/src/audio/player.c | |||
@@ -30,6 +30,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ | |||
30 | #include <the_Foundation/thread.h> | 30 | #include <the_Foundation/thread.h> |
31 | #include <SDL_audio.h> | 31 | #include <SDL_audio.h> |
32 | 32 | ||
33 | #if defined (LAGRANGE_ENABLE_MPG123) | ||
34 | # include <mpg123.h> | ||
35 | #endif | ||
36 | |||
33 | /*----------------------------------------------------------------------------------------------*/ | 37 | /*----------------------------------------------------------------------------------------------*/ |
34 | 38 | ||
35 | iDeclareType(ContentSpec) | 39 | iDeclareType(ContentSpec) |
@@ -68,6 +72,9 @@ struct Impl_Decoder { | |||
68 | uint64_t currentSample; | 72 | uint64_t currentSample; |
69 | uint64_t totalSamples; /* zero if unknown */ | 73 | uint64_t totalSamples; /* zero if unknown */ |
70 | stb_vorbis * vorbis; | 74 | stb_vorbis * vorbis; |
75 | #if defined (LAGRANGE_ENABLE_MPG123) | ||
76 | mpg123_handle * mpeg; | ||
77 | #endif | ||
71 | }; | 78 | }; |
72 | 79 | ||
73 | enum iDecoderStatus { | 80 | enum iDecoderStatus { |
@@ -155,8 +162,18 @@ static enum iDecoderStatus decodeWav_Decoder_(iDecoder *d, iRanges inputRange) { | |||
155 | return ok_DecoderStatus; | 162 | return ok_DecoderStatus; |
156 | } | 163 | } |
157 | 164 | ||
158 | static enum iDecoderStatus decodeVorbis_Decoder_(iDecoder *d, iRanges inputRange) { | 165 | static void writePending_Decoder_(iDecoder *d) { |
159 | iUnused(inputRange); | 166 | /* Write as much as we can. */ |
167 | lock_Mutex(&d->outputMutex); | ||
168 | size_t avail = vacancy_SampleBuf(&d->output); | ||
169 | size_t n = iMin(avail, size_Array(&d->pendingOutput)); | ||
170 | write_SampleBuf(&d->output, constData_Array(&d->pendingOutput), n); | ||
171 | removeN_Array(&d->pendingOutput, 0, n); | ||
172 | unlock_Mutex(&d->outputMutex); | ||
173 | d->currentSample += n; | ||
174 | } | ||
175 | |||
176 | static enum iDecoderStatus decodeVorbis_Decoder_(iDecoder *d) { | ||
160 | const iBlock *input = &d->input->data; | 177 | const iBlock *input = &d->input->data; |
161 | if (!d->vorbis) { | 178 | if (!d->vorbis) { |
162 | lock_Mutex(&d->input->mtx); | 179 | lock_Mutex(&d->input->mtx); |
@@ -213,14 +230,47 @@ static enum iDecoderStatus decodeVorbis_Decoder_(iDecoder *d, iRanges inputRange | |||
213 | } | 230 | } |
214 | } | 231 | } |
215 | } | 232 | } |
216 | /* Write as much as we can. */ | 233 | writePending_Decoder_(d); |
217 | lock_Mutex(&d->outputMutex); | 234 | return status; |
218 | size_t avail = vacancy_SampleBuf(&d->output); | 235 | } |
219 | size_t n = iMin(avail, size_Array(&d->pendingOutput)); | 236 | |
220 | write_SampleBuf(&d->output, constData_Array(&d->pendingOutput), n); | 237 | enum iDecoderStatus decodeMpeg_Decoder_(iDecoder *d) { |
221 | removeN_Array(&d->pendingOutput, 0, n); | 238 | enum iDecoderStatus status = ok_DecoderStatus; |
222 | unlock_Mutex(&d->outputMutex); | 239 | #if defined (LAGRANGE_ENABLE_MPG123) |
223 | d->currentSample += n; | 240 | const iBlock *input = &d->input->data; |
241 | if (!d->mpeg) { | ||
242 | d->mpeg = mpg123_new(NULL, NULL); | ||
243 | mpg123_format_none(d->mpeg); | ||
244 | mpg123_format(d->mpeg, d->outputFreq, d->output.numChannels, MPG123_ENC_SIGNED_16); | ||
245 | mpg123_open_feed(d->mpeg); | ||
246 | lock_Mutex(&d->input->mtx); | ||
247 | mpg123_feed(d->mpeg, constData_Block(input), size_Block(input)); | ||
248 | unlock_Mutex(&d->input->mtx); | ||
249 | long r; int ch, enc; | ||
250 | mpg123_getformat(d->mpeg, &r, &ch, &enc); | ||
251 | iAssert(r == d->outputFreq); | ||
252 | iAssert(ch == d->output.numChannels); | ||
253 | iAssert(enc == MPG123_ENC_SIGNED_16); | ||
254 | } | ||
255 | while (size_Array(&d->pendingOutput) < d->output.count) { | ||
256 | int16_t buffer[512]; | ||
257 | size_t bytesWritten = 0; | ||
258 | const int rc = mpg123_read(d->mpeg, buffer, sizeof(buffer), &bytesWritten); | ||
259 | const float gain = d->gain; | ||
260 | for (size_t i = 0; i < bytesWritten / 2; i++) { | ||
261 | buffer[i] *= gain; | ||
262 | } | ||
263 | pushBackN_Array(&d->pendingOutput, buffer, bytesWritten / 2 / d->output.numChannels); | ||
264 | if (rc == MPG123_NEED_MORE) { | ||
265 | status = needMoreInput_DecoderStatus; | ||
266 | break; | ||
267 | } | ||
268 | else if (rc == MPG123_DONE) { | ||
269 | break; | ||
270 | } | ||
271 | } | ||
272 | writePending_Decoder_(d); | ||
273 | #endif | ||
224 | return status; | 274 | return status; |
225 | } | 275 | } |
226 | 276 | ||
@@ -242,7 +292,11 @@ static iThreadResult run_Decoder_(iThread *thread) { | |||
242 | status = decodeWav_Decoder_(d, inputRange); | 292 | status = decodeWav_Decoder_(d, inputRange); |
243 | break; | 293 | break; |
244 | case vorbis_DecoderType: | 294 | case vorbis_DecoderType: |
245 | status = decodeVorbis_Decoder_(d, inputRange); | 295 | status = decodeVorbis_Decoder_(d); |
296 | break; | ||
297 | case mpeg_DecoderType: | ||
298 | status = decodeMpeg_Decoder_(d); | ||
299 | break; | ||
246 | default: | 300 | default: |
247 | break; | 301 | break; |
248 | } | 302 | } |
@@ -280,6 +334,9 @@ void init_Decoder(iDecoder *d, iInputBuf *input, const iContentSpec *spec) { | |||
280 | d->currentSample = 0; | 334 | d->currentSample = 0; |
281 | d->totalSamples = spec->totalSamples; | 335 | d->totalSamples = spec->totalSamples; |
282 | d->vorbis = NULL; | 336 | d->vorbis = NULL; |
337 | #if defined (LAGRANGE_ENABLE_MPG123) | ||
338 | d->mpeg = NULL; | ||
339 | #endif | ||
283 | init_Mutex(&d->outputMutex); | 340 | init_Mutex(&d->outputMutex); |
284 | d->thread = new_Thread(run_Decoder_); | 341 | d->thread = new_Thread(run_Decoder_); |
285 | setUserData_Thread(d->thread, d); | 342 | setUserData_Thread(d->thread, d); |
@@ -295,6 +352,15 @@ void deinit_Decoder(iDecoder *d) { | |||
295 | deinit_Mutex(&d->outputMutex); | 352 | deinit_Mutex(&d->outputMutex); |
296 | deinit_SampleBuf(&d->output); | 353 | deinit_SampleBuf(&d->output); |
297 | deinit_Array(&d->pendingOutput); | 354 | deinit_Array(&d->pendingOutput); |
355 | if (d->vorbis) { | ||
356 | stb_vorbis_close(d->vorbis); | ||
357 | } | ||
358 | #if defined (LAGRANGE_ENABLE_MPG123) | ||
359 | if (d->mpeg) { | ||
360 | mpg123_close(d->mpeg); | ||
361 | mpg123_delete(d->mpeg); | ||
362 | } | ||
363 | #endif | ||
298 | } | 364 | } |
299 | 365 | ||
300 | iDefineTypeConstructionArgs(Decoder, (iInputBuf *input, const iContentSpec *spec), | 366 | iDefineTypeConstructionArgs(Decoder, (iInputBuf *input, const iContentSpec *spec), |
@@ -336,6 +402,11 @@ static iContentSpec contentSpec_Player_(const iPlayer *d) { | |||
336 | !cmp_String(&d->mime, "audio/x-vorbis+ogg")) { | 402 | !cmp_String(&d->mime, "audio/x-vorbis+ogg")) { |
337 | content.type = vorbis_DecoderType; | 403 | content.type = vorbis_DecoderType; |
338 | } | 404 | } |
405 | #if defined (LAGRANGE_ENABLE_MPG123) | ||
406 | else if (!cmp_String(&d->mime, "audio/mpeg") || !cmp_String(&d->mime, "audio/mp3")) { | ||
407 | content.type = mpeg_DecoderType; | ||
408 | } | ||
409 | #endif | ||
339 | else { | 410 | else { |
340 | /* TODO: Could try decoders to see if one works? */ | 411 | /* TODO: Could try decoders to see if one works? */ |
341 | content.type = none_DecoderType; | 412 | content.type = none_DecoderType; |
@@ -438,6 +509,24 @@ static iContentSpec contentSpec_Player_(const iPlayer *d) { | |||
438 | content.inputFormat = AUDIO_F32; /* actually stb_vorbis provides floats */ | 509 | content.inputFormat = AUDIO_F32; /* actually stb_vorbis provides floats */ |
439 | stb_vorbis_close(vrb); | 510 | stb_vorbis_close(vrb); |
440 | } | 511 | } |
512 | else if (content.type == mpeg_DecoderType) { | ||
513 | #if defined (LAGRANGE_ENABLE_MPG123) | ||
514 | mpg123_handle *mh = mpg123_new(NULL, NULL); | ||
515 | mpg123_open_feed(mh); | ||
516 | mpg123_feed(mh, constData_Block(&d->data->data), size_Block(&d->data->data)); | ||
517 | long rate = 0; | ||
518 | int channels = 0; | ||
519 | int encoding = 0; | ||
520 | if (mpg123_getformat(mh, &rate, &channels, &encoding) == MPG123_OK) { | ||
521 | content.output.freq = rate; | ||
522 | content.output.channels = channels; | ||
523 | content.inputFormat = AUDIO_S16; | ||
524 | content.output.format = AUDIO_S16; | ||
525 | } | ||
526 | mpg123_close(mh); | ||
527 | mpg123_delete(mh); | ||
528 | #endif | ||
529 | } | ||
441 | iAssert(content.inputFormat == content.output.format || | 530 | iAssert(content.inputFormat == content.output.format || |
442 | (content.inputFormat == AUDIO_S24LSB && content.output.format == AUDIO_S16) || | 531 | (content.inputFormat == AUDIO_S24LSB && content.output.format == AUDIO_S16) || |
443 | (content.inputFormat == AUDIO_F64LSB && content.output.format == AUDIO_F32)); | 532 | (content.inputFormat == AUDIO_F64LSB && content.output.format == AUDIO_F32)); |