filename | src/aica/aica.c |
changeset | 66:2ec5b6eb75e5 |
prev | 61:eb7a73c9bcae |
next | 73:0bb57e51ac9e |
author | nkeynes |
date | Tue Jan 10 13:56:54 2006 +0000 (16 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 +00001.2 +++ b/src/aica/aica.c Tue Jan 10 13:56:54 2006 +00001.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_module1.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_IMPL1.20 #include "aica.h"1.22 @@ -37,6 +39,7 @@1.23 int aica_load_state( FILE *f );1.24 uint32_t aica_run_slice( uint32_t );1.26 +#define IS_TIMER_ENABLED() (MMIO_READ( AICA2, AICA_TCR ) & 0x40)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.39 void aica_reset( void )1.40 {1.41 arm_reset();1.42 + aica_event(2); /* Pre-deliver a timer interrupt */1.43 }1.45 void aica_start( void )1.46 @@ -64,15 +69,36 @@1.48 }1.50 +/**1.51 + * Keep track of what we've done so far this second, to try to keep the1.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.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 config1.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.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.114 -/* General registers */1.115 +/**1.116 + * AICA control registers1.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 a1.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 to1.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 + else1.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 +}
.