Search
lxdream.org :: lxdream/src/aica/audio.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/aica/audio.c
changeset 73:0bb57e51ac9e
prev66:2ec5b6eb75e5
next79:6d832137fdff
author nkeynes
date Thu Jan 12 11:30:19 2006 +0000 (15 years ago)
permissions -rw-r--r--
last change Render multiple samples per shot, should be mildly faster
Move timer logic down into armcore
Minor tweaks
view annotate diff log raw
     1 /**
     2  * $Id: audio.c,v 1.2 2006-01-12 11:30:19 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 500
    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 	    switch( channel->sample_format ) {
   190 	    case AUDIO_FMT_16BIT:
   191 		for( j=0; j<num_samples; j++ ) {
   192 		    sample = *(int16_t *)(arm_mem + channel->posn + channel->start);
   193 		    result_buf[j][0] += sample * channel->vol_left;
   194 		    result_buf[j][1] += sample * channel->vol_right;
   196 		    channel->posn_left += channel->sample_rate;
   197 		    while( channel->posn_left > audio.output_rate ) {
   198 			channel->posn_left -= audio.output_rate;
   199 			channel->posn++;
   201 			if( channel->posn == channel->end ) {
   202 			    if( channel->loop )
   203 				channel->posn = channel->loop_start;
   204 			    else {
   205 				audio_stop_channel(i);
   206 				j = num_samples;
   207 				break;
   208 			    }
   209 			}
   210 		    }
   211 		}
   212 		break;
   213 	    case AUDIO_FMT_8BIT:
   214 		for( j=0; j<num_samples; j++ ) {
   215 		    sample = (*(int8_t *)(arm_mem + channel->posn + channel->start)) << 8;
   216 		    result_buf[j][0] += sample * channel->vol_left;
   217 		    result_buf[j][1] += sample * channel->vol_right;
   219 		    channel->posn_left += channel->sample_rate;
   220 		    while( channel->posn_left > audio.output_rate ) {
   221 			channel->posn_left -= audio.output_rate;
   222 			channel->posn++;
   224 			if( channel->posn == channel->end ) {
   225 			    if( channel->loop )
   226 				channel->posn = channel->loop_start;
   227 			    else {
   228 				audio_stop_channel(i);
   229 				j = num_samples;
   230 				break;
   231 			    }
   232 			}
   233 		    }
   234 		}
   235 		break;
   236 	    case AUDIO_FMT_ADPCM:
   237 		for( j=0; j<num_samples; j++ ) {
   238 		    sample = (int16_t)channel->adpcm_predict;
   239 		    result_buf[j][0] += sample * channel->vol_left;
   240 		    result_buf[j][1] += sample * channel->vol_right;
   241 		    channel->posn_left += channel->sample_rate;
   242 		    while( channel->posn_left > audio.output_rate ) {
   243 			channel->posn_left -= audio.output_rate;
   244 			if( channel->adpcm_nibble == 0 ) {
   245 			    uint8_t data = *(uint8_t *)(arm_mem + channel->posn + channel->start);
   246 			    adpcm_yamaha_decode_nibble( channel, (data >> 4) & 0x0F );
   247 			    channel->adpcm_nibble = 1;
   248 			} else {
   249 			    channel->posn++;
   250 			    if( channel->posn == channel->end ) {
   251 				if( channel->loop )
   252 				    channel->posn = channel->loop_start;
   253 				else
   254 				    audio_stop_channel(i);
   255 				break;
   256 			    }
   257 			    uint8_t data = *(uint8_t *)(arm_mem + channel->posn + channel->start);
   258 			    adpcm_yamaha_decode_nibble( channel, data & 0x0F );
   259 			    channel->adpcm_nibble = 0;
   260 			}
   261 		    }
   262 		}
   263 		break;
   264 	    default:
   265 		break;
   266 	    }
   267 	}
   268     }
   270     /* Down-render to the final output format */
   272     if( audio.output_format & AUDIO_FMT_16BIT ) {
   273 	audio_buffer_t buf = audio.output_buffers[audio.write_buffer];
   274 	uint16_t *data = (uint16_t *)&buf->data[buf->posn];
   275 	for( j=0; j < num_samples; j++ ) {
   276 	    *data++ = (int16_t)(result_buf[j][0] >> 8);
   277 	    *data++ = (int16_t)(result_buf[j][1] >> 8);	
   278 	    buf->posn += 4;
   279 	    if( buf->posn == buf->length ) {
   280 		audio_next_write_buffer();
   281 		buf = audio.output_buffers[audio.write_buffer];
   282 		data = (uint16_t *)&buf->data[0];
   283 	    }
   284 	}
   285     } else {
   286 	audio_buffer_t buf = audio.output_buffers[audio.write_buffer];
   287 	uint8_t *data = (uint8_t *)&buf->data[buf->posn];
   288 	for( j=0; j < num_samples; j++ ) {
   289 	    *data++ = (uint8_t)(result_buf[j][0] >> 16);
   290 	    *data++ = (uint8_t)(result_buf[j][1] >> 16);	
   291 	    buf->posn += 2;
   292 	    if( buf->posn == buf->length ) {
   293 		audio_next_write_buffer();
   294 		buf = audio.output_buffers[audio.write_buffer];
   295 		data = (uint8_t *)&buf->data[0];
   296 	    }
   297 	}
   298     }
   299 }
   301 /********************** Internal AICA calls ***************************/
   303 audio_channel_t audio_get_channel( int channel ) 
   304 {
   305     return &audio.channels[channel];
   306 }
   308 void audio_stop_channel( int channel ) 
   309 {
   310     audio.channels[channel].active = FALSE;
   311 }
   314 void audio_start_channel( int channel )
   315 {
   316     audio.channels[channel].posn = 0;
   317     audio.channels[channel].posn_left = 0;
   318     audio.channels[channel].adpcm_nibble = 0;
   319     audio.channels[channel].adpcm_step = 0;
   320     audio.channels[channel].adpcm_predict = 0;
   321     audio.channels[channel].active = TRUE;
   322     DEBUG("Channel %d on", channel );
   323 }
.