nkeynes@66 | 1 | /**
|
nkeynes@561 | 2 | * $Id$
|
nkeynes@66 | 3 | *
|
nkeynes@66 | 4 | * Audio mixer core. Combines all the active streams into a single sound
|
nkeynes@66 | 5 | * buffer for output.
|
nkeynes@66 | 6 | *
|
nkeynes@66 | 7 | * Copyright (c) 2005 Nathan Keynes.
|
nkeynes@66 | 8 | *
|
nkeynes@66 | 9 | * This program is free software; you can redistribute it and/or modify
|
nkeynes@66 | 10 | * it under the terms of the GNU General Public License as published by
|
nkeynes@66 | 11 | * the Free Software Foundation; either version 2 of the License, or
|
nkeynes@66 | 12 | * (at your option) any later version.
|
nkeynes@66 | 13 | *
|
nkeynes@66 | 14 | * This program is distributed in the hope that it will be useful,
|
nkeynes@66 | 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
nkeynes@66 | 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
nkeynes@66 | 17 | * GNU General Public License for more details.
|
nkeynes@66 | 18 | */
|
nkeynes@66 | 19 |
|
nkeynes@66 | 20 | #include "aica/aica.h"
|
nkeynes@66 | 21 | #include "aica/audio.h"
|
nkeynes@700 | 22 | #include <glib/gmem.h>
|
nkeynes@66 | 23 | #include "dream.h"
|
nkeynes@66 | 24 | #include <assert.h>
|
nkeynes@66 | 25 | #include <string.h>
|
nkeynes@66 | 26 |
|
nkeynes@697 | 27 |
|
nkeynes@697 | 28 | extern struct audio_driver audio_null_driver;
|
nkeynes@697 | 29 | extern struct audio_driver audio_osx_driver;
|
nkeynes@697 | 30 | extern struct audio_driver audio_pulse_driver;
|
nkeynes@697 | 31 | extern struct audio_driver audio_esd_driver;
|
nkeynes@697 | 32 | extern struct audio_driver audio_alsa_driver;
|
nkeynes@697 | 33 |
|
nkeynes@697 | 34 | audio_driver_t audio_driver_list[] = {
|
nkeynes@697 | 35 | #ifdef HAVE_CORE_AUDIO
|
nkeynes@736 | 36 | &audio_osx_driver,
|
nkeynes@697 | 37 | #endif
|
nkeynes@657 | 38 | #ifdef HAVE_PULSE
|
nkeynes@736 | 39 | &audio_pulse_driver,
|
nkeynes@657 | 40 | #endif
|
nkeynes@531 | 41 | #ifdef HAVE_ESOUND
|
nkeynes@736 | 42 | &audio_esd_driver,
|
nkeynes@531 | 43 | #endif
|
bhaal22@643 | 44 | #ifdef HAVE_ALSA
|
nkeynes@736 | 45 | &audio_alsa_driver,
|
bhaal22@643 | 46 | #endif
|
nkeynes@736 | 47 | &audio_null_driver,
|
nkeynes@736 | 48 | NULL };
|
nkeynes@531 | 49 |
|
nkeynes@66 | 50 | #define NUM_BUFFERS 3
|
nkeynes@700 | 51 | #define MS_PER_BUFFER 100
|
nkeynes@66 | 52 |
|
nkeynes@66 | 53 | #define BUFFER_EMPTY 0
|
nkeynes@66 | 54 | #define BUFFER_WRITING 1
|
nkeynes@66 | 55 | #define BUFFER_FULL 2
|
nkeynes@66 | 56 |
|
nkeynes@66 | 57 | struct audio_state {
|
nkeynes@66 | 58 | audio_buffer_t output_buffers[NUM_BUFFERS];
|
nkeynes@66 | 59 | int write_buffer;
|
nkeynes@66 | 60 | int read_buffer;
|
nkeynes@66 | 61 | uint32_t output_format;
|
nkeynes@66 | 62 | uint32_t output_rate;
|
nkeynes@66 | 63 | uint32_t output_sample_size;
|
nkeynes@465 | 64 | struct audio_channel channels[AUDIO_CHANNEL_COUNT];
|
nkeynes@66 | 65 | } audio;
|
nkeynes@66 | 66 |
|
nkeynes@66 | 67 | audio_driver_t audio_driver = NULL;
|
nkeynes@66 | 68 |
|
nkeynes@66 | 69 | #define NEXT_BUFFER() ((audio.write_buffer == NUM_BUFFERS-1) ? 0 : audio.write_buffer+1)
|
nkeynes@66 | 70 |
|
nkeynes@66 | 71 | /**
|
nkeynes@465 | 72 | * Preserve audio channel state only - don't bother saving the buffers
|
nkeynes@465 | 73 | */
|
nkeynes@465 | 74 | void audio_save_state( FILE *f )
|
nkeynes@465 | 75 | {
|
nkeynes@465 | 76 | fwrite( &audio.channels[0], sizeof(struct audio_channel), AUDIO_CHANNEL_COUNT, f );
|
nkeynes@465 | 77 | }
|
nkeynes@465 | 78 |
|
nkeynes@465 | 79 | int audio_load_state( FILE *f )
|
nkeynes@465 | 80 | {
|
nkeynes@465 | 81 | int read = fread( &audio.channels[0], sizeof(struct audio_channel), AUDIO_CHANNEL_COUNT, f );
|
nkeynes@465 | 82 | return (read == AUDIO_CHANNEL_COUNT ? 0 : -1 );
|
nkeynes@465 | 83 | }
|
nkeynes@465 | 84 |
|
nkeynes@531 | 85 | audio_driver_t get_audio_driver_by_name( const char *name )
|
nkeynes@531 | 86 | {
|
nkeynes@531 | 87 | int i;
|
nkeynes@531 | 88 | if( name == NULL ) {
|
nkeynes@697 | 89 | return audio_driver_list[0];
|
nkeynes@531 | 90 | }
|
nkeynes@531 | 91 | for( i=0; audio_driver_list[i] != NULL; i++ ) {
|
nkeynes@697 | 92 | if( strcasecmp( audio_driver_list[i]->name, name ) == 0 ) {
|
nkeynes@697 | 93 | return audio_driver_list[i];
|
nkeynes@697 | 94 | }
|
nkeynes@531 | 95 | }
|
nkeynes@531 | 96 |
|
nkeynes@531 | 97 | return NULL;
|
nkeynes@531 | 98 | }
|
nkeynes@531 | 99 |
|
nkeynes@700 | 100 | void print_audio_drivers( FILE * out )
|
nkeynes@700 | 101 | {
|
nkeynes@700 | 102 | int i;
|
nkeynes@700 | 103 | fprintf( out, "Available audio drivers:\n" );
|
nkeynes@700 | 104 | for( i=0; audio_driver_list[i] != NULL; i++ ) {
|
nkeynes@700 | 105 | fprintf( out, " %-8s %s\n", audio_driver_list[i]->name,
|
nkeynes@736 | 106 | gettext(audio_driver_list[i]->description) );
|
nkeynes@700 | 107 | }
|
nkeynes@700 | 108 | }
|
nkeynes@700 | 109 |
|
nkeynes@697 | 110 | audio_driver_t audio_init_driver( const char *preferred_driver )
|
nkeynes@697 | 111 | {
|
nkeynes@697 | 112 | audio_driver_t audio_driver = get_audio_driver_by_name(preferred_driver);
|
nkeynes@697 | 113 | if( audio_driver == NULL ) {
|
nkeynes@697 | 114 | ERROR( "Audio driver '%s' not found, aborting.", preferred_driver );
|
nkeynes@697 | 115 | exit(2);
|
nkeynes@697 | 116 | } else if( audio_set_driver( audio_driver ) == FALSE ) {
|
nkeynes@779 | 117 | int i;
|
nkeynes@779 | 118 | for( i=0; audio_driver_list[i] != NULL; i++ ) {
|
nkeynes@779 | 119 | if( audio_driver_list[i] != audio_driver &&
|
nkeynes@779 | 120 | audio_set_driver( audio_driver_list[i] ) ) {
|
nkeynes@779 | 121 | ERROR( "Failed to initialize audio driver %s, falling back to %s",
|
nkeynes@779 | 122 | audio_driver->name, audio_driver_list[i]->name );
|
nkeynes@779 | 123 | return audio_driver_list[i];
|
nkeynes@779 | 124 | }
|
nkeynes@779 | 125 | }
|
nkeynes@779 | 126 | ERROR( "Unable to intialize any audio driver, aborting." );
|
nkeynes@779 | 127 | exit(2);
|
nkeynes@759 | 128 | }
|
nkeynes@759 | 129 | return audio_driver;
|
nkeynes@697 | 130 | }
|
nkeynes@697 | 131 |
|
nkeynes@465 | 132 | /**
|
nkeynes@66 | 133 | * Set the output driver, sample rate and format. Also initializes the
|
nkeynes@66 | 134 | * output buffers, flushing any current data and reallocating as
|
nkeynes@66 | 135 | * necessary.
|
nkeynes@66 | 136 | */
|
nkeynes@697 | 137 | gboolean audio_set_driver( audio_driver_t driver )
|
nkeynes@66 | 138 | {
|
nkeynes@66 | 139 | uint32_t bytes_per_sample = 1;
|
nkeynes@66 | 140 | uint32_t samples_per_buffer;
|
nkeynes@66 | 141 | int i;
|
nkeynes@66 | 142 |
|
nkeynes@111 | 143 | if( audio_driver == NULL || driver != NULL ) {
|
nkeynes@697 | 144 | if( driver == NULL )
|
nkeynes@697 | 145 | driver = &audio_null_driver;
|
nkeynes@697 | 146 | if( driver != audio_driver ) {
|
nkeynes@697 | 147 | if( !driver->init() )
|
nkeynes@697 | 148 | return FALSE;
|
nkeynes@697 | 149 | audio_driver = driver;
|
nkeynes@697 | 150 | }
|
nkeynes@111 | 151 | }
|
nkeynes@111 | 152 |
|
nkeynes@697 | 153 | switch( driver->sample_format & AUDIO_FMT_SAMPLE_MASK ) {
|
nkeynes@697 | 154 | case AUDIO_FMT_8BIT:
|
nkeynes@697 | 155 | bytes_per_sample = 1;
|
nkeynes@697 | 156 | break;
|
nkeynes@697 | 157 | case AUDIO_FMT_16BIT:
|
nkeynes@697 | 158 | bytes_per_sample = 2;
|
nkeynes@697 | 159 | break;
|
nkeynes@697 | 160 | case AUDIO_FMT_FLOAT:
|
nkeynes@697 | 161 | bytes_per_sample = 4;
|
nkeynes@697 | 162 | break;
|
nkeynes@697 | 163 | }
|
nkeynes@697 | 164 |
|
nkeynes@697 | 165 | if( driver->sample_format & AUDIO_FMT_STEREO )
|
nkeynes@697 | 166 | bytes_per_sample <<= 1;
|
nkeynes@697 | 167 | if( driver->sample_rate == audio.output_rate &&
|
nkeynes@697 | 168 | bytes_per_sample == audio.output_sample_size )
|
nkeynes@697 | 169 | return TRUE;
|
nkeynes@697 | 170 | samples_per_buffer = (driver->sample_rate * MS_PER_BUFFER / 1000);
|
nkeynes@66 | 171 | for( i=0; i<NUM_BUFFERS; i++ ) {
|
nkeynes@697 | 172 | if( audio.output_buffers[i] != NULL )
|
nkeynes@697 | 173 | free(audio.output_buffers[i]);
|
nkeynes@697 | 174 | audio.output_buffers[i] = g_malloc0( sizeof(struct audio_buffer) + samples_per_buffer * bytes_per_sample );
|
nkeynes@697 | 175 | audio.output_buffers[i]->length = samples_per_buffer * bytes_per_sample;
|
nkeynes@697 | 176 | audio.output_buffers[i]->posn = 0;
|
nkeynes@697 | 177 | audio.output_buffers[i]->status = BUFFER_EMPTY;
|
nkeynes@66 | 178 | }
|
nkeynes@697 | 179 | audio.output_format = driver->sample_format;
|
nkeynes@697 | 180 | audio.output_rate = driver->sample_rate;
|
nkeynes@66 | 181 | audio.output_sample_size = bytes_per_sample;
|
nkeynes@66 | 182 | audio.write_buffer = 0;
|
nkeynes@66 | 183 | audio.read_buffer = 0;
|
nkeynes@66 | 184 |
|
nkeynes@111 | 185 | return TRUE;
|
nkeynes@66 | 186 | }
|
nkeynes@66 | 187 |
|
nkeynes@66 | 188 | /**
|
nkeynes@66 | 189 | * Mark the current write buffer as full and prepare the next buffer for
|
nkeynes@66 | 190 | * writing. Returns the next buffer to write to.
|
nkeynes@66 | 191 | * If all buffers are full, returns NULL.
|
nkeynes@66 | 192 | */
|
nkeynes@66 | 193 | audio_buffer_t audio_next_write_buffer( )
|
nkeynes@66 | 194 | {
|
nkeynes@66 | 195 | audio_buffer_t result = NULL;
|
nkeynes@66 | 196 | audio_buffer_t current = audio.output_buffers[audio.write_buffer];
|
nkeynes@66 | 197 | current->status = BUFFER_FULL;
|
nkeynes@66 | 198 | if( audio.read_buffer == audio.write_buffer &&
|
nkeynes@697 | 199 | audio_driver->process_buffer( current ) ) {
|
nkeynes@697 | 200 | audio_next_read_buffer();
|
nkeynes@66 | 201 | }
|
nkeynes@697 | 202 | int next_buffer = NEXT_BUFFER();
|
nkeynes@697 | 203 | result = audio.output_buffers[next_buffer];
|
nkeynes@66 | 204 | if( result->status == BUFFER_FULL )
|
nkeynes@697 | 205 | return NULL;
|
nkeynes@66 | 206 | else {
|
nkeynes@697 | 207 | audio.write_buffer = next_buffer;
|
nkeynes@697 | 208 | result->status = BUFFER_WRITING;
|
nkeynes@697 | 209 | return result;
|
nkeynes@66 | 210 | }
|
nkeynes@66 | 211 | }
|
nkeynes@66 | 212 |
|
nkeynes@66 | 213 | /**
|
nkeynes@66 | 214 | * Mark the current read buffer as empty and return the next buffer for
|
nkeynes@66 | 215 | * reading. If there is no next buffer yet, returns NULL.
|
nkeynes@66 | 216 | */
|
nkeynes@66 | 217 | audio_buffer_t audio_next_read_buffer( )
|
nkeynes@66 | 218 | {
|
nkeynes@66 | 219 | audio_buffer_t current = audio.output_buffers[audio.read_buffer];
|
nkeynes@697 | 220 | if( current->status == BUFFER_FULL ) {
|
nkeynes@697 | 221 | // Current read buffer has data, which we've just emptied
|
nkeynes@697 | 222 | current->status = BUFFER_EMPTY;
|
nkeynes@697 | 223 | current->posn = 0;
|
nkeynes@697 | 224 | audio.read_buffer++;
|
nkeynes@697 | 225 | if( audio.read_buffer == NUM_BUFFERS )
|
nkeynes@697 | 226 | audio.read_buffer = 0;
|
nkeynes@697 | 227 |
|
nkeynes@697 | 228 | current = audio.output_buffers[audio.read_buffer];
|
nkeynes@697 | 229 | if( current->status == BUFFER_FULL ) {
|
nkeynes@697 | 230 | current->posn = 0;
|
nkeynes@697 | 231 | return current;
|
nkeynes@697 | 232 | }
|
nkeynes@697 | 233 | else return NULL;
|
nkeynes@697 | 234 | } else {
|
nkeynes@697 | 235 | return NULL;
|
nkeynes@697 | 236 | }
|
nkeynes@697 | 237 |
|
nkeynes@66 | 238 | }
|
nkeynes@66 | 239 |
|
nkeynes@66 | 240 | /*************************** ADPCM ***********************************/
|
nkeynes@66 | 241 |
|
nkeynes@66 | 242 | /**
|
nkeynes@66 | 243 | * The following section borrows heavily from ffmpeg, which is
|
nkeynes@66 | 244 | * copyright (c) 2001-2003 by the fine folks at the ffmpeg project,
|
nkeynes@66 | 245 | * distributed under the GPL version 2 or later.
|
nkeynes@66 | 246 | */
|
nkeynes@66 | 247 |
|
nkeynes@66 | 248 | #define CLAMP_TO_SHORT(value) \
|
nkeynes@736 | 249 | if (value > 32767) \
|
nkeynes@66 | 250 | value = 32767; \
|
nkeynes@736 | 251 | else if (value < -32768) \
|
nkeynes@66 | 252 | value = -32768; \
|
nkeynes@66 | 253 |
|
nkeynes@66 | 254 | static const int yamaha_indexscale[] = {
|
nkeynes@736 | 255 | 230, 230, 230, 230, 307, 409, 512, 614,
|
nkeynes@736 | 256 | 230, 230, 230, 230, 307, 409, 512, 614
|
nkeynes@66 | 257 | };
|
nkeynes@66 | 258 |
|
nkeynes@66 | 259 | static const int yamaha_difflookup[] = {
|
nkeynes@736 | 260 | 1, 3, 5, 7, 9, 11, 13, 15,
|
nkeynes@736 | 261 | -1, -3, -5, -7, -9, -11, -13, -15
|
nkeynes@66 | 262 | };
|
nkeynes@66 | 263 |
|
nkeynes@66 | 264 | static inline short adpcm_yamaha_decode_nibble( audio_channel_t c,
|
nkeynes@736 | 265 | unsigned char nibble )
|
nkeynes@66 | 266 | {
|
nkeynes@66 | 267 | if( c->adpcm_step == 0 ) {
|
nkeynes@66 | 268 | c->adpcm_predict = 0;
|
nkeynes@66 | 269 | c->adpcm_step = 127;
|
nkeynes@66 | 270 | }
|
nkeynes@66 | 271 |
|
nkeynes@66 | 272 | c->adpcm_predict += (c->adpcm_step * yamaha_difflookup[nibble]) >> 3;
|
nkeynes@66 | 273 | CLAMP_TO_SHORT(c->adpcm_predict);
|
nkeynes@66 | 274 | c->adpcm_step = (c->adpcm_step * yamaha_indexscale[nibble]) >> 8;
|
nkeynes@66 | 275 | c->adpcm_step = CLAMP(c->adpcm_step, 127, 24567);
|
nkeynes@66 | 276 | return c->adpcm_predict;
|
nkeynes@66 | 277 | }
|
nkeynes@66 | 278 |
|
nkeynes@66 | 279 | /*************************** Sample mixer *****************************/
|
nkeynes@66 | 280 |
|
nkeynes@66 | 281 | /**
|
nkeynes@66 | 282 | * Mix a single output sample.
|
nkeynes@66 | 283 | */
|
nkeynes@73 | 284 | void audio_mix_samples( int num_samples )
|
nkeynes@66 | 285 | {
|
nkeynes@66 | 286 | int i, j;
|
nkeynes@73 | 287 | int32_t result_buf[num_samples][2];
|
nkeynes@73 | 288 |
|
nkeynes@73 | 289 | memset( &result_buf, 0, sizeof(result_buf) );
|
nkeynes@66 | 290 |
|
nkeynes@465 | 291 | for( i=0; i < AUDIO_CHANNEL_COUNT; i++ ) {
|
nkeynes@697 | 292 | audio_channel_t channel = &audio.channels[i];
|
nkeynes@697 | 293 | if( channel->active ) {
|
nkeynes@697 | 294 | int32_t sample;
|
nkeynes@697 | 295 | int vol_left = (channel->vol * (32 - channel->pan)) >> 5;
|
nkeynes@697 | 296 | int vol_right = (channel->vol * (channel->pan + 1)) >> 5;
|
nkeynes@697 | 297 | switch( channel->sample_format ) {
|
nkeynes@697 | 298 | case AUDIO_FMT_16BIT:
|
nkeynes@697 | 299 | for( j=0; j<num_samples; j++ ) {
|
nkeynes@934 | 300 | sample = ((int16_t *)(aica_main_ram + channel->start))[channel->posn];
|
nkeynes@697 | 301 | result_buf[j][0] += sample * vol_left;
|
nkeynes@697 | 302 | result_buf[j][1] += sample * vol_right;
|
nkeynes@697 | 303 |
|
nkeynes@697 | 304 | channel->posn_left += channel->sample_rate;
|
nkeynes@697 | 305 | while( channel->posn_left > audio.output_rate ) {
|
nkeynes@697 | 306 | channel->posn_left -= audio.output_rate;
|
nkeynes@697 | 307 | channel->posn++;
|
nkeynes@697 | 308 |
|
nkeynes@697 | 309 | if( channel->posn == channel->end ) {
|
nkeynes@697 | 310 | if( channel->loop ) {
|
nkeynes@697 | 311 | channel->posn = channel->loop_start;
|
nkeynes@697 | 312 | channel->loop = LOOP_LOOPED;
|
nkeynes@697 | 313 | } else {
|
nkeynes@697 | 314 | audio_stop_channel(i);
|
nkeynes@697 | 315 | j = num_samples;
|
nkeynes@697 | 316 | break;
|
nkeynes@697 | 317 | }
|
nkeynes@697 | 318 | }
|
nkeynes@697 | 319 | }
|
nkeynes@697 | 320 | }
|
nkeynes@697 | 321 | break;
|
nkeynes@697 | 322 | case AUDIO_FMT_8BIT:
|
nkeynes@697 | 323 | for( j=0; j<num_samples; j++ ) {
|
nkeynes@934 | 324 | sample = ((int8_t *)(aica_main_ram + channel->start))[channel->posn] << 8;
|
nkeynes@697 | 325 | result_buf[j][0] += sample * vol_left;
|
nkeynes@697 | 326 | result_buf[j][1] += sample * vol_right;
|
nkeynes@697 | 327 |
|
nkeynes@697 | 328 | channel->posn_left += channel->sample_rate;
|
nkeynes@697 | 329 | while( channel->posn_left > audio.output_rate ) {
|
nkeynes@697 | 330 | channel->posn_left -= audio.output_rate;
|
nkeynes@697 | 331 | channel->posn++;
|
nkeynes@697 | 332 |
|
nkeynes@697 | 333 | if( channel->posn == channel->end ) {
|
nkeynes@697 | 334 | if( channel->loop ) {
|
nkeynes@697 | 335 | channel->posn = channel->loop_start;
|
nkeynes@697 | 336 | channel->loop = LOOP_LOOPED;
|
nkeynes@697 | 337 | } else {
|
nkeynes@697 | 338 | audio_stop_channel(i);
|
nkeynes@697 | 339 | j = num_samples;
|
nkeynes@697 | 340 | break;
|
nkeynes@697 | 341 | }
|
nkeynes@697 | 342 | }
|
nkeynes@697 | 343 | }
|
nkeynes@697 | 344 | }
|
nkeynes@697 | 345 | break;
|
nkeynes@697 | 346 | case AUDIO_FMT_ADPCM:
|
nkeynes@697 | 347 | for( j=0; j<num_samples; j++ ) {
|
nkeynes@697 | 348 | sample = (int16_t)channel->adpcm_predict;
|
nkeynes@697 | 349 | result_buf[j][0] += sample * vol_left;
|
nkeynes@697 | 350 | result_buf[j][1] += sample * vol_right;
|
nkeynes@697 | 351 | channel->posn_left += channel->sample_rate;
|
nkeynes@697 | 352 | while( channel->posn_left > audio.output_rate ) {
|
nkeynes@697 | 353 | channel->posn_left -= audio.output_rate;
|
nkeynes@697 | 354 | channel->posn++;
|
nkeynes@697 | 355 | if( channel->posn == channel->end ) {
|
nkeynes@697 | 356 | if( channel->loop ) {
|
nkeynes@697 | 357 | channel->posn = channel->loop_start;
|
nkeynes@697 | 358 | channel->loop = LOOP_LOOPED;
|
nkeynes@697 | 359 | channel->adpcm_predict = 0;
|
nkeynes@697 | 360 | channel->adpcm_step = 0;
|
nkeynes@697 | 361 | } else {
|
nkeynes@697 | 362 | audio_stop_channel(i);
|
nkeynes@697 | 363 | j = num_samples;
|
nkeynes@697 | 364 | break;
|
nkeynes@697 | 365 | }
|
nkeynes@697 | 366 | }
|
nkeynes@934 | 367 | uint8_t data = ((uint8_t *)(aica_main_ram + channel->start))[channel->posn>>1];
|
nkeynes@697 | 368 | if( channel->posn&1 ) {
|
nkeynes@697 | 369 | adpcm_yamaha_decode_nibble( channel, (data >> 4) & 0x0F );
|
nkeynes@697 | 370 | } else {
|
nkeynes@697 | 371 | adpcm_yamaha_decode_nibble( channel, data & 0x0F );
|
nkeynes@697 | 372 | }
|
nkeynes@697 | 373 | }
|
nkeynes@697 | 374 | }
|
nkeynes@697 | 375 | break;
|
nkeynes@697 | 376 | default:
|
nkeynes@697 | 377 | break;
|
nkeynes@697 | 378 | }
|
nkeynes@697 | 379 | }
|
nkeynes@66 | 380 | }
|
nkeynes@736 | 381 |
|
nkeynes@66 | 382 | /* Down-render to the final output format */
|
nkeynes@697 | 383 | audio_buffer_t buf = audio.output_buffers[audio.write_buffer];
|
nkeynes@697 | 384 | if( buf->status == BUFFER_FULL ) {
|
nkeynes@697 | 385 | buf = audio_next_write_buffer();
|
nkeynes@697 | 386 | if( buf == NULL ) { // no available space
|
nkeynes@697 | 387 | return;
|
nkeynes@697 | 388 | }
|
nkeynes@697 | 389 | }
|
nkeynes@736 | 390 |
|
nkeynes@697 | 391 | switch( audio.output_format & AUDIO_FMT_SAMPLE_MASK ) {
|
nkeynes@697 | 392 | case AUDIO_FMT_FLOAT: {
|
nkeynes@697 | 393 | float scale = 1.0/SHRT_MAX;
|
nkeynes@697 | 394 | float *data = (float *)&buf->data[buf->posn];
|
nkeynes@697 | 395 | for( j=0; j<num_samples; j++ ) {
|
nkeynes@697 | 396 | *data++ = scale * (result_buf[j][0] >> 6);
|
nkeynes@697 | 397 | *data++ = scale * (result_buf[j][1] >> 6);
|
nkeynes@697 | 398 | buf->posn += 8;
|
nkeynes@697 | 399 | if( buf->posn == buf->length ) {
|
nkeynes@697 | 400 | buf = audio_next_write_buffer();
|
nkeynes@697 | 401 | if( buf == NULL ) {
|
nkeynes@697 | 402 | break;
|
nkeynes@697 | 403 | }
|
nkeynes@697 | 404 | data = (float *)&buf->data[0];
|
nkeynes@697 | 405 | }
|
nkeynes@697 | 406 | }
|
nkeynes@697 | 407 | break;
|
nkeynes@697 | 408 | }
|
nkeynes@697 | 409 | case AUDIO_FMT_16BIT: {
|
nkeynes@697 | 410 | int16_t *data = (int16_t *)&buf->data[buf->posn];
|
nkeynes@697 | 411 | for( j=0; j < num_samples; j++ ) {
|
nkeynes@697 | 412 | *data++ = (int16_t)(result_buf[j][0] >> 6);
|
nkeynes@697 | 413 | *data++ = (int16_t)(result_buf[j][1] >> 6);
|
nkeynes@697 | 414 | buf->posn += 4;
|
nkeynes@697 | 415 | if( buf->posn == buf->length ) {
|
nkeynes@697 | 416 | buf = audio_next_write_buffer();
|
nkeynes@697 | 417 | if( buf == NULL ) {
|
nkeynes@697 | 418 | // All buffers are full
|
nkeynes@697 | 419 | break;
|
nkeynes@697 | 420 | }
|
nkeynes@697 | 421 | data = (int16_t *)&buf->data[0];
|
nkeynes@697 | 422 | }
|
nkeynes@697 | 423 | }
|
nkeynes@697 | 424 | break;
|
nkeynes@697 | 425 | }
|
nkeynes@697 | 426 | case AUDIO_FMT_8BIT: {
|
nkeynes@700 | 427 | int8_t *data = (int8_t *)&buf->data[buf->posn];
|
nkeynes@697 | 428 | for( j=0; j < num_samples; j++ ) {
|
nkeynes@697 | 429 | *data++ = (int8_t)(result_buf[j][0] >> 16);
|
nkeynes@697 | 430 | *data++ = (int8_t)(result_buf[j][1] >> 16);
|
nkeynes@697 | 431 | buf->posn += 2;
|
nkeynes@697 | 432 | if( buf->posn == buf->length ) {
|
nkeynes@697 | 433 | buf = audio_next_write_buffer();
|
nkeynes@697 | 434 | if( buf == NULL ) {
|
nkeynes@697 | 435 | // All buffers are full
|
nkeynes@697 | 436 | break;
|
nkeynes@697 | 437 | }
|
nkeynes@697 | 438 | buf = audio.output_buffers[audio.write_buffer];
|
nkeynes@700 | 439 | data = (int8_t *)&buf->data[0];
|
nkeynes@697 | 440 | }
|
nkeynes@697 | 441 | }
|
nkeynes@697 | 442 | break;
|
nkeynes@697 | 443 | }
|
nkeynes@66 | 444 | }
|
nkeynes@66 | 445 | }
|
nkeynes@66 | 446 |
|
nkeynes@66 | 447 | /********************** Internal AICA calls ***************************/
|
nkeynes@66 | 448 |
|
nkeynes@66 | 449 | audio_channel_t audio_get_channel( int channel )
|
nkeynes@66 | 450 | {
|
nkeynes@66 | 451 | return &audio.channels[channel];
|
nkeynes@66 | 452 | }
|
nkeynes@66 | 453 |
|
nkeynes@434 | 454 | void audio_start_stop_channel( int channel, gboolean start )
|
nkeynes@434 | 455 | {
|
nkeynes@434 | 456 | if( audio.channels[channel].active ) {
|
nkeynes@736 | 457 | if( !start ) {
|
nkeynes@736 | 458 | audio_stop_channel(channel);
|
nkeynes@736 | 459 | }
|
nkeynes@434 | 460 | } else if( start ) {
|
nkeynes@736 | 461 | audio_start_channel(channel);
|
nkeynes@434 | 462 | }
|
nkeynes@434 | 463 | }
|
nkeynes@434 | 464 |
|
nkeynes@66 | 465 | void audio_stop_channel( int channel )
|
nkeynes@66 | 466 | {
|
nkeynes@66 | 467 | audio.channels[channel].active = FALSE;
|
nkeynes@66 | 468 | }
|
nkeynes@66 | 469 |
|
nkeynes@66 | 470 |
|
nkeynes@66 | 471 | void audio_start_channel( int channel )
|
nkeynes@66 | 472 | {
|
nkeynes@66 | 473 | audio.channels[channel].posn = 0;
|
nkeynes@66 | 474 | audio.channels[channel].posn_left = 0;
|
nkeynes@66 | 475 | audio.channels[channel].active = TRUE;
|
nkeynes@434 | 476 | if( audio.channels[channel].sample_format == AUDIO_FMT_ADPCM ) {
|
nkeynes@736 | 477 | audio.channels[channel].adpcm_step = 0;
|
nkeynes@736 | 478 | audio.channels[channel].adpcm_predict = 0;
|
nkeynes@934 | 479 | uint8_t data = ((uint8_t *)(aica_main_ram + audio.channels[channel].start))[0];
|
nkeynes@736 | 480 | adpcm_yamaha_decode_nibble( &audio.channels[channel], data & 0x0F );
|
nkeynes@434 | 481 | }
|
nkeynes@66 | 482 | }
|