DOSBox-X
|
00001 /* 00002 * Modified SDL Sound API implementation 00003 * ------------------------------------- 00004 * This file implements the API, the documentation for which can 00005 * be found in SDL_sound.h. This API has been changed from its 00006 * original implementation as follows: 00007 * - Cut down in size; most notably exclusion of the conversion routines 00008 * - Small bug fixes and warnings cleaned up 00009 * - Elimination of intermediate buffers, allowing direct decoding 00010 * - Moved from sample-based logic to frame-based (channel-agnostic) 00011 * 00012 * Copyright (C) 2020 The DOSBox Team 00013 * Copyright (C) 2018-2019 Kevin R. Croft <krcroft@gmail.com> 00014 * Copyright (C) 2001-2017 Ryan C. Gordon <icculus@icculus.org> 00015 * 00016 * This program is free software; you can redistribute it and/or modify 00017 * it under the terms of the GNU General Public License as published by 00018 * the Free Software Foundation; either version 2 of the License, or 00019 * (at your option) any later version. 00020 * 00021 * This program is distributed in the hope that it will be useful, 00022 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00023 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00024 * GNU General Public License for more details. 00025 * 00026 * You should have received a copy of the GNU General Public License along 00027 * with this program; if not, write to the Free Software Foundation, Inc., 00028 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00029 */ 00030 00031 #include <stdio.h> 00032 #include <ctype.h> 00033 00034 #if HAVE_CONFIG_H 00035 # include <config.h> 00036 #endif 00037 00038 #include <SDL.h> 00039 #include <SDL_thread.h> 00040 #include "SDL_sound.h" 00041 00042 #define __SDL_SOUND_INTERNAL__ 00043 #include "SDL_sound_internal.h" 00044 00045 typedef struct 00046 { 00047 int available; 00048 const Sound_DecoderFunctions *funcs; 00049 } decoder_element; 00050 00051 /* Supported decoder drivers... */ 00052 extern const Sound_DecoderFunctions __Sound_DecoderFunctions_FLAC; 00053 extern const Sound_DecoderFunctions __Sound_DecoderFunctions_MP3; 00054 #ifdef USE_OPUS 00055 extern const Sound_DecoderFunctions __Sound_DecoderFunctions_OPUS; 00056 #endif 00057 extern const Sound_DecoderFunctions __Sound_DecoderFunctions_VORBIS; 00058 extern const Sound_DecoderFunctions __Sound_DecoderFunctions_WAV; 00059 00060 static decoder_element decoders[] = 00061 { 00062 { 0, &__Sound_DecoderFunctions_FLAC }, 00063 { 0, &__Sound_DecoderFunctions_MP3 }, 00064 #ifdef USE_OPUS 00065 { 0, &__Sound_DecoderFunctions_OPUS }, 00066 #endif 00067 { 0, &__Sound_DecoderFunctions_VORBIS }, 00068 { 0, &__Sound_DecoderFunctions_WAV }, 00069 { 0, NULL } 00070 }; 00071 00072 00073 00074 /* General SDL_sound state ... */ 00075 00076 typedef struct __SOUND_ERRMSGTYPE__ 00077 { 00078 Uint32 tid; 00079 int error_available; 00080 char error_string[128]; 00081 struct __SOUND_ERRMSGTYPE__ *next; 00082 } ErrMsg; 00083 00084 static ErrMsg *error_msgs = NULL; 00085 static SDL_mutex *errorlist_mutex = NULL; 00086 00087 static Sound_Sample *sample_list = NULL; /* this is a linked list. */ 00088 static SDL_mutex *samplelist_mutex = NULL; 00089 00090 static const Sound_DecoderInfo **available_decoders = NULL; 00091 static int initialized = 0; 00092 00093 00094 /* functions ... */ 00095 00096 void Sound_GetLinkedVersion(Sound_Version *ver) 00097 { 00098 if (ver != NULL) 00099 { 00100 ver->major = SOUND_VER_MAJOR; 00101 ver->minor = SOUND_VER_MINOR; 00102 ver->patch = SOUND_VER_PATCH; 00103 } /* if */ 00104 } /* Sound_GetLinkedVersion */ 00105 00106 00107 int Sound_Init(void) 00108 { 00109 size_t i; 00110 size_t pos = 0; 00111 size_t total = sizeof (decoders) / sizeof (decoders[0]); 00112 BAIL_IF_MACRO(initialized, ERR_IS_INITIALIZED, 0); 00113 00114 sample_list = NULL; 00115 error_msgs = NULL; 00116 00117 available_decoders = (const Sound_DecoderInfo **) 00118 malloc((total) * sizeof (Sound_DecoderInfo *)); 00119 BAIL_IF_MACRO(available_decoders == NULL, ERR_OUT_OF_MEMORY, 0); 00120 00121 SDL_InitSubSystem(SDL_INIT_AUDIO); 00122 00123 errorlist_mutex = SDL_CreateMutex(); 00124 samplelist_mutex = SDL_CreateMutex(); 00125 00126 for (i = 0; decoders[i].funcs != NULL; i++) 00127 { 00128 decoders[i].available = decoders[i].funcs->init(); 00129 if (decoders[i].available) 00130 { 00131 available_decoders[pos] = &(decoders[i].funcs->info); 00132 pos++; 00133 } /* if */ 00134 } /* for */ 00135 00136 available_decoders[pos] = NULL; 00137 00138 initialized = 1; 00139 return(1); 00140 } /* Sound_Init */ 00141 00142 00143 int Sound_Quit(void) 00144 { 00145 ErrMsg *err; 00146 ErrMsg *nexterr = NULL; 00147 size_t i; 00148 00149 BAIL_IF_MACRO(!initialized, ERR_NOT_INITIALIZED, 0); 00150 00151 while (((volatile Sound_Sample *) sample_list) != NULL) 00152 { 00153 Sound_Sample *sample = sample_list; 00154 Sound_FreeSample(sample); /* Updates sample_list. */ 00155 } 00156 00157 initialized = 0; 00158 00159 SDL_DestroyMutex(samplelist_mutex); 00160 samplelist_mutex = NULL; 00161 sample_list = NULL; 00162 00163 for (i = 0; decoders[i].funcs != NULL; i++) 00164 { 00165 if (decoders[i].available) 00166 { 00167 decoders[i].funcs->quit(); 00168 decoders[i].available = 0; 00169 } /* if */ 00170 } /* for */ 00171 00172 if (available_decoders != NULL) 00173 free((void *) available_decoders); 00174 available_decoders = NULL; 00175 00176 /* clean up error state for each thread... */ 00177 SDL_LockMutex(errorlist_mutex); 00178 for (err = error_msgs; err != NULL; err = nexterr) 00179 { 00180 nexterr = err->next; 00181 free(err); 00182 } /* for */ 00183 error_msgs = NULL; 00184 SDL_UnlockMutex(errorlist_mutex); 00185 SDL_DestroyMutex(errorlist_mutex); 00186 errorlist_mutex = NULL; 00187 00188 return(1); 00189 } /* Sound_Quit */ 00190 00191 00192 const Sound_DecoderInfo **Sound_AvailableDecoders(void) 00193 { 00194 return(available_decoders); /* READ. ONLY. */ 00195 } /* Sound_AvailableDecoders */ 00196 00197 00198 static ErrMsg *findErrorForCurrentThread(void) 00199 { 00200 ErrMsg *i; 00201 Uint32 tid; 00202 00203 if (error_msgs != NULL) 00204 { 00205 tid = SDL_ThreadID(); 00206 00207 SDL_LockMutex(errorlist_mutex); 00208 for (i = error_msgs; i != NULL; i = i->next) 00209 { 00210 if (i->tid == tid) 00211 { 00212 SDL_UnlockMutex(errorlist_mutex); 00213 return(i); 00214 } /* if */ 00215 } /* for */ 00216 SDL_UnlockMutex(errorlist_mutex); 00217 } /* if */ 00218 00219 return(NULL); /* no error available. */ 00220 } /* findErrorForCurrentThread */ 00221 00222 00223 const char *Sound_GetError(void) 00224 { 00225 const char *retval = NULL; 00226 ErrMsg *err; 00227 00228 if (!initialized) 00229 return(ERR_NOT_INITIALIZED); 00230 00231 err = findErrorForCurrentThread(); 00232 if ((err != NULL) && (err->error_available)) 00233 { 00234 retval = err->error_string; 00235 err->error_available = 0; 00236 } /* if */ 00237 00238 return(retval); 00239 } /* Sound_GetError */ 00240 00241 00242 void Sound_ClearError(void) 00243 { 00244 ErrMsg *err; 00245 00246 if (!initialized) 00247 return; 00248 00249 err = findErrorForCurrentThread(); 00250 if (err != NULL) 00251 err->error_available = 0; 00252 } /* Sound_ClearError */ 00253 00254 00255 /* 00256 * This is declared in the internal header. 00257 */ 00258 void __Sound_SetError(const char *str) 00259 { 00260 ErrMsg *err; 00261 00262 if (str == NULL) 00263 return; 00264 00265 SNDDBG(("__Sound_SetError(\"%s\");%s\n", str, 00266 (initialized) ? "" : " [NOT INITIALIZED!]")); 00267 00268 if (!initialized) 00269 return; 00270 00271 err = findErrorForCurrentThread(); 00272 if (err == NULL) 00273 { 00274 err = (ErrMsg *) malloc(sizeof (ErrMsg)); 00275 if (err == NULL) 00276 return; /* uhh...? */ 00277 00278 memset((void *) err, '\0', sizeof (ErrMsg)); 00279 err->tid = SDL_ThreadID(); 00280 00281 SDL_LockMutex(errorlist_mutex); 00282 err->next = error_msgs; 00283 error_msgs = err; 00284 SDL_UnlockMutex(errorlist_mutex); 00285 } /* if */ 00286 00287 err->error_available = 1; 00288 snprintf(err->error_string, sizeof (err->error_string), "%s", str); 00289 } /* __Sound_SetError */ 00290 00291 00292 Uint32 __Sound_convertMsToBytePos(Sound_AudioInfo *info, Uint32 ms) 00293 { 00294 /* "frames" == "sample frames" */ 00295 float frames_per_ms = ((float) info->rate) / 1000.0f; 00296 Uint32 frame_offset = (Uint32) (frames_per_ms * ((float) ms)); 00297 Uint32 frame_size = (Uint32) ((info->format & 0xFF) / 8) * info->channels; 00298 return(frame_offset * frame_size); 00299 } /* __Sound_convertMsToBytePos */ 00300 00301 00302 /* 00303 * -ansi and -pedantic flags prevent use of strcasecmp() on Linux, and 00304 * I honestly don't want to mess around with figuring out if a given 00305 * platform has "strcasecmp", "stricmp", or 00306 * "compare_two_damned_strings_case_insensitive", which I hear is in the 00307 * next release of Carbon. :) This is exported so decoders may use it if 00308 * they like. 00309 */ 00310 int __Sound_strcasecmp(const char *x, const char *y) 00311 { 00312 int ux, uy; 00313 00314 if (x == y) /* same pointer? Both NULL? */ 00315 return(0); 00316 00317 if (x == NULL) 00318 return(-1); 00319 00320 if (y == NULL) 00321 return(1); 00322 00323 do 00324 { 00325 ux = toupper((int) *x); 00326 uy = toupper((int) *y); 00327 if (ux > uy) 00328 return(1); 00329 else if (ux < uy) 00330 return(-1); 00331 x++; 00332 y++; 00333 } while ((ux) && (uy)); 00334 00335 return(0); 00336 } /* __Sound_strcasecmp */ 00337 00338 00339 /* 00340 * Allocate a Sound_Sample, and fill in most of its fields. Those that need 00341 * to be filled in later, by a decoder, will be initialized to zero. 00342 */ 00343 static Sound_Sample *alloc_sample(SDL_RWops *rw, Sound_AudioInfo *desired) 00344 { 00345 /* 00346 * !!! FIXME: We're going to need to pool samples, since the mixer 00347 * !!! FIXME: might be allocating tons of these on a regular basis. 00348 */ 00349 Sound_Sample *retval = NULL; 00350 Sound_Sample *sample = (Sound_Sample *)malloc(sizeof (Sound_Sample)); 00351 Sound_SampleInternal *internal = (Sound_SampleInternal *)malloc(sizeof (Sound_SampleInternal)); 00352 if (sample && internal) { 00353 memset(sample, '\0', sizeof (Sound_Sample)); 00354 memset(internal, '\0', sizeof (Sound_SampleInternal)); 00355 if (desired != NULL) { 00356 memcpy(&sample->desired, desired, sizeof (Sound_AudioInfo)); 00357 } 00358 internal->rw = rw; 00359 sample->opaque = internal; 00360 retval = sample; 00361 } else { 00362 __Sound_SetError(ERR_OUT_OF_MEMORY); 00363 free(sample); 00364 free(internal); 00365 } 00366 return retval; 00367 } /* alloc_sample */ 00368 00369 00370 #if (defined DEBUG_CHATTER) 00371 static __inline__ const char *fmt_to_str(Uint16 fmt) 00372 { 00373 switch(fmt) 00374 { 00375 case AUDIO_U8: 00376 return("U8"); 00377 case AUDIO_S8: 00378 return("S8"); 00379 case AUDIO_U16LSB: 00380 return("U16LSB"); 00381 case AUDIO_S16LSB: 00382 return("S16LSB"); 00383 case AUDIO_U16MSB: 00384 return("U16MSB"); 00385 case AUDIO_S16MSB: 00386 return("S16MSB"); 00387 } /* switch */ 00388 00389 return("Unknown"); 00390 } /* fmt_to_str */ 00391 #endif 00392 00393 00394 /* 00395 * The bulk of the Sound_NewSample() work is done here... 00396 * Ask the specified decoder to handle the data in (rw), and if 00397 * so, construct the Sound_Sample. Otherwise, try to wind (rw)'s stream 00398 * back to where it was, and return false. 00399 */ 00400 static int init_sample(const Sound_DecoderFunctions *funcs, 00401 Sound_Sample *sample, const char *ext, 00402 Sound_AudioInfo *_desired) 00403 { 00404 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; 00405 Sound_AudioInfo desired; 00406 const Sint64 pos = SDL_RWtell(internal->rw); 00407 00408 /* fill in the funcs for this decoder... */ 00409 sample->decoder = &funcs->info; 00410 internal->funcs = funcs; 00411 if (!funcs->open(sample, ext)) 00412 { 00413 SDL_RWseek(internal->rw, pos, SEEK_SET); /* set for next try... */ 00414 return(0); 00415 } /* if */ 00416 00417 /* success; we've got a decoder! */ 00418 00419 memcpy(&desired, (_desired != NULL) ? _desired : &sample->actual, 00420 sizeof (Sound_AudioInfo)); 00421 00422 if (desired.format == 0) 00423 desired.format = sample->actual.format; 00424 if (desired.channels == 0) 00425 desired.channels = sample->actual.channels; 00426 if (desired.rate == 0) 00427 desired.rate = sample->actual.rate; 00428 00429 00430 /* these pointers are all one and the same. */ 00431 memcpy(&sample->desired, &desired, sizeof (Sound_AudioInfo)); 00432 00433 /* Prepend our new Sound_Sample to the sample_list... */ 00434 SDL_LockMutex(samplelist_mutex); 00435 internal->next = sample_list; 00436 if (sample_list != NULL) 00437 ((Sound_SampleInternal *) sample_list->opaque)->prev = sample; 00438 sample_list = sample; 00439 SDL_UnlockMutex(samplelist_mutex); 00440 00441 SNDDBG(("New sample DESIRED format: %s format, %d rate, %d channels.\n", 00442 fmt_to_str(sample->desired.format), 00443 sample->desired.rate, 00444 sample->desired.channels)); 00445 00446 SNDDBG(("New sample ACTUAL format: %s format, %d rate, %d channels.\n", 00447 fmt_to_str(sample->actual.format), 00448 sample->actual.rate, 00449 sample->actual.channels)); 00450 return(1); 00451 } /* init_sample */ 00452 00453 00454 Sound_Sample *Sound_NewSample(SDL_RWops *rw, const char *ext, 00455 Sound_AudioInfo *desired) 00456 { 00457 Sound_Sample *retval; 00458 decoder_element *decoder; 00459 00460 /* sanity checks. */ 00461 BAIL_IF_MACRO(!initialized, ERR_NOT_INITIALIZED, NULL); 00462 BAIL_IF_MACRO(rw == NULL, ERR_INVALID_ARGUMENT, NULL); 00463 00464 retval = alloc_sample(rw, desired); 00465 if (!retval) 00466 return(NULL); /* alloc_sample() sets error message... */ 00467 00468 if (ext != NULL) 00469 { 00470 for (decoder = &decoders[0]; decoder->funcs != NULL; decoder++) 00471 { 00472 if (decoder->available) 00473 { 00474 const char **decoderExt = decoder->funcs->info.extensions; 00475 while (*decoderExt) 00476 { 00477 if (__Sound_strcasecmp(*decoderExt, ext) == 0) 00478 { 00479 if (init_sample(decoder->funcs, retval, ext, desired)) 00480 return(retval); 00481 break; /* done with this decoder either way. */ 00482 } /* if */ 00483 decoderExt++; 00484 } /* while */ 00485 } /* if */ 00486 } /* for */ 00487 } /* if */ 00488 00489 /* no direct extension match? Try everything we've got... */ 00490 for (decoder = &decoders[0]; decoder->funcs != NULL; decoder++) 00491 { 00492 if (decoder->available) 00493 { 00494 int should_try = 1; 00495 const char **decoderExt = decoder->funcs->info.extensions; 00496 00497 /* skip if we would have tried decoder above... */ 00498 while (*decoderExt) 00499 { 00500 if (__Sound_strcasecmp(*decoderExt, ext) == 0) 00501 { 00502 should_try = 0; 00503 break; 00504 } /* if */ 00505 decoderExt++; 00506 } /* while */ 00507 00508 if (should_try) 00509 { 00510 if (init_sample(decoder->funcs, retval, ext, desired)) 00511 return(retval); 00512 } /* if */ 00513 } /* if */ 00514 } /* for */ 00515 00516 /* nothing could handle the sound data... */ 00517 free(retval->opaque); 00518 free(retval); 00519 SDL_RWclose(rw); 00520 __Sound_SetError(ERR_UNSUPPORTED_FORMAT); 00521 return(NULL); 00522 } /* Sound_NewSample */ 00523 00524 00525 Sound_Sample *Sound_NewSampleFromFile(const char *filename, 00526 Sound_AudioInfo *desired) 00527 { 00528 const char *ext; 00529 SDL_RWops *rw; 00530 00531 BAIL_IF_MACRO(!initialized, ERR_NOT_INITIALIZED, NULL); 00532 BAIL_IF_MACRO(filename == NULL, ERR_INVALID_ARGUMENT, NULL); 00533 00534 ext = strrchr(filename, '.'); 00535 00536 00537 SNDDBG(("Sound_NewSampleFromFile ext = `%s`", ext)); 00538 00539 rw = SDL_RWFromFile(filename, "rb"); 00540 /* !!! FIXME: rw = RWops_FromFile(filename, "rb");*/ 00541 BAIL_IF_MACRO(rw == NULL, SDL_GetError(), NULL); 00542 00543 if (ext != NULL) 00544 ext++; 00545 00546 return(Sound_NewSample(rw, ext, desired)); 00547 } /* Sound_NewSampleFromFile */ 00548 00549 void Sound_FreeSample(Sound_Sample *sample) 00550 { 00551 Sound_SampleInternal *internal; 00552 00553 if (!initialized) 00554 { 00555 __Sound_SetError(ERR_NOT_INITIALIZED); 00556 return; 00557 } /* if */ 00558 00559 if (sample == NULL) 00560 { 00561 __Sound_SetError(ERR_INVALID_ARGUMENT); 00562 return; 00563 } /* if */ 00564 00565 internal = (Sound_SampleInternal *) sample->opaque; 00566 00567 SDL_LockMutex(samplelist_mutex); 00568 00569 /* update the sample_list... */ 00570 if (internal->prev != NULL) 00571 { 00572 Sound_SampleInternal *prevInternal; 00573 prevInternal = (Sound_SampleInternal *) internal->prev->opaque; 00574 prevInternal->next = internal->next; 00575 } /* if */ 00576 else 00577 { 00578 assert(sample_list == sample); 00579 sample_list = internal->next; 00580 } /* else */ 00581 00582 if (internal->next != NULL) 00583 { 00584 Sound_SampleInternal *nextInternal; 00585 nextInternal = (Sound_SampleInternal *) internal->next->opaque; 00586 nextInternal->prev = internal->prev; 00587 } /* if */ 00588 00589 SDL_UnlockMutex(samplelist_mutex); 00590 00591 /* nuke it... */ 00592 internal->funcs->close(sample); 00593 00594 if (internal->rw != NULL) /* this condition is a "just in case" thing. */ 00595 SDL_RWclose(internal->rw); 00596 00597 free(internal); 00598 free(sample); 00599 } /* Sound_FreeSample */ 00600 00601 Uint32 Sound_Decode_Direct(Sound_Sample *sample, void* buffer, Uint32 desired_frames) 00602 { 00603 Sound_SampleInternal *internal = NULL; 00604 00605 /* a boatload of sanity checks... */ 00606 BAIL_IF_MACRO(!initialized, ERR_NOT_INITIALIZED, 0); 00607 BAIL_IF_MACRO(sample == NULL, ERR_INVALID_ARGUMENT, 0); 00608 BAIL_IF_MACRO(sample->flags & SOUND_SAMPLEFLAG_ERROR, ERR_PREV_ERROR, 0); 00609 BAIL_IF_MACRO(sample->flags & SOUND_SAMPLEFLAG_EOF, ERR_PREV_EOF, 0); 00610 00611 internal = (Sound_SampleInternal *) sample->opaque; 00612 00613 /* reset EAGAIN. Decoder can flip it back on if it needs to. */ 00614 sample->flags &= ~SOUND_SAMPLEFLAG_EAGAIN; 00615 return internal->funcs->read(sample, buffer, desired_frames); 00616 } /* Sound_Decode */ 00617 00618 00619 int Sound_Rewind(Sound_Sample *sample) 00620 { 00621 Sound_SampleInternal *internal; 00622 BAIL_IF_MACRO(!initialized, ERR_NOT_INITIALIZED, 0); 00623 00624 internal = (Sound_SampleInternal *) sample->opaque; 00625 if (!internal->funcs->rewind(sample)) 00626 { 00627 sample->flags |= SOUND_SAMPLEFLAG_ERROR; 00628 return(0); 00629 } /* if */ 00630 00631 sample->flags &= ~SOUND_SAMPLEFLAG_EAGAIN; 00632 sample->flags &= ~SOUND_SAMPLEFLAG_ERROR; 00633 sample->flags &= ~SOUND_SAMPLEFLAG_EOF; 00634 00635 return(1); 00636 } /* Sound_Rewind */ 00637 00638 00639 int Sound_Seek(Sound_Sample *sample, Uint32 ms) 00640 { 00641 Sound_SampleInternal *internal; 00642 00643 BAIL_IF_MACRO(!initialized, ERR_NOT_INITIALIZED, 0); 00644 if (!(sample->flags & SOUND_SAMPLEFLAG_CANSEEK)) 00645 BAIL_MACRO(ERR_CANNOT_SEEK, 0); 00646 00647 internal = (Sound_SampleInternal *) sample->opaque; 00648 BAIL_IF_MACRO(!internal->funcs->seek(sample, ms), NULL, 0); 00649 00650 sample->flags &= ~SOUND_SAMPLEFLAG_EAGAIN; 00651 sample->flags &= ~SOUND_SAMPLEFLAG_ERROR; 00652 sample->flags &= ~SOUND_SAMPLEFLAG_EOF; 00653 00654 return(1); 00655 } /* Sound_Rewind */ 00656 00657 00658 Sint32 Sound_GetDuration(Sound_Sample *sample) 00659 { 00660 Sound_SampleInternal *internal; 00661 BAIL_IF_MACRO(!initialized, ERR_NOT_INITIALIZED, -1); 00662 internal = (Sound_SampleInternal *) sample->opaque; 00663 return(internal->total_time); 00664 } /* Sound_GetDuration */ 00665 00666 /* end of SDL_sound.c ... */