예제 #1
0
파일: ogg.c 프로젝트: sesc4mt/mvcdecoder
static size_t ogg_stream_update(ALLEGRO_AUDIO_STREAM *stream, void *data,
                                size_t buf_size)
{
   AL_OV_DATA *extra = (AL_OV_DATA *) stream->extra;
	
#ifdef ALLEGRO_LITTLE_ENDIAN
   const int endian = 0;      /* 0 for Little-Endian, 1 for Big-Endian */
#else
   const int endian = 1;      /* 0 for Little-Endian, 1 for Big-Endian */
#endif
   const int word_size = 2;   /* 1 = 8bit, 2 = 16-bit. nothing else */
   const int signedness = 1;  /* 0 for unsigned, 1 for signed */

   unsigned long pos = 0;
   int read_length = buf_size;
#if !defined(ALLEGRO_GP2XWIZ) && !defined(ALLEGRO_IPHONE)
   double ctime = ov_time_tell(extra->vf);
#else
   double ctime = ov_time_tell(extra->vf)/1000.0;
#endif
   double rate = extra->vi->rate;
   double btime = ((double)buf_size / (double)word_size) / rate;
   
   if (stream->spl.loop == _ALLEGRO_PLAYMODE_STREAM_ONEDIR) {
      if (ctime + btime > extra->loop_end) {
         read_length = (extra->loop_end - ctime) * rate * (double)word_size;
         if (read_length < 0)
            return 0;
         read_length += read_length % word_size;
         }
      }
   while (pos < (unsigned long)read_length) {
#if !defined(ALLEGRO_GP2XWIZ) && !defined(ALLEGRO_IPHONE)
      unsigned long read = ov_read(extra->vf, (char *)data + pos,
                                   read_length - pos, endian, word_size,
                                   signedness, &extra->bitstream);
#else
      (void)endian;
      (void)signedness;
      unsigned long read = ov_read(extra->vf, (char *)data + pos,
                                   read_length - pos, &extra->bitstream);
#endif
      pos += read;
	   
      /* If nothing read then now to silence from here to the end. */
      if (read == 0) {
         int silence = _al_kcm_get_silence(stream->spl.spl_data.depth);
         memset((char *)data + pos, silence, buf_size - pos);
         /* return the number of usefull byes written */
         return pos;
      }
   }

   return pos;
}
/* Custom routine which runs in another thread to periodically check if DirectSound
   wants more data for a stream */
static void* _dsound_update(ALLEGRO_THREAD *self, void *arg)
{
   ALLEGRO_VOICE *voice = (ALLEGRO_VOICE *)arg;
   ALLEGRO_DS_DATA *ex_data = (ALLEGRO_DS_DATA*)voice->extra;
   const int bytes_per_sample = ex_data->bits_per_sample / 8;
   DWORD play_cursor = 0;
   DWORD write_cursor;
   DWORD saved_play_cursor = 0;
   unsigned int samples;
   LPVOID ptr1, ptr2;
   DWORD block1_bytes, block2_bytes;
   unsigned char *data;
   HRESULT hr;

   (void)self;

   unsigned char *silence = (unsigned char *)al_malloc(buffer_size);
   int silence_value = _al_kcm_get_silence(voice->depth);
   memset(silence, silence_value, buffer_size);

   /* Fill buffer */
   hr = ex_data->ds8_buffer->Lock(0, buffer_size,
      &ptr1, &block1_bytes, &ptr2, &block2_bytes,
      DSBLOCK_ENTIREBUFFER);
   if (!FAILED(hr)) {
      samples = buffer_size / bytes_per_sample / ex_data->channels;
      data = (unsigned char *) _al_voice_update(voice, &samples);
      memcpy(ptr1, data, block1_bytes);
      memcpy(ptr2, data + block1_bytes, block2_bytes);
      ex_data->ds8_buffer->Unlock(ptr1, block1_bytes, ptr2, block2_bytes);
   }

   ex_data->ds8_buffer->Play(0, 0, DSBPLAY_LOOPING);

   do {
      if (!_dsound_voice_is_playing(voice)) {
         ex_data->ds8_buffer->Play(0, 0, DSBPLAY_LOOPING);
      }

      ex_data->ds8_buffer->GetCurrentPosition(&play_cursor, &write_cursor);

      /* We try to fill the gap between the saved_play_cursor and the
       * play_cursor.
       */
      int d = play_cursor - saved_play_cursor;
      if (d < 0)
         d += buffer_size;

      /* Don't fill small gaps.  Let it accumulate to amortise the cost of
       * mixing the samples and locking/unlocking the buffer.
       */
      if (d < MIN_FILL) {
         al_rest(0.005);
         continue;
      }

      /* Don't generate too many samples at once.  The buffer may underrun
       * while we wait for _al_voice_update to complete.
       */
      samples = d / bytes_per_sample / ex_data->channels;
      if (samples > MAX_FILL) {
         samples = MAX_FILL;
      }

      /* Generate the samples. */
      data = (unsigned char *) _al_voice_update(voice, &samples);
      if (data == NULL) {
         data = silence;
      }

      hr = ex_data->ds8_buffer->Lock(saved_play_cursor,
         samples * bytes_per_sample * ex_data->channels,
         &ptr1, &block1_bytes, &ptr2, &block2_bytes, 0);
      if (!FAILED(hr)) {
         memcpy(ptr1, data, block1_bytes);
         memcpy(ptr2, data + block1_bytes, block2_bytes);
         hr = ex_data->ds8_buffer->Unlock(ptr1, block1_bytes,
            ptr2, block2_bytes);
         if (FAILED(hr)) {
            ALLEGRO_ERROR("Unlock failed: %s\n", ds_get_error(hr));
         }
      }
      saved_play_cursor += block1_bytes + block2_bytes;
      saved_play_cursor %= buffer_size;
   } while (!ex_data->stop_voice);

   ex_data->ds8_buffer->Stop();

   al_free(silence);

   ex_data->stop_voice = 0;
   al_broadcast_cond(voice->cond);

   return NULL;
}
예제 #3
0
파일: oss.c 프로젝트: sesc4mt/mvcdecoder
static void* oss_update(ALLEGRO_THREAD *self, void *arg)
{
   ALLEGRO_VOICE *voice = arg;
   OSS_VOICE *oss_voice = voice->extra;
   (void)self;

   while (!oss_voice->quit_poll_thread) {
      /*
      For possible eventual non-blocking mode:

      audio_buf_info bi;

      if (ioctl(oss_voice->fd, SNDCTL_DSP_GETOSPACE, &bi) == -1) {
         TRACE(PREFIX_E "Error SNDCTL_DSP_GETOSPACE.\n");
         TRACE(PREFIX_E "errno: %i -- %s\n", errno, strerror(errno));
         return NULL;
      }

      len = bi.bytes;
      */

      /* How many bytes are we supposed to try to write at once? */
      unsigned int frames = 1024;

      if (oss_voice->stop && !oss_voice->stopped) {
         oss_voice->stopped = true;
      }

      if (!oss_voice->stop && oss_voice->stopped) {
         oss_voice->stopped = false;
      }

      if (!voice->is_streaming && !oss_voice->stopped) {
         void *buf;
         int bytes = frames * oss_voice->frame_size;

         oss_update_nonstream_voice(voice, &buf, &bytes);
         frames = bytes / oss_voice->frame_size;
         if (write(oss_voice->fd, buf, bytes) == -1) {
            ALLEGRO_ERROR("errno: %i -- %s\n", errno, strerror(errno));
            if (errno != EINTR)
               return NULL;
         }
      }
      else if (voice->is_streaming && !oss_voice->stopped) {
         const void *data = _al_voice_update(voice, &frames);
         if (data == NULL)
            goto silence;

         if (write(oss_voice->fd, data, frames * oss_voice->frame_size) == -1) {
            ALLEGRO_ERROR("errno: %i -- %s\n", errno, strerror(errno));
            if (errno != EINTR)
               return NULL;
         }
      }
      else {
silence:
         /* If stopped just fill with silence. */
         memset(sil_buf, _al_kcm_get_silence(voice->depth), SIL_BUF_SIZE);
         if(write(oss_voice->fd, sil_buf, SIL_BUF_SIZE) == -1) {
            ALLEGRO_ERROR("errno: %i -- %s\n", errno, strerror(errno));
         }
      }
   }

   return NULL;
}