summaryrefslogtreecommitdiff
path: root/src/audio
diff options
context:
space:
mode:
authorJaakko Keränen <jaakko.keranen@iki.fi>2020-10-04 21:46:14 +0300
committerJaakko Keränen <jaakko.keranen@iki.fi>2020-10-04 21:46:14 +0300
commite04ef8eb590373908aa1058542ba332cd3b43015 (patch)
treeb97c714fd1cba4e1db004f6bb9ebc1f138f63404 /src/audio
parent2f3fa20d07d86c56e3e3d054339e0b02ef577c4b (diff)
Playing back a WAV file
Simple test case works now: loading a 16-bit stereo PCM WAV from a file (i.e., no streaming) and playing it back.
Diffstat (limited to 'src/audio')
-rw-r--r--src/audio/player.c87
1 files changed, 55 insertions, 32 deletions
diff --git a/src/audio/player.c b/src/audio/player.c
index 1dd3c38a..1dd2ebfc 100644
--- a/src/audio/player.c
+++ b/src/audio/player.c
@@ -60,17 +60,21 @@ iDeclareType(SampleBuf)
60 60
61struct Impl_SampleBuf { 61struct Impl_SampleBuf {
62 void * data; 62 void * data;
63 size_t sampleSize; 63 uint8_t numBits;
64 uint8_t numChannels;
65 uint8_t sampleSize; /* bytes; one sample includes values for all channels */
64 size_t count; 66 size_t count;
65 size_t head, tail; 67 size_t head, tail;
66}; 68};
67 69
68void init_SampleBuf(iSampleBuf *d, size_t sampleSize, size_t count) { 70void init_SampleBuf(iSampleBuf *d, size_t numChannels, size_t sampleSize, size_t count) {
69 d->sampleSize = sampleSize; 71 d->numChannels = numChannels;
70 d->count = count + 1; /* considered empty if head==tail */ 72 d->sampleSize = sampleSize;
71 d->data = malloc(d->sampleSize * d->count); 73 d->numBits = sampleSize / numChannels * 8;
72 d->head = 0; 74 d->count = count + 1; /* considered empty if head==tail */
73 d->tail = 0; 75 d->data = malloc(d->sampleSize * d->count);
76 d->head = 0;
77 d->tail = 0;
74} 78}
75 79
76void deinit_SampleBuf(iSampleBuf *d) { 80void deinit_SampleBuf(iSampleBuf *d) {
@@ -146,24 +150,41 @@ enum iDecoderType {
146 150
147struct Impl_Decoder { 151struct Impl_Decoder {
148 enum iDecoderType type; 152 enum iDecoderType type;
153 float gain;
149 iThread * thread; 154 iThread * thread;
150 iInputBuf * input; 155 iInputBuf * input;
151 size_t inputPos; 156 size_t inputPos;
152 iSampleBuf output; 157 iSampleBuf output;
153 iMutex mtx; /* for output */ 158 iMutex outputMutex;
154 iRanges wavData; 159 iRanges wavData;
155}; 160};
156 161
157static void parseWav_Decoder_(iDecoder *d, iRanges inputRange) { 162static void parseWav_Decoder_(iDecoder *d, iRanges inputRange) {
158 lock_Mutex(&d->mtx); 163 const size_t sampleSize = d->output.sampleSize;
159 const size_t vacancy = vacancy_SampleBuf(&d->output); 164 const size_t vacancy = vacancy_SampleBuf(&d->output);
160 const size_t avail = iMin(inputRange.end - d->inputPos, d->wavData.end - d->inputPos) / 165 const size_t avail = iMin(inputRange.end - d->inputPos, d->wavData.end - d->inputPos) /
161 d->output.sampleSize; 166 sampleSize;
162 const size_t n = iMin(vacancy, avail); 167 const size_t n = iMin(vacancy, avail);
163 iGuardMutex(&d->input->mtx, /* lock so input array isn't reallocated during the copy */ 168 if (n == 0) return;
164 write_SampleBuf(&d->output, constData_Block(&d->input->data) + d->inputPos, n)); 169 void *samples = malloc(sampleSize * n);
165 d->inputPos += n; 170 /* Get a copy of the input for mixing. */ {
166 unlock_Mutex(&d->mtx); 171 lock_Mutex(&d->input->mtx);
172 memcpy(
173 samples, constData_Block(&d->input->data) + sampleSize * d->inputPos, sampleSize * n);
174 d->inputPos += n;
175 unlock_Mutex(&d->input->mtx);
176 }
177 /* Gain. */ {
178 const float gain = d->gain;
179 if (d->output.numBits == 16) {
180 int16_t *value = samples;
181 for (size_t count = d->output.numChannels * n; count; count--, value++) {
182 *value *= gain;
183 }
184 }
185 }
186 iGuardMutex(&d->outputMutex, write_SampleBuf(&d->output, samples, n));
187 free(samples);
167} 188}
168 189
169static iThreadResult run_Decoder_(iThread *thread) { 190static iThreadResult run_Decoder_(iThread *thread) {
@@ -195,11 +216,14 @@ static iThreadResult run_Decoder_(iThread *thread) {
195 216
196void init_Decoder(iDecoder *d, iInputBuf *input, const iContentSpec *spec) { 217void init_Decoder(iDecoder *d, iInputBuf *input, const iContentSpec *spec) {
197 d->type = wav_DecoderType; 218 d->type = wav_DecoderType;
219 d->gain = 0.5f;
198 d->input = input; 220 d->input = input;
199 d->inputPos = spec->wavData.start; 221 d->inputPos = spec->wavData.start;
200 init_SampleBuf(&d->output, SDL_AUDIO_BITSIZE(spec->spec.format) / 8 * 222 init_SampleBuf(&d->output,
201 spec->spec.channels, spec->spec.samples * 2); 223 spec->spec.channels,
202 init_Mutex(&d->mtx); 224 SDL_AUDIO_BITSIZE(spec->spec.format) / 8 * spec->spec.channels,
225 spec->spec.samples * 2);
226 init_Mutex(&d->outputMutex);
203 d->thread = new_Thread(run_Decoder_); 227 d->thread = new_Thread(run_Decoder_);
204 setUserData_Thread(d->thread, d); 228 setUserData_Thread(d->thread, d);
205 start_Thread(d->thread); 229 start_Thread(d->thread);
@@ -210,7 +234,7 @@ void deinit_Decoder(iDecoder *d) {
210 signal_Condition(&d->input->changed); 234 signal_Condition(&d->input->changed);
211 join_Thread(d->thread); 235 join_Thread(d->thread);
212 iRelease(d->thread); 236 iRelease(d->thread);
213 deinit_Mutex(&d->mtx); 237 deinit_Mutex(&d->outputMutex);
214 deinit_SampleBuf(&d->output); 238 deinit_SampleBuf(&d->output);
215} 239}
216 240
@@ -289,8 +313,7 @@ static iContentSpec contentSpec_Player_(const iPlayer *d) {
289 (bitsPerSample == 8 ? AUDIO_S8 : bitsPerSample == 16 ? AUDIO_S16 : AUDIO_S32); 313 (bitsPerSample == 8 ? AUDIO_S8 : bitsPerSample == 16 ? AUDIO_S16 : AUDIO_S32);
290 } 314 }
291 else if (memcmp(magic, "data", 4) == 0) { 315 else if (memcmp(magic, "data", 4) == 0) {
292 size_t len = read32_Stream(is); /* data size */ 316 content.wavData = (iRanges){ pos_Stream(is), pos_Stream(is) + size };
293 content.wavData = (iRanges){ pos_Stream(is), pos_Stream(is) + len };
294 break; 317 break;
295 } 318 }
296 else { 319 else {
@@ -307,14 +330,14 @@ static void writeOutputSamples_Player_(void *plr, Uint8 *stream, int len) {
307 iAssert(d->decoder); 330 iAssert(d->decoder);
308 const size_t sampleSize = sampleSize_Player_(d); 331 const size_t sampleSize = sampleSize_Player_(d);
309 const size_t count = len / sampleSize; 332 const size_t count = len / sampleSize;
310 lock_Mutex(&d->decoder->mtx); 333 lock_Mutex(&d->decoder->outputMutex);
311 if (size_SampleBuf(&d->decoder->output) >= count) { 334 if (size_SampleBuf(&d->decoder->output) >= count) {
312 read_SampleBuf(&d->decoder->output, count, stream); 335 read_SampleBuf(&d->decoder->output, count, stream);
313 } 336 }
314 else { 337 else {
315 memset(stream, 0, len); /* TODO: If unsigned samples, don't use zero! */ 338 memset(stream, d->spec.silence, len);
316 } 339 }
317 unlock_Mutex(&d->decoder->mtx); 340 unlock_Mutex(&d->decoder->outputMutex);
318 /* Wake up decoder; there is more room for output. */ 341 /* Wake up decoder; there is more room for output. */
319 signal_Condition(&d->data->changed); 342 signal_Condition(&d->data->changed);
320} 343}
@@ -340,23 +363,23 @@ void setFormatHint_Player(iPlayer *d, const char *hint) {
340} 363}
341 364
342void updateSourceData_Player(iPlayer *d, const iBlock *data, enum iPlayerUpdate update) { 365void updateSourceData_Player(iPlayer *d, const iBlock *data, enum iPlayerUpdate update) {
343 iInputBuf *inp = d->data; 366 iInputBuf *input = d->data;
344 lock_Mutex(&inp->mtx); 367 lock_Mutex(&input->mtx);
345 switch (update) { 368 switch (update) {
346 case replace_PlayerUpdate: 369 case replace_PlayerUpdate:
347 set_Block(&inp->data, data); 370 set_Block(&input->data, data);
348 inp->isComplete = iFalse; 371 input->isComplete = iFalse;
349 break; 372 break;
350 case append_PlayerUpdate: 373 case append_PlayerUpdate:
351 append_Block(&inp->data, data); 374 append_Block(&input->data, data);
352 inp->isComplete = iFalse; 375 input->isComplete = iFalse;
353 break; 376 break;
354 case complete_PlayerUpdate: 377 case complete_PlayerUpdate:
355 inp->isComplete = iTrue; 378 input->isComplete = iTrue;
356 break; 379 break;
357 } 380 }
358 signal_Condition(&inp->changed); 381 signal_Condition(&input->changed);
359 unlock_Mutex(&inp->mtx); 382 unlock_Mutex(&input->mtx);
360} 383}
361 384
362iBool start_Player(iPlayer *d) { 385iBool start_Player(iPlayer *d) {