summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/audio/player.c215
1 files changed, 161 insertions, 54 deletions
diff --git a/src/audio/player.c b/src/audio/player.c
index 1dd2ebfc..f1d6a2c8 100644
--- a/src/audio/player.c
+++ b/src/audio/player.c
@@ -28,6 +28,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
28 28
29iDeclareType(InputBuf) 29iDeclareType(InputBuf)
30 30
31#if !defined (AUDIO_S24LSB)
32# define AUDIO_S24LSB 0x8018 /* 24-bit integer samples */
33#endif
34#if !defined (AUDIO_F64LSB)
35# define AUDIO_F64LSB 0x8140 /* 64-bit floating point samples */
36#endif
37
31struct Impl_InputBuf { 38struct Impl_InputBuf {
32 iMutex mtx; 39 iMutex mtx;
33 iCondition changed; 40 iCondition changed;
@@ -59,25 +66,28 @@ iDefineTypeConstruction(InputBuf)
59iDeclareType(SampleBuf) 66iDeclareType(SampleBuf)
60 67
61struct Impl_SampleBuf { 68struct Impl_SampleBuf {
62 void * data; 69 SDL_AudioFormat format;
63 uint8_t numBits; 70 uint8_t numChannels;
64 uint8_t numChannels; 71 uint8_t sampleSize; /* as bytes; one sample includes values for all channels */
65 uint8_t sampleSize; /* bytes; one sample includes values for all channels */ 72 void * data;
66 size_t count; 73 size_t count;
67 size_t head, tail; 74 size_t head, tail;
75 iCondition moreNeeded;
68}; 76};
69 77
70void init_SampleBuf(iSampleBuf *d, size_t numChannels, size_t sampleSize, size_t count) { 78void init_SampleBuf(iSampleBuf *d, SDL_AudioFormat format, size_t numChannels, size_t count) {
79 d->format = format;
71 d->numChannels = numChannels; 80 d->numChannels = numChannels;
72 d->sampleSize = sampleSize; 81 d->sampleSize = SDL_AUDIO_BITSIZE(format) / 8 * numChannels;
73 d->numBits = sampleSize / numChannels * 8;
74 d->count = count + 1; /* considered empty if head==tail */ 82 d->count = count + 1; /* considered empty if head==tail */
75 d->data = malloc(d->sampleSize * d->count); 83 d->data = malloc(d->sampleSize * d->count);
76 d->head = 0; 84 d->head = 0;
77 d->tail = 0; 85 d->tail = 0;
86 init_Condition(&d->moreNeeded);
78} 87}
79 88
80void deinit_SampleBuf(iSampleBuf *d) { 89void deinit_SampleBuf(iSampleBuf *d) {
90 deinit_Condition(&d->moreNeeded);
81 free(d->data); 91 free(d->data);
82} 92}
83 93
@@ -134,8 +144,9 @@ void read_SampleBuf(iSampleBuf *d, const size_t n, void *samples_out) {
134iDeclareType(ContentSpec) 144iDeclareType(ContentSpec)
135 145
136struct Impl_ContentSpec { 146struct Impl_ContentSpec {
137 SDL_AudioSpec spec; 147 SDL_AudioFormat inputFormat;
138 iRanges wavData; 148 SDL_AudioSpec output;
149 iRanges wavData;
139}; 150};
140 151
141iDeclareType(Decoder) 152iDeclareType(Decoder)
@@ -152,6 +163,7 @@ struct Impl_Decoder {
152 enum iDecoderType type; 163 enum iDecoderType type;
153 float gain; 164 float gain;
154 iThread * thread; 165 iThread * thread;
166 SDL_AudioFormat inputFormat;
155 iInputBuf * input; 167 iInputBuf * input;
156 size_t inputPos; 168 size_t inputPos;
157 iSampleBuf output; 169 iSampleBuf output;
@@ -159,70 +171,140 @@ struct Impl_Decoder {
159 iRanges wavData; 171 iRanges wavData;
160}; 172};
161 173
162static void parseWav_Decoder_(iDecoder *d, iRanges inputRange) { 174enum iDecoderParseStatus {
163 const size_t sampleSize = d->output.sampleSize; 175 ok_DecoderParseStatus,
164 const size_t vacancy = vacancy_SampleBuf(&d->output); 176 needMoreInput_DecoderParseStatus,
165 const size_t avail = iMin(inputRange.end - d->inputPos, d->wavData.end - d->inputPos) / 177};
166 sampleSize; 178
179static enum iDecoderParseStatus parseWav_Decoder_(iDecoder *d, iRanges inputRange) {
180 const uint8_t numChannels = d->output.numChannels;
181 const size_t inputSampleSize = numChannels * SDL_AUDIO_BITSIZE(d->inputFormat) / 8;
182 const size_t vacancy = vacancy_SampleBuf(&d->output);
183 const size_t inputBytePos = inputSampleSize * d->inputPos;
184 const size_t avail =
185 iMin(inputRange.end - inputBytePos, d->wavData.end - inputBytePos) / inputSampleSize;
186 if (avail == 0) {
187 return needMoreInput_DecoderParseStatus;
188 }
167 const size_t n = iMin(vacancy, avail); 189 const size_t n = iMin(vacancy, avail);
168 if (n == 0) return; 190 if (n == 0) {
169 void *samples = malloc(sampleSize * n); 191 return ok_DecoderParseStatus;
192 }
193 void *samples = malloc(inputSampleSize * n);
170 /* Get a copy of the input for mixing. */ { 194 /* Get a copy of the input for mixing. */ {
171 lock_Mutex(&d->input->mtx); 195 lock_Mutex(&d->input->mtx);
172 memcpy( 196 iAssert(inputSampleSize * d->inputPos < size_Block(&d->input->data));
173 samples, constData_Block(&d->input->data) + sampleSize * d->inputPos, sampleSize * n); 197 memcpy(samples,
198 constData_Block(&d->input->data) + inputSampleSize * d->inputPos,
199 inputSampleSize * n);
174 d->inputPos += n; 200 d->inputPos += n;
175 unlock_Mutex(&d->input->mtx); 201 unlock_Mutex(&d->input->mtx);
176 } 202 }
177 /* Gain. */ { 203 /* Gain. */ {
178 const float gain = d->gain; 204 const float gain = d->gain;
179 if (d->output.numBits == 16) { 205 if (d->inputFormat == AUDIO_F64LSB) {
180 int16_t *value = samples; 206 iAssert(d->output.format == AUDIO_F32);
181 for (size_t count = d->output.numChannels * n; count; count--, value++) { 207 double *inValue = samples;
208 float * outValue = samples;
209 for (size_t count = numChannels * n; count; count--) {
210 *outValue++ = gain * *inValue++;
211 }
212 }
213 else if (d->inputFormat == AUDIO_F32) {
214 float *value = samples;
215 for (size_t count = numChannels * n; count; count--, value++) {
182 *value *= gain; 216 *value *= gain;
183 } 217 }
184 } 218 }
219 else if (d->inputFormat == AUDIO_S24LSB) {
220 iAssert(d->output.format == AUDIO_S16);
221 const char *inValue = samples;
222 int16_t * outValue = samples;
223 for (size_t count = numChannels * n; count; count--, inValue += 3, outValue++) {
224 memcpy(outValue, inValue, 2);
225 *outValue *= gain;
226 }
227 }
228 else {
229 switch (SDL_AUDIO_BITSIZE(d->output.format)) {
230 case 8: {
231 uint8_t *value = samples;
232 for (size_t count = numChannels * n; count; count--, value++) {
233 *value = (int) (*value - 127) * gain + 127;
234 }
235 break;
236 }
237 case 16: {
238 int16_t *value = samples;
239 for (size_t count = numChannels * n; count; count--, value++) {
240 *value *= gain;
241 }
242 break;
243 }
244 case 32: {
245 int32_t *value = samples;
246 for (size_t count = numChannels * n; count; count--, value++) {
247 *value *= gain;
248 }
249 break;
250 }
251 }
252 }
185 } 253 }
186 iGuardMutex(&d->outputMutex, write_SampleBuf(&d->output, samples, n)); 254 iGuardMutex(&d->outputMutex, write_SampleBuf(&d->output, samples, n));
187 free(samples); 255 free(samples);
256 return ok_DecoderParseStatus;
188} 257}
189 258
190static iThreadResult run_Decoder_(iThread *thread) { 259static iThreadResult run_Decoder_(iThread *thread) {
191 iDecoder *d = userData_Thread(thread); 260 iDecoder *d = userData_Thread(thread);
261 /* Amount of data initially available. */
262 lock_Mutex(&d->input->mtx);
263 size_t inputSize = size_InputBuf(d->input);
264 unlock_Mutex(&d->input->mtx);
192 while (d->type) { 265 while (d->type) {
193 size_t inputSize = 0;
194 /* Grab more input. */ {
195 lock_Mutex(&d->input->mtx);
196 wait_Condition(&d->input->changed, &d->input->mtx);
197 inputSize = size_Block(&d->input->data);
198 unlock_Mutex(&d->input->mtx);
199 }
200 iRanges inputRange = { d->inputPos, inputSize }; 266 iRanges inputRange = { d->inputPos, inputSize };
201 iAssert(inputRange.start <= inputRange.end); 267 iAssert(inputRange.start <= inputRange.end);
202 if (!d->type) break; 268 if (!d->type) break;
203 /* Have data to work on and a place to save output? */ 269 /* Have data to work on and a place to save output? */
204 if (!isEmpty_Range(&inputRange) && !isFull_SampleBuf(&d->output)) { 270 enum iDecoderParseStatus status = ok_DecoderParseStatus;
271 if (!isEmpty_Range(&inputRange)) {
205 switch (d->type) { 272 switch (d->type) {
206 case wav_DecoderType: 273 case wav_DecoderType:
207 parseWav_Decoder_(d, inputRange); 274 status = parseWav_Decoder_(d, inputRange);
208 break; 275 break;
209 default: 276 default:
210 break; 277 break;
211 } 278 }
212 } 279 }
280 if (status == needMoreInput_DecoderParseStatus) {
281 lock_Mutex(&d->input->mtx);
282 if (size_InputBuf(d->input) == inputSize) {
283 wait_Condition(&d->input->changed, &d->input->mtx);
284 }
285 inputSize = size_InputBuf(d->input);
286 unlock_Mutex(&d->input->mtx);
287 }
288 else {
289 iGuardMutex(
290 &d->outputMutex, if (isFull_SampleBuf(&d->output)) {
291 wait_Condition(&d->output.moreNeeded, &d->outputMutex);
292 });
293 }
213 } 294 }
214 return 0; 295 return 0;
215} 296}
216 297
217void init_Decoder(iDecoder *d, iInputBuf *input, const iContentSpec *spec) { 298void init_Decoder(iDecoder *d, iInputBuf *input, const iContentSpec *spec) {
218 d->type = wav_DecoderType; 299 d->type = wav_DecoderType;
219 d->gain = 0.5f; 300 d->gain = 0.5f;
220 d->input = input; 301 d->input = input;
221 d->inputPos = spec->wavData.start; 302 d->inputPos = spec->wavData.start;
303 d->inputFormat = spec->inputFormat;
222 init_SampleBuf(&d->output, 304 init_SampleBuf(&d->output,
223 spec->spec.channels, 305 spec->output.format,
224 SDL_AUDIO_BITSIZE(spec->spec.format) / 8 * spec->spec.channels, 306 spec->output.channels,
225 spec->spec.samples * 2); 307 spec->output.samples * 2);
226 init_Mutex(&d->outputMutex); 308 init_Mutex(&d->outputMutex);
227 d->thread = new_Thread(run_Decoder_); 309 d->thread = new_Thread(run_Decoder_);
228 setUserData_Thread(d->thread, d); 310 setUserData_Thread(d->thread, d);
@@ -231,6 +313,7 @@ void init_Decoder(iDecoder *d, iInputBuf *input, const iContentSpec *spec) {
231 313
232void deinit_Decoder(iDecoder *d) { 314void deinit_Decoder(iDecoder *d) {
233 d->type = none_DecoderType; 315 d->type = none_DecoderType;
316 signal_Condition(&d->output.moreNeeded);
234 signal_Condition(&d->input->changed); 317 signal_Condition(&d->input->changed);
235 join_Thread(d->thread); 318 join_Thread(d->thread);
236 iRelease(d->thread); 319 iRelease(d->thread);
@@ -287,30 +370,52 @@ static iContentSpec contentSpec_Player_(const iPlayer *d) {
287 readData_Buffer(buf, 4, magic); 370 readData_Buffer(buf, 4, magic);
288 const size_t size = read32_Stream(is); 371 const size_t size = read32_Stream(is);
289 if (memcmp(magic, "fmt ", 4) == 0) { 372 if (memcmp(magic, "fmt ", 4) == 0) {
290 if (size != 16) { 373 if (size != 16 && size != 18) {
291 return content; 374 return content;
292 } 375 }
293 const int16_t mode = read16_Stream(is); /* 1 = PCM */ 376 enum iWavFormat {
377 pcm_WavFormat = 1,
378 ieeeFloat_WavFormat = 3,
379 };
380 const int16_t mode = read16_Stream(is); /* 1 = PCM, 3 = IEEE_FLOAT */
294 const int16_t numChannels = read16_Stream(is); 381 const int16_t numChannels = read16_Stream(is);
295 const int32_t freq = read32_Stream(is); 382 const int32_t freq = read32_Stream(is);
296 const uint32_t bytesPerSecond = readU32_Stream(is); 383 const uint32_t bytesPerSecond = readU32_Stream(is);
297 const int16_t blockAlign = read16_Stream(is); 384 const int16_t blockAlign = read16_Stream(is);
298 const int16_t bitsPerSample = read16_Stream(is); 385 const int16_t bitsPerSample = read16_Stream(is);
386 const uint16_t extSize = (size == 18 ? readU16_Stream(is) : 0);
299 iUnused(bytesPerSecond); 387 iUnused(bytesPerSecond);
300 iUnused(blockAlign); /* TODO: Should use this one when reading samples? */ 388 if (mode != pcm_WavFormat && mode != ieeeFloat_WavFormat) { /* PCM or float */
301 if (mode != 1) { /* PCM */ 389 return content;
390 }
391 if (extSize != 0) {
302 return content; 392 return content;
303 } 393 }
304 if (numChannels != 1 && numChannels != 2) { 394 if (numChannels != 1 && numChannels != 2) {
305 return content; 395 return content;
306 } 396 }
307 if (bitsPerSample != 8 && bitsPerSample != 16 && bitsPerSample != 32) { 397 if (bitsPerSample != 8 && bitsPerSample != 16 && bitsPerSample != 24 &&
398 bitsPerSample != 32 && bitsPerSample != 64) {
399 return content;
400 }
401 if (bitsPerSample == 24 && blockAlign != 3 * numChannels) {
308 return content; 402 return content;
309 } 403 }
310 content.spec.freq = freq; 404 content.output.freq = freq;
311 content.spec.channels = numChannels; 405 content.output.channels = numChannels;
312 content.spec.format = 406 if (mode == ieeeFloat_WavFormat) {
313 (bitsPerSample == 8 ? AUDIO_S8 : bitsPerSample == 16 ? AUDIO_S16 : AUDIO_S32); 407 content.inputFormat = (bitsPerSample == 32 ? AUDIO_F32 : AUDIO_F64LSB);
408 content.output.format = AUDIO_F32;
409 }
410 else if (bitsPerSample == 24) {
411 content.inputFormat = AUDIO_S24LSB;
412 content.output.format = AUDIO_S16;
413 }
414 else {
415 content.inputFormat = content.output.format =
416 (bitsPerSample == 8 ? AUDIO_U8
417 : bitsPerSample == 16 ? AUDIO_S16 : AUDIO_S32);
418 }
314 } 419 }
315 else if (memcmp(magic, "data", 4) == 0) { 420 else if (memcmp(magic, "data", 4) == 0) {
316 content.wavData = (iRanges){ pos_Stream(is), pos_Stream(is) + size }; 421 content.wavData = (iRanges){ pos_Stream(is), pos_Stream(is) + size };
@@ -321,7 +426,10 @@ static iContentSpec contentSpec_Player_(const iPlayer *d) {
321 } 426 }
322 } 427 }
323 } 428 }
324 content.spec.samples = 2048; 429 iAssert(content.inputFormat == content.output.format ||
430 (content.inputFormat == AUDIO_S24LSB && content.output.format == AUDIO_S16) ||
431 (content.inputFormat == AUDIO_F64LSB && content.output.format == AUDIO_F32));
432 content.output.samples = 2048;
325 return content; 433 return content;
326} 434}
327 435
@@ -337,9 +445,8 @@ static void writeOutputSamples_Player_(void *plr, Uint8 *stream, int len) {
337 else { 445 else {
338 memset(stream, d->spec.silence, len); 446 memset(stream, d->spec.silence, len);
339 } 447 }
448 signal_Condition(&d->decoder->output.moreNeeded);
340 unlock_Mutex(&d->decoder->outputMutex); 449 unlock_Mutex(&d->decoder->outputMutex);
341 /* Wake up decoder; there is more room for output. */
342 signal_Condition(&d->data->changed);
343} 450}
344 451
345void init_Player(iPlayer *d) { 452void init_Player(iPlayer *d) {
@@ -387,9 +494,9 @@ iBool start_Player(iPlayer *d) {
387 return iFalse; 494 return iFalse;
388 } 495 }
389 iContentSpec content = contentSpec_Player_(d); 496 iContentSpec content = contentSpec_Player_(d);
390 content.spec.callback = writeOutputSamples_Player_; 497 content.output.callback = writeOutputSamples_Player_;
391 content.spec.userdata = d; 498 content.output.userdata = d;
392 d->device = SDL_OpenAudioDevice(NULL, SDL_FALSE /* playback */, &content.spec, &d->spec, 0); 499 d->device = SDL_OpenAudioDevice(NULL, SDL_FALSE /* playback */, &content.output, &d->spec, 0);
393 if (!d->device) { 500 if (!d->device) {
394 return iFalse; 501 return iFalse;
395 } 502 }