Ejemplo n.º 1
0
Archivo: ga.c Proyecto: Botyto/Core
void ga_data_source_release(ga_DataSource* in_dataSrc)
{
  gc_int32 refCount;
  assert(in_dataSrc->refCount > 0);
  gc_mutex_lock(in_dataSrc->refMutex);
  --in_dataSrc->refCount;
  refCount = in_dataSrc->refCount;
  gc_mutex_unlock(in_dataSrc->refMutex);
  if(refCount == 0)
    gaX_data_source_destroy(in_dataSrc);
}
Ejemplo n.º 2
0
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;
    }
  }
}
Ejemplo n.º 3
0
gc_int32 gauX_sample_source_ogg_tell(void* in_context, gc_int32* out_totalSamples)
{
  gau_SampleSourceOggContext* ctx = &((gau_SampleSourceOgg*)in_context)->context;
  gc_int32 ret;
  gc_mutex_lock(ctx->oggMutex);
  /* TODO: Decide whether to support total samples for OGG files */
  if(out_totalSamples)
    *out_totalSamples = ov_pcm_total(&ctx->oggFile, -1); /* Note: This isn't always valid when the stream is poorly-formatted */
  ret = (gc_int32)ov_pcm_tell(&ctx->oggFile);
  gc_mutex_unlock(ctx->oggMutex);
  return ret;
}
Ejemplo n.º 4
0
gaX_StreamLink* gaX_stream_manager_add(ga_StreamManager* in_mgr, ga_BufferedStream* in_stream)
{
  gaX_StreamLink* streamLink = gaX_stream_link_create(in_stream);
  gaX_stream_link_acquire(streamLink); /* The new client adds its own refcount */
  /* It's safe to add() while iterating in stream() because of implicit fault tolerance */
  /* That is, all possible outcomes are valid, despite the race condition */
  /* This is true because we are guaranteed to stream() on the same thread that calls remove() */
  gc_mutex_lock(in_mgr->streamListMutex);
  streamLink->stream = in_stream;
  gc_list_link(&in_mgr->streamList, (gc_Link*)streamLink, streamLink);
  gc_mutex_unlock(in_mgr->streamListMutex);
  return streamLink;
}
Ejemplo n.º 5
0
gc_int32 gauX_data_source_file_seek(void* in_context, gc_int32 in_offset, gc_int32 in_origin)
{
  gau_DataSourceFileContext* ctx = (gau_DataSourceFileContext*)in_context;
  gc_mutex_lock(ctx->fileMutex);
  switch(in_origin)
  {
  case GA_SEEK_ORIGIN_SET: fseek(ctx->f, in_offset, SEEK_SET); break;
  case GA_SEEK_ORIGIN_CUR: fseek(ctx->f, in_offset, SEEK_CUR); break;
  case GA_SEEK_ORIGIN_END: fseek(ctx->f, in_offset, SEEK_END); break;
  }
  gc_mutex_unlock(ctx->fileMutex);
  return 0;
}
Ejemplo n.º 6
0
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;
}
Ejemplo n.º 7
0
Archivo: ga.c Proyecto: Botyto/Core
gc_result ga_mixer_mix(ga_Mixer* in_mixer, void* out_buffer)
{
  gc_int32 i;
  ga_Mixer* m = in_mixer;
  gc_Link* link;
  gc_int32 end = m->numSamples * m->format.numChannels;
  ga_Format* fmt = &m->format;
  gc_int32 mixSampleSize = ga_format_sampleSize(&m->mixFormat);
  memset(&m->mixBuffer[0], 0, m->numSamples * mixSampleSize);

  link = m->mixList.next;
  while(link != &m->mixList)
  {
    ga_Handle* h = (ga_Handle*)link->data;
    gc_Link* oldLink = link;
    link = link->next;
    gaX_mixer_mix_handle(m, (ga_Handle*)h, m->numSamples);
    if(ga_handle_finished(h))
    {
      gc_mutex_lock(m->mixMutex);
      gc_list_unlink(oldLink);
      gc_mutex_unlock(m->mixMutex);
    }
  }

  switch(fmt->bitsPerSample) /* mixBuffer will already be correct bps */
  {
  case 8:
    {
      gc_int8* mix = (gc_int8*)out_buffer;
      for(i = 0; i < end; ++i)
      {
        gc_int32 sample = m->mixBuffer[i];
        mix[i] = (gc_int8)(sample > -128 ? (sample < 127 ? sample : 127) : -128);
      }
      break;
    }
  case 16:
    {
      gc_int16* mix = (gc_int16*)out_buffer;
      for(i = 0; i < end; ++i)
      {
        gc_int32 sample = m->mixBuffer[i];
        mix[i] = (gc_int16)(sample > -32768 ? (sample < 32767 ? sample : 32767) : -32768);
      }
      break;
    }
  }
  return GC_SUCCESS;
}
Ejemplo n.º 8
0
gc_int32 gaX_stream_link_produce(gaX_StreamLink* in_streamLink)
{
  gc_int32 ret = 1;
  gc_mutex_lock(in_streamLink->produceMutex);
  if(in_streamLink->stream)
  {
    /* Mutexing this entire section guarantees that ga_stream_destroy()
       cannot occur during production */
    ga_stream_produce(in_streamLink->stream);
    ret = 0;
  }
  gc_mutex_unlock(in_streamLink->produceMutex);
  return ret;
}
Ejemplo n.º 9
0
Archivo: ga.c Proyecto: Botyto/Core
gc_result ga_handle_setParamf(ga_Handle* in_handle, gc_int32 in_param,
                              gc_float32 in_value)
{
  ga_Handle* h = in_handle;
  switch(in_param)
  {
  case GA_HANDLE_PARAM_GAIN:
    gc_mutex_lock(h->handleMutex);
    h->gain = in_value;
    gc_mutex_unlock(h->handleMutex);
    return GC_SUCCESS;
  case GA_HANDLE_PARAM_PAN:
    gc_mutex_lock(h->handleMutex);
    h->pan = in_value;
    gc_mutex_unlock(h->handleMutex);
    return GC_SUCCESS;
  case GA_HANDLE_PARAM_PITCH:
    gc_mutex_lock(h->handleMutex);
    h->pitch = in_value;
    gc_mutex_unlock(h->handleMutex);
    return GC_SUCCESS;
  }
  return GC_ERROR_GENERIC;
}
Ejemplo n.º 10
0
gc_int32 gauX_data_source_memory_seek(void* in_context, gc_int32 in_offset, gc_int32 in_origin)
{
  gau_DataSourceMemoryContext* ctx = (gau_DataSourceMemoryContext*)in_context;
  gc_int32 dataSize = ga_memory_size(ctx->memory);
  gc_mutex_lock(ctx->memMutex);
  switch(in_origin)
  {
  case GA_SEEK_ORIGIN_SET: ctx->pos = in_offset; break;
  case GA_SEEK_ORIGIN_CUR: ctx->pos += in_offset; break;
  case GA_SEEK_ORIGIN_END: ctx->pos = dataSize - in_offset; break;
  }
  ctx->pos = ctx->pos < 0 ? 0 : ctx->pos > dataSize ? dataSize : ctx->pos;
  gc_mutex_unlock(ctx->memMutex);
  return 0;
}
Ejemplo n.º 11
0
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;
}
Ejemplo n.º 12
0
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);
    }
  }
}
Ejemplo n.º 13
0
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;
}
Ejemplo n.º 14
0
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;
}
Ejemplo n.º 15
0
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;
}
Ejemplo n.º 16
0
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;
}
Ejemplo n.º 17
0
Archivo: ga.c Proyecto: Botyto/Core
void ga_data_source_acquire(ga_DataSource* in_dataSrc)
{
  gc_mutex_lock(in_dataSrc->refMutex);
  ++in_dataSrc->refCount;
  gc_mutex_unlock(in_dataSrc->refMutex);
}
Ejemplo n.º 18
0
Archivo: ga.c Proyecto: Botyto/Core
void ga_sample_source_acquire(ga_SampleSource* in_sampleSrc)
{
  gc_mutex_lock(in_sampleSrc->refMutex);
  ++in_sampleSrc->refCount;
  gc_mutex_unlock(in_sampleSrc->refMutex);
}
Ejemplo n.º 19
0
Archivo: ga.c Proyecto: Botyto/Core
void ga_memory_acquire(ga_Memory* in_mem)
{
  gc_mutex_lock(in_mem->refMutex);
  ++in_mem->refCount;
  gc_mutex_unlock(in_mem->refMutex);
}
Ejemplo n.º 20
0
Archivo: ga.c Proyecto: Botyto/Core
void ga_sound_acquire(ga_Sound* in_sound)
{
  gc_mutex_lock(in_sound->refMutex);
  ++in_sound->refCount;
  gc_mutex_unlock(in_sound->refMutex);
}
Ejemplo n.º 21
0
Archivo: ga.c Proyecto: Botyto/Core
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);
          }
        }
      }
    }
  }
}
Ejemplo n.º 22
0
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);
}
Ejemplo n.º 23
0
void gaX_stream_link_acquire(gaX_StreamLink* in_streamLink)
{
  gc_mutex_lock(in_streamLink->refMutex);
  ++in_streamLink->refCount;
  gc_mutex_unlock(in_streamLink->refMutex);
}
Ejemplo n.º 24
0
void ga_stream_acquire(ga_BufferedStream* in_stream)
{
  gc_mutex_lock(in_stream->refMutex);
  ++in_stream->refCount;
  gc_mutex_unlock(in_stream->refMutex);
}