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; }
void ga_stream_produce(ga_BufferedStream* in_stream) { ga_BufferedStream* s = in_stream; gc_CircBuffer* b = s->buffer; gc_int32 sampleSize = ga_format_sampleSize(&s->format); gc_int32 bytesFree = gc_buffer_bytesFree(b); if(s->seek >= 0) { gc_int32 samplePos; gc_mutex_lock(s->readMutex); gc_mutex_lock(s->seekMutex); if(s->seek >= 0) /* Check again now that we're mutexed */ { samplePos = s->seek; s->tell = samplePos; s->seek = -1; s->nextSample = samplePos; ga_sample_source_seek(s->innerSrc, samplePos); gc_buffer_consume(s->buffer, gc_buffer_bytesAvail(s->buffer)); /* Clear buffer */ gauX_tell_jump_clear(&s->tellJumps); /* Clear tell-jump list */ } gc_mutex_unlock(s->seekMutex); gc_mutex_unlock(s->readMutex); } while(bytesFree) { gc_int32 samplesWritten = 0; gc_int32 bytesWritten = 0; gc_int32 bytesToWrite = bytesFree; samplesWritten = gaX_read_samples_into_stream(s, b, bytesToWrite / sampleSize, s->innerSrc); bytesWritten = samplesWritten * sampleSize; bytesFree -= bytesWritten; s->nextSample += samplesWritten; if(bytesWritten < bytesToWrite && ga_sample_source_end(s->innerSrc)) { s->end = 1; break; } } }
gc_int32 gauX_sample_source_loop_end(void* in_context) { gau_SampleSourceLoopContext* ctx = &((gau_SampleSourceLoop*)in_context)->context; return ga_sample_source_end(ctx->innerSrc); }
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); } } } } } }