Search
lxdream.org :: lxdream/src/aica/audio.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/aica/audio.c
changeset 66:2ec5b6eb75e5
next73:0bb57e51ac9e
author nkeynes
date Tue Jan 10 13:56:54 2006 +0000 (15 years ago)
permissions -rw-r--r--
last change Go go gadget audio!
Slow, but it works :)
view annotate diff log raw
     1 /**
     2  * $Id: audio.c,v 1.1 2006-01-10 13:56:54 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 4000
    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;
    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_sample( )
   179 {
   180     int i, j;
   181     int32_t result_left = 0, result_right = 0;
   183     for( i=0; i < 64; i++ ) {
   184 	audio_channel_t channel = &audio.channels[i];
   185 	if( channel->active ) {
   186 	    int32_t sample;
   187 	    switch( channel->sample_format ) {
   188 	    case AUDIO_FMT_16BIT:
   189 		sample = *(int16_t *)(arm_mem + channel->posn + channel->start);
   190 		break;
   191 	    case AUDIO_FMT_8BIT:
   192 		sample = (*(int8_t *)(arm_mem + channel->posn + channel->start)) << 8;
   193 		break;
   194 	    case AUDIO_FMT_16BIT|AUDIO_FMT_UNSIGNED:
   195 		sample = (int8_t)((*(uint16_t *)(arm_mem + channel->posn + channel->start)) - 0x8000);
   196 		break;
   197 	    case AUDIO_FMT_8BIT|AUDIO_FMT_UNSIGNED:
   198 		sample = (int8_t)((*(uint8_t *)(arm_mem + channel->posn + channel->start)) - 0x80);
   199 		break;
   200 	    case AUDIO_FMT_ADPCM:
   201 		sample = (int16_t)channel->adpcm_predict;
   202 	    default:
   203 		sample = 0; /* Unsupported */
   204 	    }
   205 	    result_left += sample * channel->vol_left;
   206 	    result_right += sample * channel->vol_right;
   208 	    channel->posn_left += channel->sample_rate;
   209 	    while( channel->posn_left > audio.output_rate ) {
   210 		channel->posn_left -= audio.output_rate;
   211 		if( channel->sample_format == AUDIO_FMT_ADPCM &&
   212 		    channel->adpcm_nibble == 0 ) {
   213 		    uint8_t data = *(uint8_t *)(arm_mem + channel->posn + channel->start);
   214 		    adpcm_yamaha_decode_nibble( channel, (data >> 4) & 0x0F );
   215 		    channel->adpcm_nibble = 1;
   216 		    continue;
   217 		}
   219 		channel->posn++;
   221 		if( channel->loop_count != 0 && 
   222 		    channel->posn >= channel->loop_end ) {
   223 		    channel->posn = channel->loop_start;
   224 		    if( channel->loop_count != -1 )
   225 			channel->loop_count --;
   226 		} else if( channel->posn >= channel->end ) {
   227 		    audio_stop_channel( i );
   228 		    break;
   229 		}
   231 		if( channel->sample_format == AUDIO_FMT_ADPCM ) {
   232 		    uint8_t data = *(uint8_t *)(arm_mem + channel->posn + channel->start);
   233 		    adpcm_yamaha_decode_nibble( channel, data & 0x0F );
   234 		    channel->adpcm_nibble = 0;
   235 		}
   236 	    }
   237 	}
   238     }
   240     /* Down-render to the final output format */
   241     audio_buffer_t buf = 
   242 	audio.output_buffers[audio.write_buffer];
   243     if( audio.output_format & AUDIO_FMT_16BIT ) {
   244 	uint16_t *data = (uint16_t *)&buf->data[buf->posn*audio.output_sample_size];
   245 	*data++ = (int16_t)(result_left >> 8);
   246 	*data++ = (int16_t)(result_right >> 8);
   247     } else {
   248 	audio_buffer_t buf = 
   249 	    audio.output_buffers[audio.write_buffer];
   250 	uint8_t *data = (uint8_t *)&buf->data[buf->posn*audio.output_sample_size];
   251 	*data++ = (int8_t)(result_left >> 22);
   252 	*data++ = (int8_t)(result_right >>22);
   253     }
   254     buf->posn++;
   255     if( buf->posn == buf->length ) {
   256 	audio_next_write_buffer();
   257     }
   258 }
   260 /********************** Internal AICA calls ***************************/
   262 audio_channel_t audio_get_channel( int channel ) 
   263 {
   264     return &audio.channels[channel];
   265 }
   267 void audio_stop_channel( int channel ) 
   268 {
   269     audio.channels[channel].active = FALSE;
   270 }
   273 void audio_start_channel( int channel )
   274 {
   275     audio.channels[channel].posn = 0;
   276     audio.channels[channel].posn_left = 0;
   277     audio.channels[channel].adpcm_nibble = 0;
   278     audio.channels[channel].adpcm_step = 0;
   279     audio.channels[channel].adpcm_predict = 0;
   280     audio.channels[channel].active = TRUE;
   281     DEBUG("Channel %d on", channel );
   282 }
.