cog/Frameworks/lazyusf/lazyusf/audio.c

140 lines
3.6 KiB
C

#include "usf.h"
#include "memory.h"
#include "audio.h"
#include <stdlib.h>
#include <stdio.h>
#include "usf_internal.h"
static const uint32_t AI_STATUS_BUSY = 0x40000000;
static const uint32_t AI_STATUS_FULL = 0x80000000;
static uint32_t get_remaining_dma_length(usf_state_t *state) {
unsigned int next_ai_event;
unsigned int remaining_dma_duration;
if (state->fifo[0].duration == 0)
return 0;
next_ai_event = state->Timers->NextTimer[AiTimer] + state->Timers->Timer;
if (!state->Timers->Active[AiTimer])
return 0;
remaining_dma_duration = next_ai_event;
if (remaining_dma_duration >= 0x80000000)
return 0;
return (uint32_t)((uint64_t)remaining_dma_duration * state->fifo[0].length / state->fifo[0].duration);
}
void AddBuffer(usf_state_t *state, unsigned char *buf, unsigned int length) {
unsigned int i, do_max;
int16_t * sample_buffer = state->sample_buffer;
if(!state->cpu_running)
return;
do_max = length >> 2;
if ( do_max > state->sample_buffer_count )
do_max = (unsigned int) state->sample_buffer_count;
if ( sample_buffer )
for (i = 0; i < do_max; ++i) {
*sample_buffer++ = ((int16_t*)buf)[1];
*sample_buffer++ = ((int16_t*)buf)[0];
buf += 4;
}
else
buf += 4 * do_max;
state->sample_buffer_count -= do_max;
state->sample_buffer = sample_buffer;
length -= do_max << 2;
if ( length ) {
sample_buffer = state->samplebuf;
do_max = length >> 2;
for (i = 0; i < do_max; ++i) {
*sample_buffer++ = ((int16_t*)buf)[1];
*sample_buffer++ = ((int16_t*)buf)[0];
buf += 4;
}
state->samples_in_buffer = do_max;
state->cpu_running = 0;
}
}
static unsigned int get_dma_duration(usf_state_t *state)
{
unsigned int samples_per_sec = state->ROM_PARAMS.aidacrate / (1 + AI_DACRATE_REG);
return (uint32_t)(((uint64_t)(AI_LEN_REG)*state->VI_INTR_TIME*state->ROM_PARAMS.vilimit) / (4 * samples_per_sec));
}
void do_dma(usf_state_t * state, const struct ai_dma * dma) {
AddBuffer(state, state->RDRAM + (dma->address & (state->RdramSize - 1) & ~3), dma->length);
if(!(AI_STATUS_REG&AI_STATUS_FULL)) {
if (state->enableFIFOfull) {
ChangeTimer(state,AiTimer,dma->duration + state->Timers->Timer);
}
else {
state->AudioIntrReg|=4;
}
}
}
void AiQueueInt(usf_state_t *state) {
ChangeTimer(state,AiTimer,state->enableFIFOfull ? get_dma_duration(state) + state->Timers->Timer : 0);
}
void AiLenChanged(usf_state_t *state) {
unsigned int duration = get_dma_duration(state);
if (AI_STATUS_REG & AI_STATUS_BUSY) {
state->fifo[1].address = AI_DRAM_ADDR_REG;
state->fifo[1].length = AI_LEN_REG;
state->fifo[1].duration = duration;
if (state->enableFIFOfull)
AI_STATUS_REG |= AI_STATUS_FULL;
else
do_dma(state, &state->fifo[1]);
}
else {
state->fifo[0].address = AI_DRAM_ADDR_REG;
state->fifo[0].length = AI_LEN_REG;
state->fifo[0].duration = duration;
AI_STATUS_REG |= AI_STATUS_BUSY;
do_dma(state, &state->fifo[0]);
}
}
void AiTimerDone(usf_state_t *state) {
if (AI_STATUS_REG & AI_STATUS_FULL) {
state->fifo[0].address = state->fifo[1].address;
state->fifo[0].length = state->fifo[1].length;
state->fifo[0].duration = state->fifo[1].duration;
AI_STATUS_REG &= ~AI_STATUS_FULL;
do_dma(state, &state->fifo[0]);
}
else {
AI_STATUS_REG &= ~AI_STATUS_BUSY;
}
}
unsigned int AiReadLength(usf_state_t * state) {
return get_remaining_dma_length(state);
}
void AiDacrateChanged(usf_state_t * state, unsigned int value) {
AI_DACRATE_REG = value;
state->SampleRate = (state->ROM_PARAMS.aidacrate) / (AI_DACRATE_REG + 1);
}