Search
lxdream.org :: lxdream :: r66:2ec5b6eb75e5
lxdream 0.9.1
released Jun 29
Download Now
changeset66:2ec5b6eb75e5
parent65:9f124c245fc6
child67:1f59399bbf17
authornkeynes
dateTue Jan 10 13:56:54 2006 +0000 (17 years ago)
Go go gadget audio!
Slow, but it works :)
src/aica/aica.c
src/aica/aica.h
src/aica/armcore.c
src/aica/armcore.h
src/aica/armmem.c
src/aica/audio.c
src/aica/audio.h
src/drivers/audio_esd.c
src/drivers/audio_null.c
1.1 --- a/src/aica/aica.c Tue Jan 03 12:21:45 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 +}
2.1 --- a/src/aica/aica.h Tue Jan 03 12:21:45 2006 +0000
2.2 +++ b/src/aica/aica.h Tue Jan 10 13:56:54 2006 +0000
2.3 @@ -1,5 +1,5 @@
2.4 /**
2.5 - * $Id: aica.h,v 1.6 2006-01-02 23:06:37 nkeynes Exp $
2.6 + * $Id: aica.h,v 1.7 2006-01-10 13:56:54 nkeynes Exp $
2.7 *
2.8 * MMIO definitions for the AICA sound chip. Note that the regions defined
2.9 * here are relative to the SH4 memory map (0x00700000 based), rather than
2.10 @@ -33,14 +33,14 @@
2.11 LONG_PORT( 0x044, CDDA_VOL_R, PORT_MRW, 0, "CDDA Volume right" )
2.12 LONG_PORT( 0x800, VOL_MASTER, PORT_MRW, UNDEFINED, "Master volume" )
2.13 LONG_PORT( 0x808, AICA_UNK7, PORT_MRW, 0, "AICA ??? 7" )
2.14 -LONG_PORT( 0x880, AICA_TIMER1, PORT_MRW, 0, "AICA Timer 1" )
2.15 -LONG_PORT( 0x890, AICA_TIMER2, PORT_MRW, 0, "AICA Timer 2" )
2.16 +LONG_PORT( 0x880, AICA_UNK6, PORT_MRW, 0, "AICA ??? 6" )
2.17 +LONG_PORT( 0x890, AICA_TIMER, PORT_MRW, 0, "AICA Timer" )
2.18 LONG_PORT( 0x89C, AICA_UNK1, PORT_MRW, 0, "AICA ??? 1" )
2.19 -LONG_PORT( 0x8A4, AICA_UNK2, PORT_MRW, 0, "AICA ??? 2" )
2.20 +LONG_PORT( 0x8A4, AICA_TCR, PORT_MRW, 0, "AICA Timer Control?" )
2.21 BYTE_PORT( 0x8A8, AICA_UNK3, PORT_MRW, 0, "AICA ??? 3" )
2.22 BYTE_PORT( 0x8AC, AICA_UNK4, PORT_MRW, 0, "AICA ??? 4" )
2.23 BYTE_PORT( 0x8B0, AICA_UNK5, PORT_MRW, 0, "AICA ??? 5" )
2.24 -LONG_PORT( 0xC00, AICA_RESET,PORT_MRW, 1, "AICA reset" )
2.25 +LONG_PORT( 0xC00, AICA_RESET,PORT_MRW, 0, "AICA reset" )
2.26 LONG_PORT( 0xD00, AICA_IRQ, PORT_MR, 0, "AICA IRQ Pending" )
2.27 LONG_PORT( 0xD04, AICA_IRQCLEAR, PORT_MRW, 0, "AICA IRQ Clear" )
2.28 MMIO_REGION_END
2.29 @@ -58,3 +58,16 @@
2.30 #define AICA_EVENT_OTHER 5
2.31
2.32 void aica_event( int event );
2.33 +void aica_write_channel( int channel, uint32_t addr, uint32_t val );
2.34 +
2.35 +/**
2.36 + * The AICA core runs at 44100 samples/second, regardless of what we're
2.37 + * actually outputing.
2.38 + */
2.39 +#define AICA_SAMPLE_RATE 44100
2.40 +
2.41 +/**
2.42 + * This is only used to determine number of instructions to execute
2.43 + * per sample, which isn't cycle accurate at the moment.
2.44 + */
2.45 +#define AICA_SAMPLE_PERIOD (1000000000 / 44100)
3.1 --- a/src/aica/armcore.c Tue Jan 03 12:21:45 2006 +0000
3.2 +++ b/src/aica/armcore.c Tue Jan 10 13:56:54 2006 +0000
3.3 @@ -1,5 +1,5 @@
3.4 /**
3.5 - * $Id: armcore.c,v 1.15 2006-01-02 23:07:17 nkeynes Exp $
3.6 + * $Id: armcore.c,v 1.16 2006-01-10 13:56:54 nkeynes Exp $
3.7 *
3.8 * ARM7TDMI CPU emulation core.
3.9 *
3.10 @@ -155,6 +155,25 @@
3.11 }
3.12
3.13 /**
3.14 + * Return a pointer to the specified register in the user bank,
3.15 + * regardless of the active bank
3.16 + */
3.17 +static uint32_t *arm_user_reg( int reg )
3.18 +{
3.19 + if( IS_EXCEPTION_MODE() ) {
3.20 + if( reg == 13 || reg == 14 )
3.21 + return &armr.user_r[reg-8];
3.22 + if( IS_FIQ_MODE() ) {
3.23 + if( reg >= 8 || reg <= 12 )
3.24 + return &armr.user_r[reg-8];
3.25 + }
3.26 + }
3.27 + return &armr.r[reg];
3.28 +}
3.29 +
3.30 +#define USER_R(n) *arm_user_reg(n)
3.31 +
3.32 +/**
3.33 * Set the CPSR to the specified value.
3.34 *
3.35 * @param value values to set in CPSR
3.36 @@ -661,6 +680,7 @@
3.37 uint32_t pc;
3.38 uint32_t ir;
3.39 uint32_t operand, operand2, tmp, tmp2, cond;
3.40 + int i;
3.41
3.42 tmp = armr.int_pending & (~armr.cpsr);
3.43 if( tmp ) {
3.44 @@ -1121,95 +1141,181 @@
3.45 }
3.46 armr.r[15] = pc + 4 + operand;
3.47 } else { /* Load/store multiple */
3.48 - int prestep, poststep;
3.49 - if( PFLAG(ir) ) {
3.50 - prestep = UFLAG(ir) ? 4 : -4;
3.51 - poststep = 0 ;
3.52 - } else {
3.53 - prestep = 0;
3.54 - poststep = UFLAG(ir) ? 4 : -4;
3.55 - }
3.56 operand = RN(ir);
3.57 - if( BFLAG(ir) ) {
3.58 - /* Actually S - bit 22. Means "make massively complicated" */
3.59 - if( LFLAG(ir) && (ir&0x00008000) ) {
3.60 - /* LDM (3). Much like normal LDM but also copies SPSR
3.61 - * back to CPSR */
3.62 - for( tmp=0; tmp < 16; tmp++ ) {
3.63 - if( (ir & (1<<tmp)) ) {
3.64 - operand += prestep;
3.65 - armr.r[tmp] = arm_read_long(operand);
3.66 - operand += poststep;
3.67 +
3.68 + switch( (ir & 0x01D00000) >> 20 ) {
3.69 + case 0: /* STMDA */
3.70 + for( i=15; i>= 0; i-- ) {
3.71 + if( (ir & (1<<i)) ) {
3.72 + arm_write_long( operand, armr.r[i] );
3.73 + operand -= 4;
3.74 + }
3.75 + }
3.76 + break;
3.77 + case 1: /* LDMDA */
3.78 + for( i=15; i>= 0; i-- ) {
3.79 + if( (ir & (1<<i)) ) {
3.80 + armr.r[i] = arm_read_long( operand );
3.81 + operand -= 4;
3.82 + }
3.83 + }
3.84 + break;
3.85 + case 4: /* STMDA (S) */
3.86 + for( i=15; i>= 0; i-- ) {
3.87 + if( (ir & (1<<i)) ) {
3.88 + arm_write_long( operand, USER_R(i) );
3.89 + operand -= 4;
3.90 + }
3.91 + }
3.92 + break;
3.93 + case 5: /* LDMDA (S) */
3.94 + if( (ir&0x00008000) ) { /* Load PC */
3.95 + for( i=15; i>= 0; i-- ) {
3.96 + if( (ir & (1<<i)) ) {
3.97 + armr.r[i] = arm_read_long( operand );
3.98 + operand -= 4;
3.99 }
3.100 }
3.101 - if( WFLAG(ir) )
3.102 - LRN(ir) = operand;
3.103 arm_restore_cpsr();
3.104 - if( armr.t ) PC &= 0xFFFFFFFE;
3.105 - else PC &= 0xFFFFFFFC;
3.106 } else {
3.107 - /* LDM/STM (2). As normal LDM but accesses the User banks
3.108 - * instead of the active ones. Aka the truly evil case
3.109 - */
3.110 - int bank_start;
3.111 - if( IS_FIQ_MODE() )
3.112 - bank_start = 8;
3.113 - else if( IS_EXCEPTION_MODE() )
3.114 - bank_start = 13;
3.115 - else bank_start = 15;
3.116 - for( tmp=0; tmp<bank_start; tmp++ ) {
3.117 - if( (ir & (1<<tmp)) ) {
3.118 - operand += prestep;
3.119 - if( LFLAG(ir) ) {
3.120 - armr.r[tmp] = arm_read_long(operand);
3.121 - } else {
3.122 - arm_write_long( operand, armr.r[tmp] );
3.123 - }
3.124 - operand += poststep;
3.125 + for( i=15; i>= 0; i-- ) {
3.126 + if( (ir & (1<<i)) ) {
3.127 + USER_R(i) = arm_read_long( operand );
3.128 + operand -= 4;
3.129 }
3.130 }
3.131 - for( ; tmp < 15; tmp ++ ) {
3.132 - if( (ir & (1<<tmp)) ) {
3.133 - operand += prestep;
3.134 - if( LFLAG(ir) ) {
3.135 - armr.user_r[tmp-8] = arm_read_long(operand);
3.136 - } else {
3.137 - arm_write_long( operand, armr.user_r[tmp-8] );
3.138 - }
3.139 - operand += poststep;
3.140 + }
3.141 + break;
3.142 + case 8: /* STMIA */
3.143 + for( i=0; i< 16; i++ ) {
3.144 + if( (ir & (1<<i)) ) {
3.145 + arm_write_long( operand, armr.r[i] );
3.146 + operand += 4;
3.147 + }
3.148 + }
3.149 + break;
3.150 + case 9: /* LDMIA */
3.151 + for( i=0; i< 16; i++ ) {
3.152 + if( (ir & (1<<i)) ) {
3.153 + armr.r[i] = arm_read_long( operand );
3.154 + operand += 4;
3.155 + }
3.156 + }
3.157 + break;
3.158 + case 12: /* STMIA (S) */
3.159 + for( i=0; i< 16; i++ ) {
3.160 + if( (ir & (1<<i)) ) {
3.161 + arm_write_long( operand, USER_R(i) );
3.162 + operand += 4;
3.163 + }
3.164 + }
3.165 + break;
3.166 + case 13: /* LDMIA (S) */
3.167 + if( (ir&0x00008000) ) { /* Load PC */
3.168 + for( i=0; i < 16; i++ ) {
3.169 + if( (ir & (1<<i)) ) {
3.170 + armr.r[i] = arm_read_long( operand );
3.171 + operand += 4;
3.172 }
3.173 }
3.174 - if( ir & 0x8000 ) {
3.175 - operand += prestep;
3.176 - if( LFLAG(ir) ) {
3.177 - /* Actually can't happen, but anyway... */
3.178 - armr.r[15] = arm_read_long(operand);
3.179 - } else {
3.180 - arm_write_long( operand, armr.r[15]+ STM_R15_OFFSET - 4 );
3.181 + arm_restore_cpsr();
3.182 + } else {
3.183 + for( i=0; i < 16; i++ ) {
3.184 + if( (ir & (1<<i)) ) {
3.185 + USER_R(i) = arm_read_long( operand );
3.186 + operand += 4;
3.187 }
3.188 - operand += poststep;
3.189 }
3.190 }
3.191 - } else {
3.192 - /* Normal LDM/STM */
3.193 - for( tmp=0; tmp < 16; tmp++ ) {
3.194 - if( (ir & (1<<tmp)) ) {
3.195 - operand += prestep;
3.196 - if( LFLAG(ir) ) {
3.197 - armr.r[tmp] = arm_read_long(operand);
3.198 - } else {
3.199 - if( tmp == 15 )
3.200 - arm_write_long( operand,
3.201 - armr.r[15] + STM_R15_OFFSET - 4 );
3.202 - else
3.203 - arm_write_long( operand, armr.r[tmp] );
3.204 - }
3.205 - operand += poststep;
3.206 + break;
3.207 + case 16: /* STMDB */
3.208 + for( i=15; i>= 0; i-- ) {
3.209 + if( (ir & (1<<i)) ) {
3.210 + operand -= 4;
3.211 + arm_write_long( operand, armr.r[i] );
3.212 }
3.213 }
3.214 - if( WFLAG(ir) )
3.215 - LRN(ir) = operand;
3.216 + break;
3.217 + case 17: /* LDMDB */
3.218 + for( i=15; i>= 0; i-- ) {
3.219 + if( (ir & (1<<i)) ) {
3.220 + operand -= 4;
3.221 + armr.r[i] = arm_read_long( operand );
3.222 + }
3.223 + }
3.224 + break;
3.225 + case 20: /* STMDB (S) */
3.226 + for( i=15; i>= 0; i-- ) {
3.227 + if( (ir & (1<<i)) ) {
3.228 + operand -= 4;
3.229 + arm_write_long( operand, USER_R(i) );
3.230 + }
3.231 + }
3.232 + break;
3.233 + case 21: /* LDMDB (S) */
3.234 + if( (ir&0x00008000) ) { /* Load PC */
3.235 + for( i=15; i>= 0; i-- ) {
3.236 + if( (ir & (1<<i)) ) {
3.237 + operand -= 4;
3.238 + armr.r[i] = arm_read_long( operand );
3.239 + }
3.240 + }
3.241 + arm_restore_cpsr();
3.242 + } else {
3.243 + for( i=15; i>= 0; i-- ) {
3.244 + if( (ir & (1<<i)) ) {
3.245 + operand -= 4;
3.246 + USER_R(i) = arm_read_long( operand );
3.247 + }
3.248 + }
3.249 + }
3.250 + break;
3.251 + case 24: /* STMIB */
3.252 + for( i=0; i< 16; i++ ) {
3.253 + if( (ir & (1<<i)) ) {
3.254 + operand += 4;
3.255 + arm_write_long( operand, armr.r[i] );
3.256 + }
3.257 + }
3.258 + break;
3.259 + case 25: /* LDMIB */
3.260 + for( i=0; i< 16; i++ ) {
3.261 + if( (ir & (1<<i)) ) {
3.262 + operand += 4;
3.263 + armr.r[i] = arm_read_long( operand );
3.264 + }
3.265 + }
3.266 + break;
3.267 + case 28: /* STMIB (S) */
3.268 + for( i=0; i< 16; i++ ) {
3.269 + if( (ir & (1<<i)) ) {
3.270 + operand += 4;
3.271 + arm_write_long( operand, USER_R(i) );
3.272 + }
3.273 + }
3.274 + break;
3.275 + case 29: /* LDMIB (S) */
3.276 + if( (ir&0x00008000) ) { /* Load PC */
3.277 + for( i=0; i < 16; i++ ) {
3.278 + if( (ir & (1<<i)) ) {
3.279 + operand += 4;
3.280 + armr.r[i] = arm_read_long( operand );
3.281 + }
3.282 + }
3.283 + arm_restore_cpsr();
3.284 + } else {
3.285 + for( i=0; i < 16; i++ ) {
3.286 + if( (ir & (1<<i)) ) {
3.287 + operand += 4;
3.288 + USER_R(i) = arm_read_long( operand );
3.289 + }
3.290 + }
3.291 + }
3.292 + break;
3.293 }
3.294 +
3.295 + if( WFLAG(ir) )
3.296 + LRN(ir) = operand;
3.297 }
3.298 break;
3.299 case 3: /* Copro */
4.1 --- a/src/aica/armcore.h Tue Jan 03 12:21:45 2006 +0000
4.2 +++ b/src/aica/armcore.h Tue Jan 10 13:56:54 2006 +0000
4.3 @@ -1,5 +1,5 @@
4.4 /**
4.5 - * $Id: armcore.h,v 1.11 2005-12-28 22:49:26 nkeynes Exp $
4.6 + * $Id: armcore.h,v 1.12 2006-01-10 13:56:54 nkeynes Exp $
4.7 *
4.8 * Interface definitions for the ARM CPU emulation core proper.
4.9 *
4.10 @@ -23,7 +23,7 @@
4.11 #include <stdint.h>
4.12 #include <stdio.h>
4.13
4.14 -#define ARM_BASE_RATE 33 /* MHZ */
4.15 +#define ARM_BASE_RATE 25 /* MHZ */
4.16 extern uint32_t arm_cpu_freq;
4.17 extern uint32_t arm_cpu_period;
4.18
5.1 --- a/src/aica/armmem.c Tue Jan 03 12:21:45 2006 +0000
5.2 +++ b/src/aica/armmem.c Tue Jan 10 13:56:54 2006 +0000
5.3 @@ -1,5 +1,5 @@
5.4 /**
5.5 - * $Id: armmem.c,v 1.6 2005-12-26 10:48:20 nkeynes Exp $
5.6 + * $Id: armmem.c,v 1.7 2006-01-10 13:56:54 nkeynes Exp $
5.7 *
5.8 * Implements the ARM's memory map.
5.9 *
5.10 @@ -19,6 +19,7 @@
5.11 #include <stdlib.h>
5.12 #include "dream.h"
5.13 #include "mem.h"
5.14 +#include "aica.h"
5.15
5.16 char *arm_mem = NULL;
5.17 char *arm_mem_scratch = NULL;
5.18 @@ -38,13 +39,20 @@
5.19 return *(int32_t *)(arm_mem + addr);
5.20 /* Main sound ram */
5.21 } else {
5.22 + uint32_t val;
5.23 switch( addr & 0xFFFFF000 ) {
5.24 case 0x00800000:
5.25 - return mmio_region_AICA0_read(addr);
5.26 + val = mmio_region_AICA0_read(addr&0x0FFF);
5.27 + // DEBUG( "ARM long read from %08X => %08X", addr, val );
5.28 + return val;
5.29 case 0x00801000:
5.30 - return mmio_region_AICA1_read(addr);
5.31 + val = mmio_region_AICA1_read(addr&0x0FFF);
5.32 + // DEBUG( "ARM long read from %08X => %08X", addr, val );
5.33 + return val;
5.34 case 0x00802000:
5.35 - return mmio_region_AICA2_read(addr);
5.36 + val = mmio_region_AICA2_read(addr&0x0FFF);
5.37 + // DEBUG( "ARM long read from %08X => %08X", addr, val );
5.38 + return val;
5.39 case 0x00803000:
5.40 case 0x00804000:
5.41 return *(int32_t *)(arm_mem_scratch + addr - 0x00803000);
5.42 @@ -72,13 +80,16 @@
5.43 } else {
5.44 switch( addr & 0xFFFFF000 ) {
5.45 case 0x00800000:
5.46 - mmio_region_AICA0_write(addr, value);
5.47 + // DEBUG( "ARM long write to %08X <= %08X", addr, value );
5.48 + mmio_region_AICA0_write(addr&0x0FFF, value);
5.49 break;
5.50 case 0x00801000:
5.51 - mmio_region_AICA1_write(addr, value);
5.52 + // DEBUG( "ARM long write to %08X <= %08X", addr, value );
5.53 + mmio_region_AICA1_write(addr&0x0FFF, value);
5.54 break;
5.55 case 0x00802000:
5.56 - mmio_region_AICA2_write(addr, value);
5.57 + // DEBUG( "ARM long write to %08X <= %08X", addr, value );
5.58 + mmio_region_AICA2_write(addr&0x0FFF, value);
5.59 break;
5.60 case 0x00803000:
5.61 case 0x00804000:
5.62 @@ -93,21 +104,42 @@
5.63 return 0;
5.64 }
5.65
5.66 +uint32_t arm_combine_byte( uint32_t addr, uint32_t val, uint8_t byte )
5.67 +{
5.68 + switch( addr & 0x03 ) {
5.69 + case 0:
5.70 + return (val & 0xFFFFFF00) | byte;
5.71 + case 1:
5.72 + return (val & 0xFFFF00FF) | (byte<<8);
5.73 + case 2:
5.74 + return (val & 0xFF00FFFF) | (byte<<16);
5.75 + case 3:
5.76 + return (val & 0x00FFFFFF) | (byte<<24);
5.77 + }
5.78 +}
5.79 +
5.80 void arm_write_byte( uint32_t addr, uint32_t value )
5.81 {
5.82 if( addr < 0x00200000 ) {
5.83 /* Main sound ram */
5.84 *(uint8_t *)(arm_mem + addr) = (uint8_t)value;
5.85 } else {
5.86 + uint32_t tmp;
5.87 switch( addr & 0xFFFFF000 ) {
5.88 case 0x00800000:
5.89 - mmio_region_AICA0_write(addr, value);
5.90 + tmp = MMIO_READ( AICA0, addr & 0x0FFC );
5.91 + value = arm_combine_byte( addr, tmp, value );
5.92 + mmio_region_AICA0_write(addr&0x0FFC, value);
5.93 break;
5.94 case 0x00801000:
5.95 - mmio_region_AICA1_write(addr, value);
5.96 + tmp = MMIO_READ( AICA1, addr & 0x0FFC );
5.97 + value = arm_combine_byte( addr, tmp, value );
5.98 + mmio_region_AICA1_write(addr&0x0FFC, value);
5.99 break;
5.100 case 0x00802000:
5.101 - mmio_region_AICA2_write(addr, value);
5.102 + tmp = MMIO_READ( AICA2, addr & 0x0FFC );
5.103 + value = arm_combine_byte( addr, tmp, value );
5.104 + mmio_region_AICA2_write(addr&0x0FFC, value);
5.105 break;
5.106 case 0x00803000:
5.107 case 0x00804000:
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
6.2 +++ b/src/aica/audio.c Tue Jan 10 13:56:54 2006 +0000
6.3 @@ -0,0 +1,282 @@
6.4 +/**
6.5 + * $Id: audio.c,v 1.1 2006-01-10 13:56:54 nkeynes Exp $
6.6 + *
6.7 + * Audio mixer core. Combines all the active streams into a single sound
6.8 + * buffer for output.
6.9 + *
6.10 + * Copyright (c) 2005 Nathan Keynes.
6.11 + *
6.12 + * This program is free software; you can redistribute it and/or modify
6.13 + * it under the terms of the GNU General Public License as published by
6.14 + * the Free Software Foundation; either version 2 of the License, or
6.15 + * (at your option) any later version.
6.16 + *
6.17 + * This program is distributed in the hope that it will be useful,
6.18 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
6.19 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
6.20 + * GNU General Public License for more details.
6.21 + */
6.22 +
6.23 +#include "aica/aica.h"
6.24 +#include "aica/audio.h"
6.25 +#include "glib/gmem.h"
6.26 +#include "dream.h"
6.27 +#include <assert.h>
6.28 +#include <string.h>
6.29 +
6.30 +#define NUM_BUFFERS 3
6.31 +#define MS_PER_BUFFER 4000
6.32 +
6.33 +#define BUFFER_EMPTY 0
6.34 +#define BUFFER_WRITING 1
6.35 +#define BUFFER_FULL 2
6.36 +
6.37 +struct audio_state {
6.38 + audio_buffer_t output_buffers[NUM_BUFFERS];
6.39 + int write_buffer;
6.40 + int read_buffer;
6.41 + uint32_t output_format;
6.42 + uint32_t output_rate;
6.43 + uint32_t output_sample_size;
6.44 + struct audio_channel channels[64];
6.45 +} audio;
6.46 +
6.47 +audio_driver_t audio_driver = NULL;
6.48 +
6.49 +#define NEXT_BUFFER() ((audio.write_buffer == NUM_BUFFERS-1) ? 0 : audio.write_buffer+1)
6.50 +
6.51 +extern char *arm_mem;
6.52 +
6.53 +/**
6.54 + * Set the output driver, sample rate and format. Also initializes the
6.55 + * output buffers, flushing any current data and reallocating as
6.56 + * necessary.
6.57 + */
6.58 +void audio_set_output( audio_driver_t driver,
6.59 + uint32_t samplerate, int format )
6.60 +{
6.61 + uint32_t bytes_per_sample = 1;
6.62 + uint32_t samples_per_buffer;
6.63 + int i;
6.64 +
6.65 + if( format & AUDIO_FMT_16BIT )
6.66 + bytes_per_sample = 2;
6.67 + if( format & AUDIO_FMT_STEREO )
6.68 + bytes_per_sample <<= 1;
6.69 + if( samplerate == audio.output_rate &&
6.70 + bytes_per_sample == audio.output_sample_size )
6.71 + return;
6.72 + samples_per_buffer = (samplerate * MS_PER_BUFFER / 1000);
6.73 + for( i=0; i<NUM_BUFFERS; i++ ) {
6.74 + if( audio.output_buffers[i] != NULL )
6.75 + free(audio.output_buffers[i]);
6.76 + audio.output_buffers[i] = g_malloc0( sizeof(struct audio_buffer) + samples_per_buffer * bytes_per_sample );
6.77 + audio.output_buffers[i]->length = samples_per_buffer;
6.78 + audio.output_buffers[i]->posn = 0;
6.79 + audio.output_buffers[i]->status = BUFFER_EMPTY;
6.80 + }
6.81 + audio.output_format = format;
6.82 + audio.output_rate = samplerate;
6.83 + audio.output_sample_size = bytes_per_sample;
6.84 + audio.write_buffer = 0;
6.85 + audio.read_buffer = 0;
6.86 +
6.87 + if( driver == NULL )
6.88 + driver = &null_audio_driver;
6.89 + audio_driver = driver;
6.90 + audio_driver->set_output_format( samplerate, format );
6.91 +}
6.92 +
6.93 +/**
6.94 + * Mark the current write buffer as full and prepare the next buffer for
6.95 + * writing. Returns the next buffer to write to.
6.96 + * If all buffers are full, returns NULL.
6.97 + */
6.98 +audio_buffer_t audio_next_write_buffer( )
6.99 +{
6.100 + audio_buffer_t result = NULL;
6.101 + audio_buffer_t current = audio.output_buffers[audio.write_buffer];
6.102 + current->status = BUFFER_FULL;
6.103 + if( audio.read_buffer == audio.write_buffer &&
6.104 + audio_driver->process_buffer( current ) ) {
6.105 + audio_next_read_buffer();
6.106 + }
6.107 + audio.write_buffer = NEXT_BUFFER();
6.108 + result = audio.output_buffers[audio.write_buffer];
6.109 + if( result->status == BUFFER_FULL )
6.110 + return NULL;
6.111 + else {
6.112 + result->status = BUFFER_WRITING;
6.113 + return result;
6.114 + }
6.115 +}
6.116 +
6.117 +/**
6.118 + * Mark the current read buffer as empty and return the next buffer for
6.119 + * reading. If there is no next buffer yet, returns NULL.
6.120 + */
6.121 +audio_buffer_t audio_next_read_buffer( )
6.122 +{
6.123 + audio_buffer_t current = audio.output_buffers[audio.read_buffer];
6.124 + assert( current->status == BUFFER_FULL );
6.125 + current->status = BUFFER_EMPTY;
6.126 + current->posn = 0;
6.127 + audio.read_buffer++;
6.128 + if( audio.read_buffer == NUM_BUFFERS )
6.129 + audio.read_buffer = 0;
6.130 +
6.131 + current = audio.output_buffers[audio.read_buffer];
6.132 + if( current->status == BUFFER_FULL )
6.133 + return current;
6.134 + else return NULL;
6.135 +}
6.136 +
6.137 +/*************************** ADPCM ***********************************/
6.138 +
6.139 +/**
6.140 + * The following section borrows heavily from ffmpeg, which is
6.141 + * copyright (c) 2001-2003 by the fine folks at the ffmpeg project,
6.142 + * distributed under the GPL version 2 or later.
6.143 + */
6.144 +
6.145 +#define CLAMP_TO_SHORT(value) \
6.146 +if (value > 32767) \
6.147 + value = 32767; \
6.148 +else if (value < -32768) \
6.149 + value = -32768; \
6.150 +
6.151 +static const int yamaha_indexscale[] = {
6.152 + 230, 230, 230, 230, 307, 409, 512, 614,
6.153 + 230, 230, 230, 230, 307, 409, 512, 614
6.154 +};
6.155 +
6.156 +static const int yamaha_difflookup[] = {
6.157 + 1, 3, 5, 7, 9, 11, 13, 15,
6.158 + -1, -3, -5, -7, -9, -11, -13, -15
6.159 +};
6.160 +
6.161 +static inline short adpcm_yamaha_decode_nibble( audio_channel_t c,
6.162 + unsigned char nibble )
6.163 +{
6.164 + if( c->adpcm_step == 0 ) {
6.165 + c->adpcm_predict = 0;
6.166 + c->adpcm_step = 127;
6.167 + }
6.168 +
6.169 + c->adpcm_predict += (c->adpcm_step * yamaha_difflookup[nibble]) >> 3;
6.170 + CLAMP_TO_SHORT(c->adpcm_predict);
6.171 + c->adpcm_step = (c->adpcm_step * yamaha_indexscale[nibble]) >> 8;
6.172 + c->adpcm_step = CLAMP(c->adpcm_step, 127, 24567);
6.173 + return c->adpcm_predict;
6.174 +}
6.175 +
6.176 +/*************************** Sample mixer *****************************/
6.177 +
6.178 +/**
6.179 + * Mix a single output sample.
6.180 + */
6.181 +void audio_mix_sample( )
6.182 +{
6.183 + int i, j;
6.184 + int32_t result_left = 0, result_right = 0;
6.185 +
6.186 + for( i=0; i < 64; i++ ) {
6.187 + audio_channel_t channel = &audio.channels[i];
6.188 + if( channel->active ) {
6.189 + int32_t sample;
6.190 + switch( channel->sample_format ) {
6.191 + case AUDIO_FMT_16BIT:
6.192 + sample = *(int16_t *)(arm_mem + channel->posn + channel->start);
6.193 + break;
6.194 + case AUDIO_FMT_8BIT:
6.195 + sample = (*(int8_t *)(arm_mem + channel->posn + channel->start)) << 8;
6.196 + break;
6.197 + case AUDIO_FMT_16BIT|AUDIO_FMT_UNSIGNED:
6.198 + sample = (int8_t)((*(uint16_t *)(arm_mem + channel->posn + channel->start)) - 0x8000);
6.199 + break;
6.200 + case AUDIO_FMT_8BIT|AUDIO_FMT_UNSIGNED:
6.201 + sample = (int8_t)((*(uint8_t *)(arm_mem + channel->posn + channel->start)) - 0x80);
6.202 + break;
6.203 + case AUDIO_FMT_ADPCM:
6.204 + sample = (int16_t)channel->adpcm_predict;
6.205 + default:
6.206 + sample = 0; /* Unsupported */
6.207 + }
6.208 + result_left += sample * channel->vol_left;
6.209 + result_right += sample * channel->vol_right;
6.210 +
6.211 + channel->posn_left += channel->sample_rate;
6.212 + while( channel->posn_left > audio.output_rate ) {
6.213 + channel->posn_left -= audio.output_rate;
6.214 + if( channel->sample_format == AUDIO_FMT_ADPCM &&
6.215 + channel->adpcm_nibble == 0 ) {
6.216 + uint8_t data = *(uint8_t *)(arm_mem + channel->posn + channel->start);
6.217 + adpcm_yamaha_decode_nibble( channel, (data >> 4) & 0x0F );
6.218 + channel->adpcm_nibble = 1;
6.219 + continue;
6.220 + }
6.221 +
6.222 + channel->posn++;
6.223 +
6.224 + if( channel->loop_count != 0 &&
6.225 + channel->posn >= channel->loop_end ) {
6.226 + channel->posn = channel->loop_start;
6.227 + if( channel->loop_count != -1 )
6.228 + channel->loop_count --;
6.229 + } else if( channel->posn >= channel->end ) {
6.230 + audio_stop_channel( i );
6.231 + break;
6.232 + }
6.233 +
6.234 + if( channel->sample_format == AUDIO_FMT_ADPCM ) {
6.235 + uint8_t data = *(uint8_t *)(arm_mem + channel->posn + channel->start);
6.236 + adpcm_yamaha_decode_nibble( channel, data & 0x0F );
6.237 + channel->adpcm_nibble = 0;
6.238 + }
6.239 + }
6.240 + }
6.241 + }
6.242 +
6.243 + /* Down-render to the final output format */
6.244 + audio_buffer_t buf =
6.245 + audio.output_buffers[audio.write_buffer];
6.246 + if( audio.output_format & AUDIO_FMT_16BIT ) {
6.247 + uint16_t *data = (uint16_t *)&buf->data[buf->posn*audio.output_sample_size];
6.248 + *data++ = (int16_t)(result_left >> 8);
6.249 + *data++ = (int16_t)(result_right >> 8);
6.250 + } else {
6.251 + audio_buffer_t buf =
6.252 + audio.output_buffers[audio.write_buffer];
6.253 + uint8_t *data = (uint8_t *)&buf->data[buf->posn*audio.output_sample_size];
6.254 + *data++ = (int8_t)(result_left >> 22);
6.255 + *data++ = (int8_t)(result_right >>22);
6.256 + }
6.257 + buf->posn++;
6.258 + if( buf->posn == buf->length ) {
6.259 + audio_next_write_buffer();
6.260 + }
6.261 +}
6.262 +
6.263 +/********************** Internal AICA calls ***************************/
6.264 +
6.265 +audio_channel_t audio_get_channel( int channel )
6.266 +{
6.267 + return &audio.channels[channel];
6.268 +}
6.269 +
6.270 +void audio_stop_channel( int channel )
6.271 +{
6.272 + audio.channels[channel].active = FALSE;
6.273 +}
6.274 +
6.275 +
6.276 +void audio_start_channel( int channel )
6.277 +{
6.278 + audio.channels[channel].posn = 0;
6.279 + audio.channels[channel].posn_left = 0;
6.280 + audio.channels[channel].adpcm_nibble = 0;
6.281 + audio.channels[channel].adpcm_step = 0;
6.282 + audio.channels[channel].adpcm_predict = 0;
6.283 + audio.channels[channel].active = TRUE;
6.284 + DEBUG("Channel %d on", channel );
6.285 +}
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
7.2 +++ b/src/aica/audio.h Tue Jan 10 13:56:54 2006 +0000
7.3 @@ -0,0 +1,113 @@
7.4 +/**
7.5 + * $Id: audio.h,v 1.1 2006-01-10 13:56:54 nkeynes Exp $
7.6 + *
7.7 + * Audio engine, ie the part that does the actual work.
7.8 + *
7.9 + * Copyright (c) 2005 Nathan Keynes.
7.10 + *
7.11 + * This program is free software; you can redistribute it and/or modify
7.12 + * it under the terms of the GNU General Public License as published by
7.13 + * the Free Software Foundation; either version 2 of the License, or
7.14 + * (at your option) any later version.
7.15 + *
7.16 + * This program is distributed in the hope that it will be useful,
7.17 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
7.18 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
7.19 + * GNU General Public License for more details.
7.20 + */
7.21 +#ifndef dream_audio_H
7.22 +#define dream_audio_H 1
7.23 +
7.24 +#include <stdint.h>
7.25 +#include <glib/gtypes.h>
7.26 +
7.27 +#ifdef __cplusplus
7.28 +extern "C" {
7.29 +#endif
7.30 +
7.31 +#define AUDIO_FMT_8BIT 0
7.32 +#define AUDIO_FMT_16BIT 1
7.33 +#define AUDIO_FMT_ADPCM 2
7.34 +#define AUDIO_FMT_MONO 0
7.35 +#define AUDIO_FMT_STEREO 4
7.36 +#define AUDIO_FMT_SIGNED 0
7.37 +#define AUDIO_FMT_UNSIGNED 8
7.38 +
7.39 +
7.40 +typedef struct audio_channel {
7.41 + gboolean active;
7.42 + uint32_t posn;
7.43 + uint32_t posn_left;
7.44 + uint32_t start;
7.45 + uint32_t end;
7.46 + uint32_t loop_start;
7.47 + uint32_t loop_end;
7.48 + int loop_count; /* 0 = no loop, -1 = loop forever */
7.49 + int vol_left; /* 0..255 */
7.50 + int vol_right; /* 0..255 */
7.51 + uint32_t sample_rate;
7.52 + int sample_format;
7.53 + /* Envelope etc stuff */
7.54 + /* ADPCM */
7.55 + int adpcm_nibble; /* 0 = low nibble, 1 = high nibble */
7.56 + int adpcm_step;
7.57 + int adpcm_predict;
7.58 +} *audio_channel_t;
7.59 +
7.60 +
7.61 +typedef struct audio_buffer {
7.62 + uint32_t length; /* Samples */
7.63 + uint32_t posn; /* Samples */
7.64 + int status;
7.65 + char data[0];
7.66 +} *audio_buffer_t;
7.67 +
7.68 +struct audio_driver {
7.69 + gboolean (*set_output_format)( uint32_t sample_rate, uint32_t format );
7.70 + gboolean (*process_buffer)( audio_buffer_t buffer );
7.71 +};
7.72 +
7.73 +typedef struct audio_driver *audio_driver_t;
7.74 +
7.75 +extern struct audio_driver null_audio_driver;
7.76 +extern struct audio_driver esd_audio_driver;
7.77 +
7.78 +/**
7.79 + * Set the output driver, sample rate and format. Also initializes the
7.80 + * output buffers, flushing any current data and reallocating as
7.81 + * necessary. Must be called before attempting to generate any audio.
7.82 + */
7.83 +void audio_set_output( audio_driver_t driver, uint32_t samplerate,
7.84 + int format );
7.85 +
7.86 +/**
7.87 + * Mark the current write buffer as full and prepare the next buffer for
7.88 + * writing. Returns the next buffer to write to.
7.89 + * If all buffers are full, returns NULL.
7.90 + */
7.91 +audio_buffer_t audio_next_write_buffer();
7.92 +
7.93 +/**
7.94 + * Mark the current read buffer as empty and return the next buffer for
7.95 + * reading. If there is no next buffer yet, returns NULL.
7.96 + */
7.97 +audio_buffer_t audio_next_read_buffer();
7.98 +
7.99 +/**
7.100 + * Mix a single output sample and append it to the output buffers
7.101 + */
7.102 +void audio_mix_sample( void );
7.103 +
7.104 +/**
7.105 + * Retrieve the channel information for the channel, numbered 0..63.
7.106 + */
7.107 +audio_channel_t audio_get_channel( int channel );
7.108 +
7.109 +void audio_start_channel( int channel );
7.110 +void audio_stop_channel( int channel );
7.111 +
7.112 +
7.113 +#ifdef __cplusplus
7.114 +}
7.115 +#endif
7.116 +#endif
8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
8.2 +++ b/src/drivers/audio_esd.c Tue Jan 10 13:56:54 2006 +0000
8.3 @@ -0,0 +1,58 @@
8.4 +/**
8.5 + * $Id: audio_esd.c,v 1.1 2006-01-10 13:56:54 nkeynes Exp $
8.6 + *
8.7 + * The esd (esound) audio driver
8.8 + *
8.9 + * Copyright (c) 2005 Nathan Keynes.
8.10 + *
8.11 + * This program is free software; you can redistribute it and/or modify
8.12 + * it under the terms of the GNU General Public License as published by
8.13 + * the Free Software Foundation; either version 2 of the License, or
8.14 + * (at your option) any later version.
8.15 + *
8.16 + * This program is distributed in the hope that it will be useful,
8.17 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
8.18 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
8.19 + * GNU General Public License for more details.
8.20 + */
8.21 +#include <esd.h>
8.22 +#include "aica/audio.h"
8.23 +#include "dream.h"
8.24 +
8.25 +int esd_handle = -1;
8.26 +int esd_sample_size = 1;
8.27 +
8.28 +gboolean esd_audio_set_format( uint32_t rate, uint32_t format )
8.29 +{
8.30 + if( esd_handle != -1 ) {
8.31 + esd_close(esd_handle);
8.32 + }
8.33 + esd_format_t esd_format = 0;
8.34 + esd_sample_size = 1;
8.35 + if( format & AUDIO_FMT_16BIT ) {
8.36 + esd_format |= ESD_BITS16;
8.37 + esd_sample_size = 1;
8.38 + } else esd_format |= ESD_BITS8;
8.39 + if( format & AUDIO_FMT_STEREO ) {
8.40 + esd_format |= ESD_STEREO;
8.41 + esd_sample_size = esd_sample_size << 1 ;
8.42 + }
8.43 + else esd_format |= ESD_MONO;
8.44 +
8.45 + esd_handle = esd_play_stream( esd_format, rate, "localhost", "dreamon" );
8.46 + return TRUE;
8.47 +}
8.48 +
8.49 +gboolean esd_audio_process_buffer( audio_buffer_t buffer )
8.50 +{
8.51 + if( esd_handle != -1 ) {
8.52 + write( esd_handle, buffer->data, buffer->length * esd_sample_size );
8.53 + DEBUG("Wrote buffer" );
8.54 + } else {
8.55 + ERROR( "ESD not initialized" );
8.56 + }
8.57 + return TRUE;
8.58 +}
8.59 +
8.60 +struct audio_driver esd_audio_driver = { esd_audio_set_format, esd_audio_process_buffer };
8.61 +
9.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
9.2 +++ b/src/drivers/audio_null.c Tue Jan 10 13:56:54 2006 +0000
9.3 @@ -0,0 +1,31 @@
9.4 +/**
9.5 + * $Id: audio_null.c,v 1.1 2006-01-10 13:56:54 nkeynes Exp $
9.6 + *
9.7 + * The "null" audio driver, which just discards all input without even
9.8 + * looking at it.
9.9 + *
9.10 + * Copyright (c) 2005 Nathan Keynes.
9.11 + *
9.12 + * This program is free software; you can redistribute it and/or modify
9.13 + * it under the terms of the GNU General Public License as published by
9.14 + * the Free Software Foundation; either version 2 of the License, or
9.15 + * (at your option) any later version.
9.16 + *
9.17 + * This program is distributed in the hope that it will be useful,
9.18 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
9.19 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9.20 + * GNU General Public License for more details.
9.21 + */
9.22 +#include "aica/audio.h"
9.23 +
9.24 +gboolean null_audio_set_format( uint32_t rate, uint32_t format )
9.25 +{
9.26 + return TRUE;
9.27 +}
9.28 +
9.29 +gboolean null_audio_process_buffer( audio_buffer_t buffer )
9.30 +{
9.31 + return TRUE;
9.32 +}
9.33 +
9.34 +struct audio_driver null_audio_driver = { null_audio_set_format, null_audio_process_buffer };
.