Search
lxdream.org :: lxdream/src/aica/audio.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/aica/audio.c
changeset 82:81a4acf75f10
prev79:6d832137fdff
next106:9048bac046c3
author nkeynes
date Tue Jan 17 12:54:02 2006 +0000 (15 years ago)
permissions -rw-r--r--
last change Add basic attempt at panning + proper volume
view annotate diff log raw
     1 /**
     2  * $Id: audio.c,v 1.4 2006-01-17 12:54:02 nkeynes Exp $
     3  * 
     4  * Audio mixer core. Combines all the active streams into a single sound
     5  * buffer for output. 
     6  *
     7  * Copyright (c) 2005 Nathan Keynes.
     8  *
     9  * This program is free software; you can redistribute it and/or modify
    10  * it under the terms of the GNU General Public License as published by
    11  * the Free Software Foundation; either version 2 of the License, or
    12  * (at your option) any later version.
    13  *
    14  * This program is distributed in the hope that it will be useful,
    15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    17  * GNU General Public License for more details.
    18  */
    20 #include "aica/aica.h"
    21 #include "aica/audio.h"
    22 #include "glib/gmem.h"
    23 #include "dream.h"
    24 #include <assert.h>
    25 #include <string.h>
    27 #define NUM_BUFFERS 3
    28 #define MS_PER_BUFFER 1000
    30 #define BUFFER_EMPTY   0
    31 #define BUFFER_WRITING 1
    32 #define BUFFER_FULL    2
    34 struct audio_state {
    35     audio_buffer_t output_buffers[NUM_BUFFERS];
    36     int write_buffer;
    37     int read_buffer;
    38     uint32_t output_format;
    39     uint32_t output_rate;
    40     uint32_t output_sample_size;
    41     struct audio_channel channels[64];
    42 } audio;
    44 audio_driver_t audio_driver = NULL;
    46 #define NEXT_BUFFER() ((audio.write_buffer == NUM_BUFFERS-1) ? 0 : audio.write_buffer+1)
    48 extern char *arm_mem;
    50 /**
    51  * Set the output driver, sample rate and format. Also initializes the 
    52  * output buffers, flushing any current data and reallocating as 
    53  * necessary.
    54  */
    55 void audio_set_output( audio_driver_t driver, 
    56 		       uint32_t samplerate, int format )
    57 {
    58     uint32_t bytes_per_sample = 1;
    59     uint32_t samples_per_buffer;
    60     int i;
    62     if( format & AUDIO_FMT_16BIT )
    63 	bytes_per_sample = 2;
    64     if( format & AUDIO_FMT_STEREO )
    65 	bytes_per_sample <<= 1;
    66     if( samplerate == audio.output_rate &&
    67 	bytes_per_sample == audio.output_sample_size )
    68 	return;
    69     samples_per_buffer = (samplerate * MS_PER_BUFFER / 1000);
    70     for( i=0; i<NUM_BUFFERS; i++ ) {
    71 	if( audio.output_buffers[i] != NULL )
    72 	    free(audio.output_buffers[i]);
    73 	audio.output_buffers[i] = g_malloc0( sizeof(struct audio_buffer) + samples_per_buffer * bytes_per_sample );
    74 	audio.output_buffers[i]->length = samples_per_buffer * bytes_per_sample;
    75 	audio.output_buffers[i]->posn = 0;
    76 	audio.output_buffers[i]->status = BUFFER_EMPTY;
    77     }
    78     audio.output_format = format;
    79     audio.output_rate = samplerate;
    80     audio.output_sample_size = bytes_per_sample;
    81     audio.write_buffer = 0;
    82     audio.read_buffer = 0;
    84     if( driver == NULL )
    85 	driver = &null_audio_driver;
    86     audio_driver = driver;
    87     audio_driver->set_output_format( samplerate, format );
    88 }
    90 /**
    91  * Mark the current write buffer as full and prepare the next buffer for
    92  * writing. Returns the next buffer to write to.
    93  * If all buffers are full, returns NULL.
    94  */
    95 audio_buffer_t audio_next_write_buffer( )
    96 {
    97     audio_buffer_t result = NULL;
    98     audio_buffer_t current = audio.output_buffers[audio.write_buffer];
    99     current->status = BUFFER_FULL;
   100     if( audio.read_buffer == audio.write_buffer &&
   101 	audio_driver->process_buffer( current ) ) {
   102 	audio_next_read_buffer();
   103     }
   104     audio.write_buffer = NEXT_BUFFER();
   105     result = audio.output_buffers[audio.write_buffer];
   106     if( result->status == BUFFER_FULL )
   107 	return NULL;
   108     else {
   109 	result->status = BUFFER_WRITING;
   110 	return result;
   111     }
   112 }
   114 /**
   115  * Mark the current read buffer as empty and return the next buffer for
   116  * reading. If there is no next buffer yet, returns NULL.
   117  */
   118 audio_buffer_t audio_next_read_buffer( )
   119 {
   120     audio_buffer_t current = audio.output_buffers[audio.read_buffer];
   121     assert( current->status == BUFFER_FULL );
   122     current->status = BUFFER_EMPTY;
   123     current->posn = 0;
   124     audio.read_buffer++;
   125     if( audio.read_buffer == NUM_BUFFERS )
   126 	audio.read_buffer = 0;
   128     current = audio.output_buffers[audio.read_buffer];
   129     if( current->status == BUFFER_FULL )
   130 	return current;
   131     else return NULL;
   132 }
   134 /*************************** ADPCM ***********************************/
   136 /**
   137  * The following section borrows heavily from ffmpeg, which is
   138  * copyright (c) 2001-2003 by the fine folks at the ffmpeg project,
   139  * distributed under the GPL version 2 or later.
   140  */
   142 #define CLAMP_TO_SHORT(value) \
   143 if (value > 32767) \
   144     value = 32767; \
   145 else if (value < -32768) \
   146     value = -32768; \
   148 static const int yamaha_indexscale[] = {
   149     230, 230, 230, 230, 307, 409, 512, 614,
   150     230, 230, 230, 230, 307, 409, 512, 614
   151 };
   153 static const int yamaha_difflookup[] = {
   154     1, 3, 5, 7, 9, 11, 13, 15,
   155     -1, -3, -5, -7, -9, -11, -13, -15
   156 };
   158 static inline short adpcm_yamaha_decode_nibble( audio_channel_t c, 
   159 						unsigned char nibble )
   160 {
   161     if( c->adpcm_step == 0 ) {
   162         c->adpcm_predict = 0;
   163         c->adpcm_step = 127;
   164     }
   166     c->adpcm_predict += (c->adpcm_step * yamaha_difflookup[nibble]) >> 3;
   167     CLAMP_TO_SHORT(c->adpcm_predict);
   168     c->adpcm_step = (c->adpcm_step * yamaha_indexscale[nibble]) >> 8;
   169     c->adpcm_step = CLAMP(c->adpcm_step, 127, 24567);
   170     return c->adpcm_predict;
   171 }
   173 /*************************** Sample mixer *****************************/
   175 /**
   176  * Mix a single output sample.
   177  */
   178 void audio_mix_samples( int num_samples )
   179 {
   180     int i, j;
   181     int32_t result_buf[num_samples][2];
   183     memset( &result_buf, 0, sizeof(result_buf) );
   185     for( i=0; i < 64; i++ ) {
   186 	audio_channel_t channel = &audio.channels[i];
   187 	if( channel->active ) {
   188 	    int32_t sample;
   189 	    int vol_left = (channel->vol * (32 - channel->pan)) >> 5;
   190 	    int vol_right = (channel->vol * (channel->pan + 1)) >> 5;
   191 	    switch( channel->sample_format ) {
   192 	    case AUDIO_FMT_16BIT:
   193 		for( j=0; j<num_samples; j++ ) {
   194 		    sample = *(int16_t *)(arm_mem + channel->posn + channel->start);
   195 		    result_buf[j][0] += sample * vol_left;
   196 		    result_buf[j][1] += sample * vol_right;
   198 		    channel->posn_left += channel->sample_rate;
   199 		    while( channel->posn_left > audio.output_rate ) {
   200 			channel->posn_left -= audio.output_rate;
   201 			channel->posn++;
   203 			if( channel->posn == channel->end ) {
   204 			    if( channel->loop )
   205 				channel->posn = channel->loop_start;
   206 			    else {
   207 				audio_stop_channel(i);
   208 				j = num_samples;
   209 				break;
   210 			    }
   211 			}
   212 		    }
   213 		}
   214 		break;
   215 	    case AUDIO_FMT_8BIT:
   216 		for( j=0; j<num_samples; j++ ) {
   217 		    sample = (*(int8_t *)(arm_mem + channel->posn + channel->start)) << 8;
   218 		    result_buf[j][0] += sample * vol_left;
   219 		    result_buf[j][1] += sample * vol_right;
   221 		    channel->posn_left += channel->sample_rate;
   222 		    while( channel->posn_left > audio.output_rate ) {
   223 			channel->posn_left -= audio.output_rate;
   224 			channel->posn++;
   226 			if( channel->posn == channel->end ) {
   227 			    if( channel->loop )
   228 				channel->posn = channel->loop_start;
   229 			    else {
   230 				audio_stop_channel(i);
   231 				j = num_samples;
   232 				break;
   233 			    }
   234 			}
   235 		    }
   236 		}
   237 		break;
   238 	    case AUDIO_FMT_ADPCM:
   239 		for( j=0; j<num_samples; j++ ) {
   240 		    sample = (int16_t)channel->adpcm_predict;
   241 		    result_buf[j][0] += sample * vol_left;
   242 		    result_buf[j][1] += sample * vol_right;
   243 		    channel->posn_left += channel->sample_rate;
   244 		    while( channel->posn_left > audio.output_rate ) {
   245 			channel->posn_left -= audio.output_rate;
   246 			if( channel->adpcm_nibble == 0 ) {
   247 			    uint8_t data = *(uint8_t *)(arm_mem + channel->posn + channel->start);
   248 			    adpcm_yamaha_decode_nibble( channel, (data >> 4) & 0x0F );
   249 			    channel->adpcm_nibble = 1;
   250 			} else {
   251 			    channel->posn++;
   252 			    if( channel->posn == channel->end ) {
   253 				if( channel->loop )
   254 				    channel->posn = channel->loop_start;
   255 				else
   256 				    audio_stop_channel(i);
   257 				break;
   258 			    }
   259 			    uint8_t data = *(uint8_t *)(arm_mem + channel->posn + channel->start);
   260 			    adpcm_yamaha_decode_nibble( channel, data & 0x0F );
   261 			    channel->adpcm_nibble = 0;
   262 			}
   263 		    }
   264 		}
   265 		break;
   266 	    default:
   267 		break;
   268 	    }
   269 	}
   270     }
   272     /* Down-render to the final output format */
   274     if( audio.output_format & AUDIO_FMT_16BIT ) {
   275 	audio_buffer_t buf = audio.output_buffers[audio.write_buffer];
   276 	uint16_t *data = (uint16_t *)&buf->data[buf->posn];
   277 	for( j=0; j < num_samples; j++ ) {
   278 	    *data++ = (int16_t)(result_buf[j][0] >> 6);
   279 	    *data++ = (int16_t)(result_buf[j][1] >> 6);	
   280 	    buf->posn += 4;
   281 	    if( buf->posn == buf->length ) {
   282 		audio_next_write_buffer();
   283 		buf = audio.output_buffers[audio.write_buffer];
   284 		data = (uint16_t *)&buf->data[0];
   285 	    }
   286 	}
   287     } else {
   288 	audio_buffer_t buf = audio.output_buffers[audio.write_buffer];
   289 	uint8_t *data = (uint8_t *)&buf->data[buf->posn];
   290 	for( j=0; j < num_samples; j++ ) {
   291 	    *data++ = (uint8_t)(result_buf[j][0] >> 16);
   292 	    *data++ = (uint8_t)(result_buf[j][1] >> 16);	
   293 	    buf->posn += 2;
   294 	    if( buf->posn == buf->length ) {
   295 		audio_next_write_buffer();
   296 		buf = audio.output_buffers[audio.write_buffer];
   297 		data = (uint8_t *)&buf->data[0];
   298 	    }
   299 	}
   300     }
   301 }
   303 /********************** Internal AICA calls ***************************/
   305 audio_channel_t audio_get_channel( int channel ) 
   306 {
   307     return &audio.channels[channel];
   308 }
   310 void audio_stop_channel( int channel ) 
   311 {
   312     audio.channels[channel].active = FALSE;
   313 }
   316 void audio_start_channel( int channel )
   317 {
   318     audio.channels[channel].posn = 0;
   319     audio.channels[channel].posn_left = 0;
   320     audio.channels[channel].adpcm_nibble = 0;
   321     audio.channels[channel].adpcm_step = 0;
   322     audio.channels[channel].adpcm_predict = 0;
   323     audio.channels[channel].active = TRUE;
   324 }
.