gc_int32 gaX_read_samples_into_stream(ga_BufferedStream* in_stream, gc_CircBuffer* in_buffer, gc_int32 in_samples, ga_SampleSource* in_sampleSrc) { void* dataA; void* dataB; gc_uint32 sizeA = 0; gc_uint32 sizeB = 0; gc_int32 numBuffers; gc_int32 numWritten = 0; ga_Format fmt; gc_int32 sampleSize; gc_CircBuffer* b = in_buffer; ga_sample_source_format(in_sampleSrc, &fmt); sampleSize = ga_format_sampleSize(&fmt); numBuffers = gc_buffer_getFree(b, in_samples * sampleSize, &dataA, &sizeA, &dataB, &sizeB); if(numBuffers >= 1) { numWritten = ga_sample_source_read(in_sampleSrc, dataA, sizeA / sampleSize, &gaX_stream_onSeek, in_stream); if(numBuffers == 2 && numWritten == sizeA) numWritten += ga_sample_source_read(in_sampleSrc, dataB, sizeB / sampleSize, &gaX_stream_onSeek, in_stream); } gc_buffer_produce(b, numWritten * sampleSize); return numWritten; }
ga_Sound* ga_sound_create_sample_source(ga_SampleSource* in_sampleSrc) { ga_Sound* ret = 0; ga_Format format; gc_int32 dataSize; gc_int32 totalSamples; ga_SampleSource* sampleSrc = in_sampleSrc; gc_int32 sampleSize; ga_sample_source_format(sampleSrc, &format); sampleSize = ga_format_sampleSize(&format); ga_sample_source_tell(sampleSrc, &totalSamples); if(totalSamples > 0) { /* Known total samples*/ char* data; ga_Memory* memory; dataSize = sampleSize * totalSamples; data = gcX_ops->allocFunc(dataSize); ga_sample_source_read(sampleSrc, data, totalSamples, 0, 0); memory = gaX_memory_create(data, dataSize, 0); if(memory) { ret = ga_sound_create(memory, &format); if(!ret) ga_memory_release(memory); } else gcX_ops->freeFunc(data); } else { /* Unknown total samples */ gc_int32 BUFFER_SAMPLES = format.sampleRate * 2; char* data = 0; ga_Memory* memory; totalSamples = 0; while(!ga_sample_source_end(sampleSrc)) { gc_int32 numSamplesRead; data = gcX_ops->reallocFunc(data, (totalSamples + BUFFER_SAMPLES) * sampleSize); numSamplesRead = ga_sample_source_read(sampleSrc, data + (totalSamples * sampleSize), BUFFER_SAMPLES, 0, 0); if(numSamplesRead < BUFFER_SAMPLES) { data = gcX_ops->reallocFunc(data, (totalSamples + numSamplesRead) * sampleSize); } totalSamples += numSamplesRead; } memory = gaX_memory_create(data, totalSamples * sampleSize, 0); if(memory) { ret = ga_sound_create(memory, &format); if(!ret) ga_memory_release(memory); } else gcX_ops->freeFunc(data); } return ret; }
gc_int32 gauX_sample_source_loop_read(void* in_context, void* in_dst, gc_int32 in_numSamples, tOnSeekFunc in_onSeekFunc, void* in_seekContext) { gau_SampleSourceLoopContext* ctx = &((gau_SampleSourceLoop*)in_context)->context; gc_int32 numRead = 0; gc_int32 triggerSample, targetSample; gc_int32 pos, total; gc_int32 sampleSize; gc_int32 totalRead = 0; ga_SampleSource* ss = ctx->innerSrc; gc_mutex_lock(ctx->loopMutex); triggerSample = ctx->triggerSample; targetSample = ctx->targetSample; gc_mutex_unlock(ctx->loopMutex); pos = ga_sample_source_tell(ss, &total); if((targetSample < 0 && triggerSample <= 0)) return ga_sample_source_read(ss, in_dst, in_numSamples, 0, 0); if(triggerSample <= 0) triggerSample = total; if(pos > triggerSample) return ga_sample_source_read(ss, in_dst, in_numSamples, 0, 0); sampleSize = ctx->sampleSize; while(in_numSamples) { gc_int32 avail = triggerSample - pos; gc_int32 doSeek = avail <= in_numSamples; gc_int32 toRead = doSeek ? avail : in_numSamples; numRead = ga_sample_source_read(ss, in_dst, toRead, 0, 0); totalRead += numRead; in_numSamples -= numRead; in_dst = (char*)in_dst + numRead * sampleSize; if(doSeek && toRead == numRead) { ga_sample_source_seek(ss, targetSample); ++ctx->loopCount; if(in_onSeekFunc) in_onSeekFunc(totalRead, targetSample - triggerSample, in_seekContext); } pos = ga_sample_source_tell(ss, &total); } return totalRead; }
void gaX_mixer_mix_handle(ga_Mixer* in_mixer, ga_Handle* in_handle, gc_int32 in_numSamples) { ga_Handle* h = in_handle; ga_Mixer* m = in_mixer; ga_SampleSource* ss = h->sampleSrc; if(ga_sample_source_end(ss)) { /* Stream is finished! */ gc_mutex_lock(h->handleMutex); if(h->state < GA_HANDLE_STATE_FINISHED) h->state = GA_HANDLE_STATE_FINISHED; gc_mutex_unlock(h->handleMutex); return; } else { if(h->state == GA_HANDLE_STATE_PLAYING) { ga_Format handleFormat; ga_sample_source_format(ss, &handleFormat); { /* Check if we have enough samples to stream a full buffer */ gc_int32 srcSampleSize = ga_format_sampleSize(&handleFormat); gc_int32 dstSampleSize = ga_format_sampleSize(&m->format); gc_float32 oldPitch = h->pitch; gc_float32 dstToSrc = handleFormat.sampleRate / (gc_float32)m->format.sampleRate * oldPitch; gc_int32 requested = (gc_int32)(in_numSamples * dstToSrc); requested = requested / dstToSrc < in_numSamples ? requested + 1 : requested; if(requested > 0 && ga_sample_source_ready(ss, requested)) { gc_float32 gain, pan, pitch; gc_int32* dstBuffer; gc_int32 dstSamples; gc_mutex_lock(h->handleMutex); gain = h->gain; pan = h->pan; pitch = h->pitch; gc_mutex_unlock(h->handleMutex); /* We avoided a mutex lock by using pitch to check if buffer has enough dst samples */ /* If it has changed since then, we re-test to make sure we still have enough samples */ if(oldPitch != pitch) { dstToSrc = handleFormat.sampleRate / (gc_float32)m->format.sampleRate * pitch; requested = (gc_int32)(in_numSamples * dstToSrc); requested = requested / dstToSrc < in_numSamples ? requested + 1 : requested; if(!(requested > 0 && ga_sample_source_ready(ss, requested))) return; } dstBuffer = &m->mixBuffer[0]; dstSamples = in_numSamples; { /* TODO: To optimize, we can refactor the _read() interface to be _mix(), avoiding this malloc/copy */ gc_int32 bufferSize = requested * srcSampleSize; void* src = gcX_ops->allocFunc(bufferSize); gc_int32 dstBytes = dstSamples * dstSampleSize; gc_int32 numRead = 0; numRead = ga_sample_source_read(ss, src, requested, 0, 0); gaX_mixer_mix_buffer(in_mixer, src, numRead, &handleFormat, dstBuffer, dstSamples, &m->format, gain, pan, pitch); gcX_ops->freeFunc(src); } } } } } }