DOSBox-X
|
00001 /* 00002 * DOSBox-X MP3 decoder API implementation 00003 * --------------------------------------- 00004 * It makes use of the dr_wav library by David Reid (mackron@gmail.com) 00005 * Source links: 00006 * - dr_libs: https://github.com/mackron/dr_libs (source) 00007 * - dr_wav: http://mackron.github.io/dr_wav.html (website) 00008 * 00009 * Copyright (C) 2020 The DOSBox Team 00010 * Copyright (C) 2018-2019 Kevin R. Croft <krcroft@gmail.com> 00011 * Copyright (C) 2001-2017 Ryan C. Gordon <icculus@icculus.org> 00012 * 00013 * This program is free software; you can redistribute it and/or modify 00014 * it under the terms of the GNU General Public License as published by 00015 * the Free Software Foundation; either version 2 of the License, or 00016 * (at your option) any later version. 00017 * 00018 * This program is distributed in the hope that it will be useful, 00019 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00020 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00021 * GNU General Public License for more details. 00022 * 00023 * You should have received a copy of the GNU General Public License along 00024 * with this program; if not, write to the Free Software Foundation, Inc., 00025 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00026 */ 00027 00028 #if HAVE_CONFIG_H 00029 # include <config.h> 00030 #endif 00031 00032 #include <math.h> /* llroundf */ 00033 00034 #include "SDL_sound.h" 00035 #define __SDL_SOUND_INTERNAL__ 00036 #include "SDL_sound_internal.h" 00037 00038 /* Map dr_wav's memory routines to SDL's */ 00039 #define DRWAV_FREE(p) SDL_free((p)) 00040 #define DRWAV_MALLOC(sz) SDL_malloc((sz)) 00041 #define DRWAV_REALLOC(p, sz) SDL_realloc((p), (sz)) 00042 #define DRWAV_ZERO_MEMORY(p, sz) SDL_memset((p), 0, (sz)) 00043 #define DRWAV_COPY_MEMORY(dst, src, sz) SDL_memcpy((dst), (src), (sz)) 00044 00045 #define DR_WAV_NO_STDIO 00046 #define DR_WAV_IMPLEMENTATION 00047 #include "dr_wav.h" 00048 00049 static size_t wav_read(void* pUserData, void* pBufferOut, size_t bytesToRead) 00050 { 00051 Uint8 *ptr = (Uint8 *) pBufferOut; 00052 Sound_Sample *sample = (Sound_Sample *) pUserData; 00053 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; 00054 SDL_RWops *rwops = internal->rw; 00055 size_t bytes_read = 0; 00056 00057 while (bytes_read < bytesToRead) { 00058 const size_t rc = SDL_RWread(rwops, ptr, 1, bytesToRead - bytes_read); 00059 if (rc == 0) { 00060 sample->flags |= SOUND_SAMPLEFLAG_EOF; 00061 break; 00062 } /* if */ 00063 bytes_read += rc; 00064 ptr += rc; 00065 } /* while */ 00066 00067 return bytes_read; 00068 } /* wav_read */ 00069 00070 static drwav_bool32 wav_seek(void* pUserData, int offset, drwav_seek_origin origin) 00071 { 00072 const int whence = (origin == drwav_seek_origin_start) ? RW_SEEK_SET : RW_SEEK_CUR; 00073 Sound_Sample *sample = (Sound_Sample *) pUserData; 00074 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; 00075 return (SDL_RWseek(internal->rw, offset, whence) != -1) ? DRWAV_TRUE : DRWAV_FALSE; 00076 } /* wav_seek */ 00077 00078 00079 static int WAV_init(void) 00080 { 00081 return 1; /* always succeeds. */ 00082 } /* WAV_init */ 00083 00084 00085 static void WAV_quit(void) 00086 { 00087 /* it's a no-op. */ 00088 } /* WAV_quit */ 00089 00090 static void WAV_close(Sound_Sample *sample) 00091 { 00092 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; 00093 drwav *dr = (drwav *) internal->decoder_private; 00094 if (dr != NULL) { 00095 (void) drwav_uninit(dr); 00096 SDL_free(dr); 00097 internal->decoder_private = NULL; 00098 } 00099 return; 00100 } /* WAV_close */ 00101 00102 static int WAV_open(Sound_Sample *sample, const char *ext) 00103 { 00104 (void) ext; // deliberately unused, but present for API compliance 00105 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; 00106 drwav* dr = (drwav*)SDL_malloc(sizeof(drwav)); 00107 drwav_result result = drwav_init_ex(dr, wav_read, wav_seek, NULL, sample, NULL, 0, NULL); 00108 internal->decoder_private = dr; 00109 00110 if (result == DRWAV_TRUE) { 00111 SNDDBG(("WAV: Codec accepted the data stream.\n")); 00112 sample->flags = SOUND_SAMPLEFLAG_CANSEEK; 00113 sample->actual.rate = dr->sampleRate; 00114 sample->actual.format = AUDIO_S16SYS; 00115 sample->actual.channels = (Uint8)(dr->channels); 00116 00117 const Uint64 frames = (Uint64) dr->totalPCMFrameCount; 00118 if (frames == 0) { 00119 internal->total_time = -1; 00120 } 00121 else { 00122 const Uint32 rate = (Uint32) dr->sampleRate; 00123 internal->total_time = ( (Sint32)frames / rate) * 1000; 00124 internal->total_time += ((frames % rate) * 1000) / rate; 00125 } /* else */ 00126 00127 } /* if result != DRWAV_TRUE */ 00128 else { 00129 SNDDBG(("WAV: Codec could not parse the data stream.\n")); 00130 WAV_close(sample); 00131 } 00132 return result; 00133 } /* WAV_open */ 00134 00135 00136 static Uint32 WAV_read(Sound_Sample *sample, void* buffer, Uint32 desired_frames) 00137 { 00138 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; 00139 drwav *dr = (drwav *) internal->decoder_private; 00140 const drwav_uint64 frames_read = drwav_read_pcm_frames_s16(dr, 00141 desired_frames, 00142 (drwav_int16 *) buffer); 00143 return (Uint32)frames_read; 00144 } /* WAV_read */ 00145 00146 00147 static int WAV_rewind(Sound_Sample *sample) 00148 { 00149 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; 00150 drwav *dr = (drwav *) internal->decoder_private; 00151 return (drwav_seek_to_pcm_frame(dr, 0) == DRWAV_TRUE); 00152 } /* WAV_rewind */ 00153 00154 static int WAV_seek(Sound_Sample *sample, Uint32 ms) 00155 { 00156 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; 00157 drwav *dr = (drwav *) internal->decoder_private; 00158 const float frames_per_ms = ((float) sample->actual.rate) / 1000.0f; 00159 const drwav_uint64 frame_offset = llroundf(frames_per_ms * ms); 00160 return (drwav_seek_to_pcm_frame(dr, frame_offset) == DRWAV_TRUE); 00161 } /* WAV_seek */ 00162 00163 static const char *extensions_wav[] = { "WAV", "W64", NULL }; 00164 00165 const Sound_DecoderFunctions __Sound_DecoderFunctions_WAV = 00166 { 00167 { 00168 extensions_wav, 00169 "WAV Audio Codec", 00170 "The DOSBox-X project" 00171 }, 00172 00173 WAV_init, /* init() method */ 00174 WAV_quit, /* quit() method */ 00175 WAV_open, /* open() method */ 00176 WAV_close, /* close() method */ 00177 WAV_read, /* read() method */ 00178 WAV_rewind, /* rewind() method */ 00179 WAV_seek /* seek() method */ 00180 }; 00181 /* end of wav.c ... */