Search
lxdream.org :: lxdream/src/aica/aica.c :: diff
lxdream 0.9.1
released Jun 29
Download Now
filename src/aica/aica.c
changeset 66:2ec5b6eb75e5
prev61:eb7a73c9bcae
next73:0bb57e51ac9e
author nkeynes
date Tue Jan 10 13:56:54 2006 +0000 (14 years ago)
permissions -rw-r--r--
last change Go go gadget audio!
Slow, but it works :)
file annotate diff log raw
1.1 --- a/src/aica/aica.c Mon Jan 02 14:50:12 2006 +0000
1.2 +++ b/src/aica/aica.c Tue Jan 10 13:56:54 2006 +0000
1.3 @@ -1,5 +1,5 @@
1.4 /**
1.5 - * $Id: aica.c,v 1.10 2006-01-02 14:50:12 nkeynes Exp $
1.6 + * $Id: aica.c,v 1.11 2006-01-10 13:56:54 nkeynes Exp $
1.7 *
1.8 * This is the core sound system (ie the bit which does the actual work)
1.9 *
1.10 @@ -19,9 +19,11 @@
1.11 #define MODULE aica_module
1.12
1.13 #include "dream.h"
1.14 +#include "dreamcast.h"
1.15 #include "mem.h"
1.16 #include "aica.h"
1.17 #include "armcore.h"
1.18 +#include "audio.h"
1.19 #define MMIO_IMPL
1.20 #include "aica.h"
1.21
1.22 @@ -37,6 +39,7 @@
1.23 int aica_load_state( FILE *f );
1.24 uint32_t aica_run_slice( uint32_t );
1.25
1.26 +#define IS_TIMER_ENABLED() (MMIO_READ( AICA2, AICA_TCR ) & 0x40)
1.27
1.28 struct dreamcast_module aica_module = { "AICA", aica_init, aica_reset,
1.29 aica_start, aica_run_slice, aica_stop,
1.30 @@ -51,12 +54,14 @@
1.31 MMIO_NOTRACE(AICA0);
1.32 MMIO_NOTRACE(AICA1);
1.33 arm_mem_init();
1.34 - arm_reset();
1.35 + aica_reset();
1.36 + audio_set_output( &esd_audio_driver, 44100, AUDIO_FMT_16BIT|AUDIO_FMT_STEREO );
1.37 }
1.38
1.39 void aica_reset( void )
1.40 {
1.41 arm_reset();
1.42 + aica_event(2); /* Pre-deliver a timer interrupt */
1.43 }
1.44
1.45 void aica_start( void )
1.46 @@ -64,15 +69,36 @@
1.47
1.48 }
1.49
1.50 +/**
1.51 + * Keep track of what we've done so far this second, to try to keep the
1.52 + * precision of samples/second.
1.53 + */
1.54 +int samples_done = 0;
1.55 +uint32_t nanosecs_done = 0;
1.56 +
1.57 uint32_t aica_run_slice( uint32_t nanosecs )
1.58 {
1.59 /* Run arm instructions */
1.60 int reset = MMIO_READ( AICA2, AICA_RESET );
1.61 - if( (reset & 1) == 0 ) {
1.62 - /* Running */
1.63 - nanosecs = arm_run_slice( nanosecs );
1.64 + if( (reset & 1) == 0 ) { /* Running */
1.65 + int num_samples = (nanosecs_done + nanosecs) / AICA_SAMPLE_RATE - samples_done;
1.66 + int i;
1.67 + for( i=0; i<num_samples; i++ ) {
1.68 + nanosecs = arm_run_slice( AICA_SAMPLE_PERIOD );
1.69 + audio_mix_sample();
1.70 + if( IS_TIMER_ENABLED() ) {
1.71 + uint8_t val = MMIO_READ( AICA2, AICA_TIMER );
1.72 + val++;
1.73 + if( val == 0 )
1.74 + aica_event( AICA_EVENT_TIMER );
1.75 + MMIO_WRITE( AICA2, AICA_TIMER, val );
1.76 + }
1.77 + if( !dreamcast_is_running() )
1.78 + break;
1.79 + }
1.80 + samples_done += num_samples;
1.81 + nanosecs_done += nanosecs;
1.82 }
1.83 - /* Generate audio buffer */
1.84 return nanosecs;
1.85 }
1.86
1.87 @@ -132,6 +158,7 @@
1.88 armr.int_pending &= ~CPSR_F;
1.89 }
1.90 }
1.91 +
1.92 /** Channel register structure:
1.93 * 00 4 Channel config
1.94 * 04 4 Waveform address lo (16 bits)
1.95 @@ -155,20 +182,22 @@
1.96 /* Write to channels 0-31 */
1.97 void mmio_region_AICA0_write( uint32_t reg, uint32_t val )
1.98 {
1.99 - // aica_write_channel( reg >> 7, reg % 128, val );
1.100 MMIO_WRITE( AICA0, reg, val );
1.101 + aica_write_channel( reg >> 7, reg % 128, val );
1.102 // DEBUG( "AICA0 Write %08X => %08X", val, reg );
1.103 }
1.104
1.105 /* Write to channels 32-64 */
1.106 void mmio_region_AICA1_write( uint32_t reg, uint32_t val )
1.107 {
1.108 - // aica_write_channel( (reg >> 7) + 32, reg % 128, val );
1.109 MMIO_WRITE( AICA1, reg, val );
1.110 + aica_write_channel( (reg >> 7) + 32, reg % 128, val );
1.111 // DEBUG( "AICA1 Write %08X => %08X", val, reg );
1.112 }
1.113
1.114 -/* General registers */
1.115 +/**
1.116 + * AICA control registers
1.117 + */
1.118 void mmio_region_AICA2_write( uint32_t reg, uint32_t val )
1.119 {
1.120 uint32_t tmp;
1.121 @@ -179,6 +208,8 @@
1.122 /* ARM enabled - execute a core reset */
1.123 DEBUG( "ARM enabled" );
1.124 arm_reset();
1.125 + samples_done = 0;
1.126 + nanosecs_done = 0;
1.127 } else if( (tmp&1) == 0 && (val&1) == 1 ) {
1.128 DEBUG( "ARM disabled" );
1.129 }
1.130 @@ -192,3 +223,91 @@
1.131 break;
1.132 }
1.133 }
1.134 +
1.135 +/**
1.136 + * Translate the channel frequency to a sample rate. The frequency is a
1.137 + * 14-bit floating point number, where bits 0..9 is the mantissa,
1.138 + * 11..14 is the signed exponent (-8 to +7). Bit 10 appears to
1.139 + * be unused.
1.140 + *
1.141 + * @return sample rate in samples per second.
1.142 + */
1.143 +uint32_t aica_frequency_to_sample_rate( uint32_t freq )
1.144 +{
1.145 + uint32_t exponent = (freq & 0x3800) >> 11;
1.146 + uint32_t mantissa = freq & 0x03FF;
1.147 + if( freq & 0x4000 ) {
1.148 + /* neg exponent - rate < 44100 */
1.149 + exponent = 8 - exponent;
1.150 + return (44100 >> exponent) +
1.151 + ((44100 * mantissa) >> (10+exponent));
1.152 + } else {
1.153 + /* pos exponent - rate > 44100 */
1.154 + return (44100 << exponent) +
1.155 + ((44100 * mantissa) >> (10-exponent));
1.156 + }
1.157 +}
1.158 +
1.159 +void aica_write_channel( int channelNo, uint32_t reg, uint32_t val )
1.160 +{
1.161 + val &= 0x0000FFFF;
1.162 + audio_channel_t channel = audio_get_channel(channelNo);
1.163 + switch( reg ) {
1.164 + case 0x00: /* Config + high address bits*/
1.165 + channel->start = (channel->start & 0xFFFF) | ((val&0x1F) << 16);
1.166 + if( val & 0x200 )
1.167 + channel->loop_count = -1;
1.168 + else
1.169 + channel->loop_count = 0;
1.170 + switch( (val >> 7) & 0x03 ) {
1.171 + case 0:
1.172 + channel->sample_format = AUDIO_FMT_16BIT;
1.173 + break;
1.174 + case 1:
1.175 + channel->sample_format = AUDIO_FMT_8BIT;
1.176 + break;
1.177 + case 2:
1.178 + case 3:
1.179 + channel->sample_format = AUDIO_FMT_ADPCM;
1.180 + break;
1.181 + }
1.182 + switch( (val >> 14) & 0x03 ) {
1.183 + case 2:
1.184 + audio_stop_channel( channelNo );
1.185 + break;
1.186 + case 3:
1.187 + audio_start_channel( channelNo );
1.188 + break;
1.189 + default:
1.190 + break;
1.191 + /* Hrmm... */
1.192 + }
1.193 + break;
1.194 + case 0x04: /* Low 16 address bits */
1.195 + channel->start = (channel->start & 0x001F0000) | val;
1.196 + break;
1.197 + case 0x08: /* Loop start */
1.198 + channel->loop_start = val;
1.199 + break;
1.200 + case 0x0C: /* Loop end */
1.201 + channel->loop_end = channel->end = val;
1.202 + break;
1.203 + case 0x10: /* Envelope register 1 */
1.204 + break;
1.205 + case 0x14: /* Envelope register 2 */
1.206 + break;
1.207 + case 0x18: /* Frequency */
1.208 + channel->sample_rate = aica_frequency_to_sample_rate ( val );
1.209 + break;
1.210 + case 0x1C: /* ??? */
1.211 + case 0x20: /* ??? */
1.212 + case 0x24: /* Volume? /pan */
1.213 + break;
1.214 + case 0x28: /* Volume */
1.215 + channel->vol_left = channel->vol_right = val & 0xFF;
1.216 + break;
1.217 + default: /* ??? */
1.218 + break;
1.219 + }
1.220 +
1.221 +}
.