mirror of
https://github.com/libretro/RetroArch.git
synced 2025-02-11 12:05:52 +00:00
(CTR/3DS) audio driver: use cpu tick count instead of csndGetState to
determine the playback position. fixes a random lockup that can happen when calling csndGetState, and also removes the need to rely on samplePAddr since it doesn't seem to available on all systems.
This commit is contained in:
parent
2076846a5c
commit
1575b7e87f
@ -21,20 +21,24 @@
|
||||
typedef struct
|
||||
{
|
||||
bool nonblocking;
|
||||
bool playing;
|
||||
int16_t* l;
|
||||
int16_t* r;
|
||||
int16_t* silence;
|
||||
|
||||
uint32_t l_paddr;
|
||||
uint32_t r_paddr;
|
||||
uint32_t silence_paddr;
|
||||
|
||||
uint32_t pos;
|
||||
|
||||
uint32_t playpos;
|
||||
uint32_t cpu_ticks_per_sample;
|
||||
uint64_t cpu_ticks_last;
|
||||
|
||||
int rate;
|
||||
|
||||
} ctr_audio_t;
|
||||
|
||||
#define CTR_AUDIO_COUNT (1u << 12u)
|
||||
#define CTR_AUDIO_COUNT (1u << 11u)
|
||||
#define CTR_AUDIO_COUNT_MASK (CTR_AUDIO_COUNT - 1u)
|
||||
#define CTR_AUDIO_SIZE (CTR_AUDIO_COUNT * sizeof(int16_t))
|
||||
#define CTR_AUDIO_SIZE_MASK (CTR_AUDIO_SIZE - 1u)
|
||||
@ -52,31 +56,30 @@ static void *ctr_audio_init(const char *device, unsigned rate, unsigned latency)
|
||||
|
||||
ctr_audio_t *ctr = (ctr_audio_t*)calloc(1, sizeof(ctr_audio_t));
|
||||
|
||||
ctr->l = linearAlloc(CTR_AUDIO_SIZE);
|
||||
ctr->r = linearAlloc(CTR_AUDIO_SIZE);
|
||||
ctr->silence = linearAlloc(CTR_AUDIO_SIZE);
|
||||
ctr->l = linearAlloc(CTR_AUDIO_SIZE);
|
||||
ctr->r = linearAlloc(CTR_AUDIO_SIZE);
|
||||
|
||||
memset(ctr->l, 0, CTR_AUDIO_SIZE);
|
||||
memset(ctr->r, 0, CTR_AUDIO_SIZE);
|
||||
memset(ctr->silence, 0, CTR_AUDIO_SIZE);
|
||||
memset(ctr->l, 0, CTR_AUDIO_SIZE);
|
||||
memset(ctr->r, 0, CTR_AUDIO_SIZE);
|
||||
|
||||
ctr->l_paddr = osConvertVirtToPhys((u32)ctr->l);
|
||||
ctr->r_paddr = osConvertVirtToPhys((u32)ctr->r);
|
||||
ctr->silence_paddr = osConvertVirtToPhys((u32)ctr->silence);
|
||||
ctr->l_paddr = osConvertVirtToPhys((u32)ctr->l);
|
||||
ctr->r_paddr = osConvertVirtToPhys((u32)ctr->r);
|
||||
|
||||
ctr->pos = 0;
|
||||
ctr->rate = rate;
|
||||
ctr->cpu_ticks_per_sample = CSND_TIMER(rate) * 4;
|
||||
|
||||
GSPGPU_FlushDataCache(NULL, (u8*)ctr->silence, CTR_AUDIO_SIZE);
|
||||
GSPGPU_FlushDataCache(NULL, (u8*)ctr->l_paddr, CTR_AUDIO_SIZE);
|
||||
GSPGPU_FlushDataCache(NULL, (u8*)ctr->r_paddr, CTR_AUDIO_SIZE);
|
||||
csndPlaySound(0x8, SOUND_LOOPMODE(CSND_LOOPMODE_NORMAL)| SOUND_FORMAT(CSND_ENCODING_PCM16),
|
||||
rate, ctr->silence, ctr->silence, CTR_AUDIO_SIZE);
|
||||
rate, 1.0, -1.0, ctr->l, ctr->l, CTR_AUDIO_SIZE);
|
||||
|
||||
csndPlaySound(0x9, SOUND_LOOPMODE(CSND_LOOPMODE_NORMAL)| SOUND_FORMAT(CSND_ENCODING_PCM16),
|
||||
rate, ctr->silence, ctr->silence, CTR_AUDIO_SIZE);
|
||||
rate, 1.0, 1.0, ctr->r, ctr->r, CTR_AUDIO_SIZE);
|
||||
|
||||
CSND_SetVol(0x8, 0xFFFF, 0);
|
||||
CSND_SetVol(0x9, 0, 0xFFFF);
|
||||
csndExecCmds(false);
|
||||
ctr->playpos = 0;
|
||||
ctr->cpu_ticks_last = svcGetSystemTick();
|
||||
ctr->playing = true;
|
||||
|
||||
return ctr;
|
||||
}
|
||||
@ -92,7 +95,6 @@ static void ctr_audio_free(void *data)
|
||||
|
||||
linearFree(ctr->l);
|
||||
linearFree(ctr->r);
|
||||
linearFree(ctr->silence);
|
||||
|
||||
free(ctr);
|
||||
}
|
||||
@ -107,45 +109,35 @@ static ssize_t ctr_audio_write(void *data, const void *buf, size_t size)
|
||||
int i;
|
||||
const uint16_t* src = buf;
|
||||
|
||||
RARCH_PERFORMANCE_INIT(ctraudio_f);
|
||||
RARCH_PERFORMANCE_INIT(ctraudio_f);
|
||||
RARCH_PERFORMANCE_START(ctraudio_f);
|
||||
|
||||
CSND_ChnInfo channel_info;
|
||||
csndGetState(0x8, &channel_info);
|
||||
uint64_t current_tick = svcGetSystemTick();
|
||||
uint32_t samples_played = (current_tick - ctr->cpu_ticks_last) / ctr->cpu_ticks_per_sample;
|
||||
ctr->playpos = (ctr->playpos + samples_played) & CTR_AUDIO_COUNT_MASK;
|
||||
ctr->cpu_ticks_last += samples_played * ctr->cpu_ticks_per_sample;
|
||||
|
||||
uint32_t playpos;
|
||||
if((channel_info.samplePAddr >= (ctr->l_paddr)) &&
|
||||
(channel_info.samplePAddr < (ctr->l_paddr + CTR_AUDIO_SIZE)))
|
||||
{
|
||||
playpos = (channel_info.samplePAddr - ctr->l_paddr) / sizeof(uint16_t);
|
||||
}
|
||||
else
|
||||
{
|
||||
CSND_SetBlock(0x8, 1, ctr->l_paddr, CTR_AUDIO_SIZE);
|
||||
CSND_SetBlock(0x9, 1, ctr->r_paddr, CTR_AUDIO_SIZE);
|
||||
csndExecCmds(false);
|
||||
playpos = 0;
|
||||
}
|
||||
|
||||
if((((playpos - ctr->pos) & CTR_AUDIO_COUNT_MASK) < (CTR_AUDIO_COUNT >> 2)) ||
|
||||
(((ctr->pos - playpos ) & CTR_AUDIO_COUNT_MASK) < (CTR_AUDIO_COUNT >> 4)) ||
|
||||
(((playpos - ctr->pos) & CTR_AUDIO_COUNT_MASK) < (size >> 2)))
|
||||
if((((ctr->playpos - ctr->pos) & CTR_AUDIO_COUNT_MASK) < (CTR_AUDIO_COUNT >> 2)) ||
|
||||
(((ctr->pos - ctr->playpos ) & CTR_AUDIO_COUNT_MASK) < (CTR_AUDIO_COUNT >> 4)) ||
|
||||
(((ctr->playpos - ctr->pos) & CTR_AUDIO_COUNT_MASK) < (size >> 2)))
|
||||
{
|
||||
if (ctr->nonblocking)
|
||||
ctr->pos = (playpos + (CTR_AUDIO_COUNT >> 1)) & CTR_AUDIO_COUNT_MASK;
|
||||
ctr->pos = (ctr->playpos + (CTR_AUDIO_COUNT >> 1)) & CTR_AUDIO_COUNT_MASK;
|
||||
else
|
||||
{
|
||||
do{
|
||||
/* todo: compute the correct sleep period */
|
||||
svcSleepThread(100000);
|
||||
// svcSleepThread(((s64)(CTR_AUDIO_COUNT >> 8) * 1000000000) / ctr->rate);
|
||||
csndGetState(0x8, &channel_info);
|
||||
playpos = (channel_info.samplePAddr - ctr->l_paddr) / sizeof(uint16_t);
|
||||
}while (((playpos - ctr->pos) & CTR_AUDIO_COUNT_MASK) < (CTR_AUDIO_COUNT >> 1)
|
||||
|| (((ctr->pos - playpos) & CTR_AUDIO_COUNT_MASK) < (CTR_AUDIO_COUNT >> 4)));
|
||||
current_tick = svcGetSystemTick();
|
||||
samples_played = (current_tick - ctr->cpu_ticks_last) / ctr->cpu_ticks_per_sample;
|
||||
ctr->playpos = (ctr->playpos + samples_played) & CTR_AUDIO_COUNT_MASK;
|
||||
ctr->cpu_ticks_last += samples_played * ctr->cpu_ticks_per_sample;
|
||||
}while (((ctr->playpos - ctr->pos) & CTR_AUDIO_COUNT_MASK) < (CTR_AUDIO_COUNT >> 1)
|
||||
|| (((ctr->pos - ctr->playpos) & CTR_AUDIO_COUNT_MASK) < (CTR_AUDIO_COUNT >> 4)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (i = 0; i < (size >> 1); i += 2)
|
||||
{
|
||||
ctr->l[ctr->pos] = src[i];
|
||||
@ -153,6 +145,9 @@ static ssize_t ctr_audio_write(void *data, const void *buf, size_t size)
|
||||
ctr->pos++;
|
||||
ctr->pos &= CTR_AUDIO_COUNT_MASK;
|
||||
}
|
||||
GSPGPU_FlushDataCache(NULL, (u8*)ctr->l, CTR_AUDIO_SIZE);
|
||||
GSPGPU_FlushDataCache(NULL, (u8*)ctr->r, CTR_AUDIO_SIZE);
|
||||
|
||||
|
||||
RARCH_PERFORMANCE_STOP(ctraudio_f);
|
||||
|
||||
@ -163,31 +158,51 @@ static bool ctr_audio_stop(void *data)
|
||||
{
|
||||
ctr_audio_t* ctr = (ctr_audio_t*)data;
|
||||
|
||||
CSND_SetBlock(0x8, 1, ctr->silence_paddr, CTR_AUDIO_SIZE);
|
||||
CSND_SetBlock(0x9, 1, ctr->silence_paddr, CTR_AUDIO_SIZE);
|
||||
/* using SetPlayState would make tracking the playback
|
||||
* position more difficult */
|
||||
|
||||
// CSND_SetPlayState(0x8, 0);
|
||||
// CSND_SetPlayState(0x9, 0);
|
||||
|
||||
/* setting the channel volume to 0 seems to make it
|
||||
* impossible to set it back to full volume later */
|
||||
|
||||
CSND_SetVol(0x8, 0x00000001, 0);
|
||||
CSND_SetVol(0x9, 0x00010000, 0);
|
||||
csndExecCmds(false);
|
||||
|
||||
ctr->playing = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ctr_audio_alive(void *data)
|
||||
{
|
||||
(void)data;
|
||||
return true;
|
||||
ctr_audio_t* ctr = (ctr_audio_t*)data;
|
||||
return ctr->playing;
|
||||
}
|
||||
|
||||
static bool ctr_audio_start(void *data)
|
||||
{
|
||||
ctr_audio_t* ctr = (ctr_audio_t*)data;
|
||||
global_t *global = global_get_ptr();
|
||||
|
||||
// csndPlaySound(0x8, SOUND_LOOPMODE(CSND_LOOPMODE_NORMAL)| SOUND_FORMAT(CSND_ENCODING_PCM16),
|
||||
// ctr->rate, ctr->l_paddr + ((ctr->pos + (CTR_AUDIO_SIZE / 2)) & CTR_AUDIO_SIZE_MASK),
|
||||
// (u32*)ctr->silence_paddr, CTR_AUDIO_SIZE);
|
||||
/* prevents restarting audio when the menu
|
||||
* is toggled off on shutdown */
|
||||
|
||||
if (global->system.shutdown)
|
||||
return true;
|
||||
|
||||
// CSND_SetPlayState(0x8, 1);
|
||||
// CSND_SetPlayState(0x9, 1);
|
||||
|
||||
CSND_SetVol(0x8, 0x00008000, 0);
|
||||
CSND_SetVol(0x9, 0x80000000, 0);
|
||||
|
||||
CSND_SetBlock(0x8, 1, ctr->l_paddr, CTR_AUDIO_SIZE);
|
||||
CSND_SetBlock(0x9, 1, ctr->r_paddr, CTR_AUDIO_SIZE);
|
||||
csndExecCmds(false);
|
||||
|
||||
ctr->playing = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user