gc_int32 gauX_sample_source_wav_read(void* in_context, void* in_dst, gc_int32 in_numSamples, tOnSeekFunc in_onSeekFunc, void* in_seekContext) { gau_SampleSourceWavContext* ctx = &((gau_SampleSourceWav*)in_context)->context; gc_int32 numRead = 0; gc_int32 totalSamples = ctx->wavHeader.dataSize / ctx->sampleSize; gc_mutex_lock(ctx->posMutex); if(ctx->pos + in_numSamples > totalSamples) in_numSamples = totalSamples - ctx->pos; if(in_numSamples > 0) { numRead = ga_data_source_read(ctx->dataSrc, in_dst, ctx->sampleSize, in_numSamples); ctx->pos += numRead; } gc_mutex_unlock(ctx->posMutex); return numRead; }
gc_int32 gauX_sample_source_sound_read(void* in_context, void* in_dst, gc_int32 in_numSamples, tOnSeekFunc in_onSeekFunc, void* in_seekContext) { gau_SampleSourceSoundContext* ctx = &((gau_SampleSourceSound*)in_context)->context; ga_Sound* snd = ctx->sound; char* src; gc_int32 pos; gc_int32 avail; gc_int32 numRead; gc_mutex_lock(ctx->posMutex); pos = ctx->pos; avail = ctx->numSamples - pos; numRead = in_numSamples > avail ? avail : in_numSamples; ctx->pos += numRead; gc_mutex_unlock(ctx->posMutex); src = (char*)ga_sound_data(snd) + pos * ctx->sampleSize; memcpy(in_dst, src, numRead * ctx->sampleSize); return numRead; }
void ga_stream_manager_buffer(ga_StreamManager* in_mgr) { gc_Link* link = in_mgr->streamList.next; while(link != &in_mgr->streamList) { gc_int32 streamDead; gaX_StreamLink* streamLink; streamLink = (gaX_StreamLink*)link->data; link = link->next; streamDead = gaX_stream_link_produce(streamLink); if(streamDead) { gc_mutex_lock(in_mgr->streamListMutex); gc_list_unlink((gc_Link*)streamLink); gc_mutex_unlock(in_mgr->streamListMutex); gaX_stream_link_release(streamLink); } } }
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; }
gc_int32 gauX_sample_source_ogg_read(void* in_context, void* in_dst, gc_int32 in_numSamples, tOnSeekFunc in_onSeekFunc, void* in_seekContext) { gau_SampleSourceOggContext* ctx = &((gau_SampleSourceOgg*)in_context)->context; gc_int32 samplesLeft = in_numSamples; gc_int32 samplesRead; gc_int32 channels = ctx->oggInfo->channels; gc_int32 totalSamples = 0; size_t dataSizeOff = 0; do{ gc_int32 bitStream; gc_float32** samples; gc_int32 i; gc_int16* dst; gc_int32 channel; gc_mutex_lock(ctx->oggMutex); samplesRead = ov_read_float(&ctx->oggFile, &samples, samplesLeft, &bitStream); if(samplesRead == 0) ctx->endOfSamples = 1; gc_mutex_unlock(ctx->oggMutex); if(samplesRead > 0) { samplesLeft -= samplesRead; dst = (gc_int16*)(in_dst) + totalSamples * channels; totalSamples += samplesRead; for(i = 0; i < samplesRead; ++i) { for(channel = 0; channel < channels; ++channel, ++dst) { gc_float32 sample = samples[channel][i] * 32768.0f; gc_int32 int32Sample = (gc_int32)sample; gc_int16 int16Sample; int32Sample = int32Sample > 32767 ? 32767 : int32Sample < -32768 ? -32768 : int32Sample; int16Sample = (gc_int16)int32Sample; *dst = int16Sample; } } } } while (samplesRead > 0 && samplesLeft); return totalSamples; }
gc_int32 gauX_data_source_memory_read(void* in_context, void* in_dst, gc_int32 in_size, gc_int32 in_count) { gau_DataSourceMemoryContext* ctx = (gau_DataSourceMemoryContext*)in_context; gc_int32 ret = 0; gc_int32 dataSize = ga_memory_size(ctx->memory); gc_int32 toRead = in_size * in_count; gc_int32 remaining; gc_mutex_lock(ctx->memMutex); remaining = dataSize - ctx->pos; toRead = toRead < remaining ? toRead : remaining; toRead = toRead - (toRead % in_size); if(toRead) { memcpy(in_dst, (char*)ga_memory_data(ctx->memory) + ctx->pos, toRead); ctx->pos += toRead; ret = toRead / in_size; } gc_mutex_unlock(ctx->memMutex); return ret; }
gc_int32 gauX_data_source_file_arc_seek(void* in_context, gc_int32 in_offset, gc_int32 in_origin) { /* TODO: What is the best way to resolve the seeking-OOB cases? */ gau_DataSourceFileArcContext* ctx = (gau_DataSourceFileArcContext*)in_context; gc_mutex_lock(ctx->fileMutex); switch(in_origin) { case GA_SEEK_ORIGIN_SET: if(ctx->size > 0 && in_offset > ctx->size) { gc_mutex_unlock(ctx->fileMutex); return -1; } fseek(ctx->f, ctx->offset + in_offset, SEEK_SET); break; case GA_SEEK_ORIGIN_CUR: { gc_int32 curPos = ftell(ctx->f) - ctx->offset; gc_int32 newPos = curPos + in_offset; if(newPos < 0 || (ctx->size > 0 && newPos > ctx->size)) { gc_mutex_unlock(ctx->fileMutex); return -1; } fseek(ctx->f, in_offset, SEEK_CUR); } break; case GA_SEEK_ORIGIN_END: if(ctx->size <= 0) { gc_mutex_unlock(ctx->fileMutex); return -1; } fseek(ctx->f, ctx->offset + ctx->size + in_offset, SEEK_SET); break; } gc_mutex_unlock(ctx->fileMutex); return 0; }
void ga_stream_acquire(ga_BufferedStream* in_stream) { gc_mutex_lock(in_stream->refMutex); ++in_stream->refCount; gc_mutex_unlock(in_stream->refMutex); }
void gaX_stream_link_acquire(gaX_StreamLink* in_streamLink) { gc_mutex_lock(in_streamLink->refMutex); ++in_streamLink->refCount; gc_mutex_unlock(in_streamLink->refMutex); }
void gaX_stream_link_kill(gaX_StreamLink* in_streamLink) { gc_mutex_lock(in_streamLink->produceMutex); in_streamLink->stream = 0; gc_mutex_unlock(in_streamLink->produceMutex); }
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); } } } } } }
void ga_sound_acquire(ga_Sound* in_sound) { gc_mutex_lock(in_sound->refMutex); ++in_sound->refCount; gc_mutex_unlock(in_sound->refMutex); }
void ga_memory_acquire(ga_Memory* in_mem) { gc_mutex_lock(in_mem->refMutex); ++in_mem->refCount; gc_mutex_unlock(in_mem->refMutex); }
void ga_sample_source_acquire(ga_SampleSource* in_sampleSrc) { gc_mutex_lock(in_sampleSrc->refMutex); ++in_sampleSrc->refCount; gc_mutex_unlock(in_sampleSrc->refMutex); }
void ga_data_source_acquire(ga_DataSource* in_dataSrc) { gc_mutex_lock(in_dataSrc->refMutex); ++in_dataSrc->refCount; gc_mutex_unlock(in_dataSrc->refMutex); }