Esempio n. 1
0
static void switch_buffers()
{
	if (playing && buffered > 0)
	{
		AUDIO_InitDMA((u32)buffers[buffer_play], BUFFER_SIZE);
		buffer_play = (buffer_play + 1) % BUFFER_COUNT;
		buffered -= BUFFER_SIZE;
	}
	else
	{
		AUDIO_InitDMA((u32)silence, BUFFER_SIZE);
	}
}
Esempio n. 2
0
static void *gx_audio_init(const char *device, unsigned rate, unsigned latency)
{
   gx_audio_t *wa = (gx_audio_t*)memalign(32, sizeof(*wa));
   if (!wa)
      return NULL;

   gx_audio_data = wa;

   memset(wa, 0, sizeof(*wa));

   AUDIO_Init(NULL);
   AUDIO_RegisterDMACallback(dma_callback);

   if (rate < 33000)
   {
      AUDIO_SetDSPSampleRate(AI_SAMPLERATE_32KHZ);
      g_settings.audio.out_rate = 32000;
   }
   else
   {
      AUDIO_SetDSPSampleRate(AI_SAMPLERATE_48KHZ);
      g_settings.audio.out_rate = 48000;
   }

   LWP_InitQueue(&wa->cond);

   wa->dma_write = BLOCKS - 1;
   DCFlushRange(wa->data, sizeof(wa->data));
   AUDIO_InitDMA((uint32_t)wa->data[wa->dma_next], CHUNK_SIZE);
   AUDIO_StartDMA();

   return wa;
}
Esempio n. 3
0
int
sound_lowlevel_init( const char *device, int *freqptr, int *stereoptr )
{
  switch(*freqptr) {
  case 32000:
    samplerate = AI_SAMPLERATE_32KHZ;
    break;
  case 48000:
    samplerate = AI_SAMPLERATE_48KHZ;
    break;
  default:
    printf("Sample rate %d not supported on Wii\n", *freqptr);
    return 1;
  }

  sfifo_init( &sound_fifo, BUFSIZE );
  *stereoptr = 1;
  
  AUDIO_Init( NULL );
  AUDIO_SetDSPSampleRate( samplerate );

#ifndef DISPLAY_AUDIO
  AUDIO_RegisterDMACallback( sound_dmacallback );
  memset( dmabuf, 0, BUFSIZE );
  AUDIO_InitDMA( (u32)dmabuf, BUFSIZE );
  DCFlushRange( dmabuf, dmalen );
  AUDIO_StartDMA();
#endif
  
  return 0;
}
Esempio n. 4
0
/*** 
      gx_audio_Update

     This function retrieves samples for the frame then set the next DMA parameters 
     Parameters will be taken in account only when current DMA operation is over

     To keep audio & video synchronized, DMA from external memory to audio interface is 
     started once by video update function when first frame is ready to be displayed, 
     then anytime video mode is changed and emulation resynchronized to video hardware.

     Once started, audio DMA restarts automatically when all samples have been played.
     At that time:
       - if DMA settings have not been updated, previous sound buffer will be played again
       - if DMA settings are updated too fast, one sound buffer frame might be skipped
     
     Therefore, in order to maintain perfect audio playback without any sound skipping  
     or lagging, we need to make sure frame emulation is completed and this function is 
     called before previous DMA transfer is finished and after it has been started.

     This is done by synchronizing frame emulation with audio DMA interrupt (which happens
     anytime audio DMA restarts). When video sync is enabled, to keep emulation in sync 
     with both video AND audio, an appropriate number of samples is rendered per frame by
     adjusting emulator output samplerate.
 ***/
int gx_audio_Update(int status)
{
  /* Current available soundbuffer */
  s16 *sb = (s16 *)(soundbuffer[bufferIndex]);

  /* Make sure current audio frame has not already been updated */
  if (status & AUDIO_UPDATE)
  {
    /* Retrieve audio samples (size must be multiple of 32 bytes) */
    bufferSize = audio_update(sb) * 4;
    DCFlushRange((void *)sb, bufferSize);

    /* Mark current audio frame as being updated */
    status &= ~AUDIO_UPDATE;
  }

  /* Wait until previous audio frame is started before pushing current audio frame into DMA */
  if ((status & AUDIO_WAIT) && !audioWait)
  {
    /* Update audio DMA settings for current frame */
    AUDIO_InitDMA((u32)sb, bufferSize);

    /* Next soundbuffer */
    bufferIndex = (bufferIndex + 1) % SOUND_BUFFER_NUM;

    /* Set audio wait flag */
    audioWait = audioSync;

    /* Current audio frame is ready for upcoming DMA */
    status &= ~AUDIO_WAIT;
  }

  return status;  
}
Esempio n. 5
0
// Called whenever more audio data is required.
static void play_more_audio()
{
	// Copy from mix buffer to DMA buffer.
	sample* const		src_begin	= &mix_buffer[mix_buffer_pointer];
	sample* const		dst_begin	= &dma_buffers[current_dma_buffer][0];
	const sample* const	dst_end		= dst_begin + samples_per_dma_buffer;
	sample*				src			= src_begin;
	sample*				dst			= dst_begin;
	while (dst != dst_end)
	{
		// We have to swap the channels, because Quake stores the left
		// channel first, whereas the GameCube expects right first.
		const u32 mix_sample = *src;
		*src++ = 0;
		*dst++ = (mix_sample >> 16) | ((mix_sample & 0x0000ffff) << 16);
	}

	// Set up the DMA.
	const u32		dma_src_address	= (u32)(dst_begin);
	const size_t	bytes			= samples_per_dma_buffer * sizeof(sample);
	AUDIO_InitDMA(dma_src_address, bytes);

	// Flush the data cache.
	DCFlushRange(dst_begin, bytes);

	// Start the DMA.
	AUDIO_StartDMA();

	// Move the mix buffer pointer.
	mix_buffer_pointer = (mix_buffer_pointer + samples_per_dma_buffer) % samples_per_mix_buffer;

	// Use the other DMA buffer next time.
	current_dma_buffer = 1 - current_dma_buffer;
}
Esempio n. 6
0
/*** 
      gx_audio_Update

     This function retrieves samples for the frame then set the next DMA parameters 
     Parameters will be taken in account only when current DMA operation is over
 ***/
void gx_audio_Update(void)
{
  /* retrieve audio samples */
  int size = audio_update() * 4;

  /* set next DMA soundbuffer */
  s16 *sb = (s16 *)(soundbuffer[mixbuffer]);
  DCFlushRange((void *)sb, size);
  AUDIO_InitDMA((u32) sb, size);
  mixbuffer ^= 1;

  /* Start Audio DMA */
  /* this is called once to kick-off DMA from external memory to audio interface        */
  /* DMA operation is automatically restarted when all samples have been sent.          */
  /* If DMA settings are not updated at that time, previous sound buffer will be used.  */
  /* Therefore we need to make sure frame emulation is completed before current DMA is  */
  /* completed, either by synchronizing frame emulation with DMA start or by syncing it */
  /* with Vertical Interrupt and outputing a suitable number of samples per frame.      */
  /*                                                                                    */
  /* In both cases, audio DMA need to be synchronized with VSYNC and therefore need to  */
  /* be resynchronized (restarted) every time video settings are changed (hopefully,    */
  /* this generally happens while no music is played.                                   */                    
  if (!audioStarted)
  {
    /* restart audio DMA */
    AUDIO_StopDMA();
    AUDIO_StartDMA();
    audioStarted = 1;

    /* resynchronize emulation */
    frameticker = 1;
  }
}
Esempio n. 7
0
static void dma_callback(void)
{
   g_audio->dma_busy = g_audio->dma_next;
   g_audio->dma_next = (g_audio->dma_next + 1) & (BLOCKS - 1);

   DCFlushRange(g_audio->data[g_audio->dma_next], CHUNK_SIZE);
   AUDIO_InitDMA((u32)g_audio->data[g_audio->dma_next], CHUNK_SIZE);

   LWP_ThreadSignal(g_audio->cond);
}
Esempio n. 8
0
static void
sound_dmacallback( void )
{
  if( sfifo_used( &sound_fifo ) < 128) return;
  
  dmalen = MIN( BUFSIZE, sfifo_used( &sound_fifo ) );
  sfifo_read( &sound_fifo, dmabuf, dmalen );
  DCFlushRange( dmabuf, dmalen );
  AUDIO_InitDMA( (u32)dmabuf, dmalen );
  AUDIO_StartDMA();
}
Esempio n. 9
0
static void StartDMA(void)
{
    AUDIO_StopDMA();
    soundpos++;
    if (soundpos >= NUMSOUNDBLOCKS)
        soundpos = 0;

    AUDIO_InitDMA((u32)stereodata16[soundpos], soundtruelen * 4);
    DCFlushRange((void *)stereodata16[soundpos], soundtruelen * 4);
    AUDIO_StartDMA();
}
Esempio n. 10
0
static void 
switch_buffers(void)
{
  AUDIO_StopDMA();
  
  cur_buffer ^= 1;

  AUDIO_InitDMA((u32)buffer[cur_buffer], buffer_size[cur_buffer]);
  AUDIO_StartDMA();

  LWP_ThreadSignal(audio_queue);
}
Esempio n. 11
0
static void dma_callback(void)
{
   gx_audio_t *wa = (gx_audio_t*)gx_audio_data;
   // erase last chunk to avoid repeating audio
   memset(wa->data[wa->dma_busy], 0, CHUNK_SIZE);

   wa->dma_busy = wa->dma_next;
   wa->dma_next = (wa->dma_next + 1) & (BLOCKS - 1);

   DCFlushRange(wa->data[wa->dma_next], CHUNK_SIZE);
   AUDIO_InitDMA((uint32_t)wa->data[wa->dma_next], CHUNK_SIZE);

   LWP_ThreadSignal(wa->cond);
}
Esempio n. 12
0
int SNDWiiInit()
{
    AUDIO_Init(NULL);
    AUDIO_SetDSPSampleRate(AI_SAMPLERATE_48KHZ);

    soundpos = 0;
    soundlen = 44100 / 60; // 60 for NTSC or 50 for PAL. Initially assume it's going to be NTSC.
    soundtruelen = 48000 / 60;
    truesoundoffset = stereodata16[0];

    memset(stereodata16, 0, SOUNDBUFSIZE);

    issoundmuted = 0;

    AUDIO_RegisterDMACallback(StartDMA);
    AUDIO_InitDMA((u32)stereodata16[soundpos], soundlen * 4);
    DCFlushRange((void *)stereodata16[soundpos], soundlen * 4);
    AUDIO_StartDMA();

    return 0;
}
Esempio n. 13
0
void OSystem_Wii::initSfx() {
	_mixer = new Audio::MixerImpl(this, 48000);

	sfx_thread_running = false;
	sfx_thread_quit = false;

	sfx_stack = (u8 *) memalign(32, SFX_THREAD_STACKSIZE);

	if (sfx_stack) {
		memset(sfx_stack, 0, SFX_THREAD_STACKSIZE);

		LWP_InitQueue(&sfx_queue);

		s32 res = LWP_CreateThread(&sfx_thread, sfx_thread_func, _mixer, sfx_stack,
									SFX_THREAD_STACKSIZE, SFX_THREAD_PRIO);

		if (res) {
			printf("ERROR creating sfx thread: %d\n", res);
			LWP_CloseQueue(sfx_queue);
			return;
		}

		sfx_thread_running = true;
	}

	for (u32 i = 0; i < SFX_BUFFERS; ++i) {
		sound_buffer[i] = (u8 *) memalign(32, SFX_THREAD_FRAG_SIZE);
		memset(sound_buffer[i], 0, SFX_THREAD_FRAG_SIZE);
		DCFlushRange(sound_buffer[i], SFX_THREAD_FRAG_SIZE);
	}

	_mixer->setReady(true);

	sb_hw = 0;

	AUDIO_SetDSPSampleRate(AI_SAMPLERATE_48KHZ);
	AUDIO_RegisterDMACallback(audio_switch_buffers);
	AUDIO_InitDMA((u32) sound_buffer[sb_hw], SFX_THREAD_FRAG_SIZE);
	AUDIO_StartDMA();
}
Esempio n. 14
0
static void *gx_audio_init(const char *device, unsigned rate, unsigned latency)
{
   if (g_audio)
      return g_audio;

   AUDIO_Init(NULL);
   AUDIO_RegisterDMACallback(dma_callback);

   if (rate < 33000)
   {
      AUDIO_SetDSPSampleRate(AI_SAMPLERATE_32KHZ);
      g_settings.audio.out_rate = 32000;
   }
   else
   {
      AUDIO_SetDSPSampleRate(AI_SAMPLERATE_48KHZ);
      g_settings.audio.out_rate = 48000;
   }

   if (!g_audio)
   {
      g_audio = memalign(32, sizeof(*g_audio));
      memset(g_audio, 0, sizeof(*g_audio));
      LWP_InitQueue(&g_audio->cond);
   }
   else
   {
      memset(g_audio->data, 0, sizeof(g_audio->data));
      g_audio->dma_busy = g_audio->dma_next = 0;
      g_audio->write_ptr = 0;
      g_audio->nonblock = false;
   }

   g_audio->dma_write = BLOCKS - 1;
   DCFlushRange(g_audio->data, sizeof(g_audio->data));
   AUDIO_InitDMA((u32)g_audio->data[g_audio->dma_next], CHUNK_SIZE);
   AUDIO_StartDMA();

   return g_audio;
}
Esempio n. 15
0
static void inline play_buffer(void){
#ifndef THREADED_AUDIO
	// We should wait for the other buffer to finish its DMA transfer first
	while( AUDIO_GetDMABytesLeft() );
	AUDIO_StopDMA();

#else // THREADED_AUDIO
	// Wait for a sample to actually be played to work around a deadlock
	LWP_SemWait(first_audio);
	
	// This thread will keep giving buffers to the audio as they come
	while(thread_running){

	// Wait for a buffer to be processed
	LWP_SemWait(buffer_full);
#endif

	// Make sure the buffer is in RAM, not the cache
	DCFlushRange(buffer[thread_buffer], buffer_size);

	// Actually send the buffer out to be played next
	AUDIO_InitDMA((unsigned int)&buffer[thread_buffer], buffer_size);

#ifdef THREADED_AUDIO
	// Wait for the audio interface to be free before playing
	LWP_SemWait(audio_free);
#endif

	// Start playing the buffer
	AUDIO_StartDMA();

#ifdef THREADED_AUDIO
	// Move the index to the next buffer
	NEXT(thread_buffer);
	}
#endif
}
Esempio n. 16
0
static void audio_switch_buffers() {
	sb_hw = (sb_hw + 1) % SFX_BUFFERS;
	AUDIO_InitDMA((u32) sound_buffer[sb_hw], SFX_THREAD_FRAG_SIZE);
	LWP_ThreadSignal(sfx_queue);
}