filename | src/aica/audio.c |
changeset | 1089:a3984d242909 |
prev | 1024:c67f2d61ab97 |
next | 1296:30ecee61f811 |
author | nkeynes |
date | Fri Mar 02 23:49:10 2012 +1000 (12 years ago) |
permissions | -rw-r--r-- |
last change | Android WIP: * Rename gui_jni.c to gui_android.c - now quite android specific. * Implement generic EGL driver with very minimal Java wrapper * Run emulation in separate thread, and implement simple queue for inter-thread communication. * Add menu/action-bar items for start + reset |
file | annotate | diff | log | raw |
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@1024 | 27 | #define MAX_AUDIO_DRIVERS 16 |
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@989 | 33 | extern struct audio_driver audio_sdl_driver; |
nkeynes@697 | 34 | |
nkeynes@1024 | 35 | static int audio_driver_count = 0; |
nkeynes@1024 | 36 | static audio_driver_t audio_driver_list[MAX_AUDIO_DRIVERS] = {}; |
nkeynes@531 | 37 | |
nkeynes@66 | 38 | #define NUM_BUFFERS 3 |
nkeynes@700 | 39 | #define MS_PER_BUFFER 100 |
nkeynes@66 | 40 | |
nkeynes@66 | 41 | #define BUFFER_EMPTY 0 |
nkeynes@66 | 42 | #define BUFFER_WRITING 1 |
nkeynes@66 | 43 | #define BUFFER_FULL 2 |
nkeynes@66 | 44 | |
nkeynes@66 | 45 | struct audio_state { |
nkeynes@66 | 46 | audio_buffer_t output_buffers[NUM_BUFFERS]; |
nkeynes@66 | 47 | int write_buffer; |
nkeynes@66 | 48 | int read_buffer; |
nkeynes@66 | 49 | uint32_t output_format; |
nkeynes@66 | 50 | uint32_t output_rate; |
nkeynes@66 | 51 | uint32_t output_sample_size; |
nkeynes@465 | 52 | struct audio_channel channels[AUDIO_CHANNEL_COUNT]; |
nkeynes@66 | 53 | } audio; |
nkeynes@66 | 54 | |
nkeynes@66 | 55 | audio_driver_t audio_driver = NULL; |
nkeynes@66 | 56 | |
nkeynes@66 | 57 | #define NEXT_BUFFER() ((audio.write_buffer == NUM_BUFFERS-1) ? 0 : audio.write_buffer+1) |
nkeynes@66 | 58 | |
nkeynes@66 | 59 | /** |
nkeynes@465 | 60 | * Preserve audio channel state only - don't bother saving the buffers |
nkeynes@465 | 61 | */ |
nkeynes@465 | 62 | void audio_save_state( FILE *f ) |
nkeynes@465 | 63 | { |
nkeynes@465 | 64 | fwrite( &audio.channels[0], sizeof(struct audio_channel), AUDIO_CHANNEL_COUNT, f ); |
nkeynes@465 | 65 | } |
nkeynes@465 | 66 | |
nkeynes@465 | 67 | int audio_load_state( FILE *f ) |
nkeynes@465 | 68 | { |
nkeynes@465 | 69 | int read = fread( &audio.channels[0], sizeof(struct audio_channel), AUDIO_CHANNEL_COUNT, f ); |
nkeynes@465 | 70 | return (read == AUDIO_CHANNEL_COUNT ? 0 : -1 ); |
nkeynes@465 | 71 | } |
nkeynes@465 | 72 | |
nkeynes@1024 | 73 | static int audio_driver_priority_compare(const void *a, const void *b) |
nkeynes@1024 | 74 | { |
nkeynes@1024 | 75 | audio_driver_t ada = *(audio_driver_t *)a; |
nkeynes@1024 | 76 | audio_driver_t adb = *(audio_driver_t *)b; |
nkeynes@1024 | 77 | return ada->priority - adb->priority; |
nkeynes@1024 | 78 | } |
nkeynes@1024 | 79 | |
nkeynes@1024 | 80 | static int audio_driver_name_compare(const void *a, const void *b) |
nkeynes@1024 | 81 | { |
nkeynes@1024 | 82 | audio_driver_t ada = *(audio_driver_t *)a; |
nkeynes@1024 | 83 | audio_driver_t adb = *(audio_driver_t *)b; |
nkeynes@1024 | 84 | return strcasecmp( ada->name, adb->name ); |
nkeynes@1024 | 85 | } |
nkeynes@1024 | 86 | |
nkeynes@1024 | 87 | |
nkeynes@1024 | 88 | |
nkeynes@1024 | 89 | gboolean audio_register_driver( audio_driver_t driver ) |
nkeynes@1024 | 90 | { |
nkeynes@1024 | 91 | if( audio_driver_count >= MAX_AUDIO_DRIVERS ) { |
nkeynes@1024 | 92 | return FALSE; |
nkeynes@1024 | 93 | } |
nkeynes@1024 | 94 | audio_driver_list[audio_driver_count++] = driver; |
nkeynes@1024 | 95 | qsort( audio_driver_list, audio_driver_count, sizeof( audio_driver_t ), audio_driver_priority_compare ); |
nkeynes@1024 | 96 | return TRUE; |
nkeynes@1024 | 97 | } |
nkeynes@1024 | 98 | |
nkeynes@531 | 99 | audio_driver_t get_audio_driver_by_name( const char *name ) |
nkeynes@531 | 100 | { |
nkeynes@531 | 101 | int i; |
nkeynes@531 | 102 | if( name == NULL ) { |
nkeynes@697 | 103 | return audio_driver_list[0]; |
nkeynes@531 | 104 | } |
nkeynes@1024 | 105 | for( i=0; i < audio_driver_count; i++ ) { |
nkeynes@697 | 106 | if( strcasecmp( audio_driver_list[i]->name, name ) == 0 ) { |
nkeynes@697 | 107 | return audio_driver_list[i]; |
nkeynes@697 | 108 | } |
nkeynes@531 | 109 | } |
nkeynes@531 | 110 | |
nkeynes@531 | 111 | return NULL; |
nkeynes@531 | 112 | } |
nkeynes@531 | 113 | |
nkeynes@700 | 114 | void print_audio_drivers( FILE * out ) |
nkeynes@700 | 115 | { |
nkeynes@700 | 116 | int i; |
nkeynes@1024 | 117 | audio_driver_t temp_list[MAX_AUDIO_DRIVERS]; |
nkeynes@1024 | 118 | memcpy( temp_list, audio_driver_list, audio_driver_count*sizeof(audio_driver_t) ); |
nkeynes@1024 | 119 | qsort( temp_list, audio_driver_count, sizeof(audio_driver_t), audio_driver_name_compare ); |
nkeynes@700 | 120 | fprintf( out, "Available audio drivers:\n" ); |
nkeynes@1024 | 121 | for( i=0; i < audio_driver_count; i++ ) { |
nkeynes@1024 | 122 | fprintf( out, " %-8s %s\n", temp_list[i]->name, |
nkeynes@1024 | 123 | gettext(temp_list[i]->description) ); |
nkeynes@700 | 124 | } |
nkeynes@700 | 125 | } |
nkeynes@700 | 126 | |
nkeynes@697 | 127 | audio_driver_t audio_init_driver( const char *preferred_driver ) |
nkeynes@697 | 128 | { |
nkeynes@697 | 129 | audio_driver_t audio_driver = get_audio_driver_by_name(preferred_driver); |
nkeynes@697 | 130 | if( audio_driver == NULL ) { |
nkeynes@697 | 131 | ERROR( "Audio driver '%s' not found, aborting.", preferred_driver ); |
nkeynes@697 | 132 | exit(2); |
nkeynes@697 | 133 | } else if( audio_set_driver( audio_driver ) == FALSE ) { |
nkeynes@779 | 134 | int i; |
nkeynes@1024 | 135 | for( i=0; i < audio_driver_count; i++ ) { |
nkeynes@779 | 136 | if( audio_driver_list[i] != audio_driver && |
nkeynes@779 | 137 | audio_set_driver( audio_driver_list[i] ) ) { |
nkeynes@779 | 138 | ERROR( "Failed to initialize audio driver %s, falling back to %s", |
nkeynes@779 | 139 | audio_driver->name, audio_driver_list[i]->name ); |
nkeynes@779 | 140 | return audio_driver_list[i]; |
nkeynes@779 | 141 | } |
nkeynes@779 | 142 | } |
nkeynes@779 | 143 | ERROR( "Unable to intialize any audio driver, aborting." ); |
nkeynes@779 | 144 | exit(2); |
nkeynes@759 | 145 | } |
nkeynes@759 | 146 | return audio_driver; |
nkeynes@697 | 147 | } |
nkeynes@697 | 148 | |
nkeynes@1024 | 149 | void audio_start_driver(void) |
nkeynes@1024 | 150 | { |
nkeynes@1024 | 151 | if( audio_driver != NULL && audio_driver->start != NULL ) { |
nkeynes@1024 | 152 | audio_driver->start(); |
nkeynes@1024 | 153 | } |
nkeynes@1024 | 154 | } |
nkeynes@1024 | 155 | |
nkeynes@1024 | 156 | void audio_stop_driver(void) |
nkeynes@1024 | 157 | { |
nkeynes@1024 | 158 | if( audio_driver != NULL && audio_driver->stop != NULL ) { |
nkeynes@1024 | 159 | audio_driver->stop(); |
nkeynes@1024 | 160 | } |
nkeynes@1024 | 161 | } |
nkeynes@1024 | 162 | |
nkeynes@465 | 163 | /** |
nkeynes@66 | 164 | * Set the output driver, sample rate and format. Also initializes the |
nkeynes@66 | 165 | * output buffers, flushing any current data and reallocating as |
nkeynes@66 | 166 | * necessary. |
nkeynes@66 | 167 | */ |
nkeynes@697 | 168 | gboolean audio_set_driver( audio_driver_t driver ) |
nkeynes@66 | 169 | { |
nkeynes@66 | 170 | uint32_t bytes_per_sample = 1; |
nkeynes@66 | 171 | uint32_t samples_per_buffer; |
nkeynes@66 | 172 | int i; |
nkeynes@66 | 173 | |
nkeynes@111 | 174 | if( audio_driver == NULL || driver != NULL ) { |
nkeynes@697 | 175 | if( driver == NULL ) |
nkeynes@697 | 176 | driver = &audio_null_driver; |
nkeynes@697 | 177 | if( driver != audio_driver ) { |
nkeynes@697 | 178 | if( !driver->init() ) |
nkeynes@697 | 179 | return FALSE; |
nkeynes@697 | 180 | audio_driver = driver; |
nkeynes@697 | 181 | } |
nkeynes@111 | 182 | } |
nkeynes@111 | 183 | |
nkeynes@697 | 184 | switch( driver->sample_format & AUDIO_FMT_SAMPLE_MASK ) { |
nkeynes@697 | 185 | case AUDIO_FMT_8BIT: |
nkeynes@697 | 186 | bytes_per_sample = 1; |
nkeynes@697 | 187 | break; |
nkeynes@697 | 188 | case AUDIO_FMT_16BIT: |
nkeynes@697 | 189 | bytes_per_sample = 2; |
nkeynes@697 | 190 | break; |
nkeynes@697 | 191 | case AUDIO_FMT_FLOAT: |
nkeynes@697 | 192 | bytes_per_sample = 4; |
nkeynes@697 | 193 | break; |
nkeynes@697 | 194 | } |
nkeynes@697 | 195 | |
nkeynes@697 | 196 | if( driver->sample_format & AUDIO_FMT_STEREO ) |
nkeynes@697 | 197 | bytes_per_sample <<= 1; |
nkeynes@697 | 198 | if( driver->sample_rate == audio.output_rate && |
nkeynes@697 | 199 | bytes_per_sample == audio.output_sample_size ) |
nkeynes@697 | 200 | return TRUE; |
nkeynes@697 | 201 | samples_per_buffer = (driver->sample_rate * MS_PER_BUFFER / 1000); |
nkeynes@66 | 202 | for( i=0; i<NUM_BUFFERS; i++ ) { |
nkeynes@697 | 203 | if( audio.output_buffers[i] != NULL ) |
nkeynes@697 | 204 | free(audio.output_buffers[i]); |
nkeynes@697 | 205 | audio.output_buffers[i] = g_malloc0( sizeof(struct audio_buffer) + samples_per_buffer * bytes_per_sample ); |
nkeynes@697 | 206 | audio.output_buffers[i]->length = samples_per_buffer * bytes_per_sample; |
nkeynes@697 | 207 | audio.output_buffers[i]->posn = 0; |
nkeynes@697 | 208 | audio.output_buffers[i]->status = BUFFER_EMPTY; |
nkeynes@66 | 209 | } |
nkeynes@697 | 210 | audio.output_format = driver->sample_format; |
nkeynes@697 | 211 | audio.output_rate = driver->sample_rate; |
nkeynes@66 | 212 | audio.output_sample_size = bytes_per_sample; |
nkeynes@66 | 213 | audio.write_buffer = 0; |
nkeynes@66 | 214 | audio.read_buffer = 0; |
nkeynes@66 | 215 | |
nkeynes@111 | 216 | return TRUE; |
nkeynes@66 | 217 | } |
nkeynes@66 | 218 | |
nkeynes@66 | 219 | /** |
nkeynes@66 | 220 | * Mark the current write buffer as full and prepare the next buffer for |
nkeynes@66 | 221 | * writing. Returns the next buffer to write to. |
nkeynes@66 | 222 | * If all buffers are full, returns NULL. |
nkeynes@66 | 223 | */ |
nkeynes@66 | 224 | audio_buffer_t audio_next_write_buffer( ) |
nkeynes@66 | 225 | { |
nkeynes@66 | 226 | audio_buffer_t result = NULL; |
nkeynes@66 | 227 | audio_buffer_t current = audio.output_buffers[audio.write_buffer]; |
nkeynes@66 | 228 | current->status = BUFFER_FULL; |
nkeynes@66 | 229 | if( audio.read_buffer == audio.write_buffer && |
nkeynes@697 | 230 | audio_driver->process_buffer( current ) ) { |
nkeynes@697 | 231 | audio_next_read_buffer(); |
nkeynes@66 | 232 | } |
nkeynes@697 | 233 | int next_buffer = NEXT_BUFFER(); |
nkeynes@697 | 234 | result = audio.output_buffers[next_buffer]; |
nkeynes@66 | 235 | if( result->status == BUFFER_FULL ) |
nkeynes@697 | 236 | return NULL; |
nkeynes@66 | 237 | else { |
nkeynes@697 | 238 | audio.write_buffer = next_buffer; |
nkeynes@697 | 239 | result->status = BUFFER_WRITING; |
nkeynes@697 | 240 | return result; |
nkeynes@66 | 241 | } |
nkeynes@66 | 242 | } |
nkeynes@66 | 243 | |
nkeynes@66 | 244 | /** |
nkeynes@66 | 245 | * Mark the current read buffer as empty and return the next buffer for |
nkeynes@66 | 246 | * reading. If there is no next buffer yet, returns NULL. |
nkeynes@66 | 247 | */ |
nkeynes@66 | 248 | audio_buffer_t audio_next_read_buffer( ) |
nkeynes@66 | 249 | { |
nkeynes@66 | 250 | audio_buffer_t current = audio.output_buffers[audio.read_buffer]; |
nkeynes@697 | 251 | if( current->status == BUFFER_FULL ) { |
nkeynes@697 | 252 | // Current read buffer has data, which we've just emptied |
nkeynes@697 | 253 | current->status = BUFFER_EMPTY; |
nkeynes@697 | 254 | current->posn = 0; |
nkeynes@697 | 255 | audio.read_buffer++; |
nkeynes@697 | 256 | if( audio.read_buffer == NUM_BUFFERS ) |
nkeynes@697 | 257 | audio.read_buffer = 0; |
nkeynes@697 | 258 | |
nkeynes@697 | 259 | current = audio.output_buffers[audio.read_buffer]; |
nkeynes@697 | 260 | if( current->status == BUFFER_FULL ) { |
nkeynes@697 | 261 | current->posn = 0; |
nkeynes@697 | 262 | return current; |
nkeynes@697 | 263 | } |
nkeynes@697 | 264 | else return NULL; |
nkeynes@697 | 265 | } else { |
nkeynes@697 | 266 | return NULL; |
nkeynes@697 | 267 | } |
nkeynes@697 | 268 | |
nkeynes@66 | 269 | } |
nkeynes@66 | 270 | |
nkeynes@66 | 271 | /*************************** ADPCM ***********************************/ |
nkeynes@66 | 272 | |
nkeynes@66 | 273 | /** |
nkeynes@66 | 274 | * The following section borrows heavily from ffmpeg, which is |
nkeynes@66 | 275 | * copyright (c) 2001-2003 by the fine folks at the ffmpeg project, |
nkeynes@66 | 276 | * distributed under the GPL version 2 or later. |
nkeynes@66 | 277 | */ |
nkeynes@66 | 278 | |
nkeynes@66 | 279 | #define CLAMP_TO_SHORT(value) \ |
nkeynes@736 | 280 | if (value > 32767) \ |
nkeynes@66 | 281 | value = 32767; \ |
nkeynes@736 | 282 | else if (value < -32768) \ |
nkeynes@66 | 283 | value = -32768; \ |
nkeynes@66 | 284 | |
nkeynes@66 | 285 | static const int yamaha_indexscale[] = { |
nkeynes@736 | 286 | 230, 230, 230, 230, 307, 409, 512, 614, |
nkeynes@736 | 287 | 230, 230, 230, 230, 307, 409, 512, 614 |
nkeynes@66 | 288 | }; |
nkeynes@66 | 289 | |
nkeynes@66 | 290 | static const int yamaha_difflookup[] = { |
nkeynes@736 | 291 | 1, 3, 5, 7, 9, 11, 13, 15, |
nkeynes@736 | 292 | -1, -3, -5, -7, -9, -11, -13, -15 |
nkeynes@66 | 293 | }; |
nkeynes@66 | 294 | |
nkeynes@66 | 295 | static inline short adpcm_yamaha_decode_nibble( audio_channel_t c, |
nkeynes@736 | 296 | unsigned char nibble ) |
nkeynes@66 | 297 | { |
nkeynes@66 | 298 | if( c->adpcm_step == 0 ) { |
nkeynes@66 | 299 | c->adpcm_predict = 0; |
nkeynes@66 | 300 | c->adpcm_step = 127; |
nkeynes@66 | 301 | } |
nkeynes@66 | 302 | |
nkeynes@66 | 303 | c->adpcm_predict += (c->adpcm_step * yamaha_difflookup[nibble]) >> 3; |
nkeynes@66 | 304 | CLAMP_TO_SHORT(c->adpcm_predict); |
nkeynes@66 | 305 | c->adpcm_step = (c->adpcm_step * yamaha_indexscale[nibble]) >> 8; |
nkeynes@66 | 306 | c->adpcm_step = CLAMP(c->adpcm_step, 127, 24567); |
nkeynes@66 | 307 | return c->adpcm_predict; |
nkeynes@66 | 308 | } |
nkeynes@66 | 309 | |
nkeynes@66 | 310 | /*************************** Sample mixer *****************************/ |
nkeynes@66 | 311 | |
nkeynes@66 | 312 | /** |
nkeynes@66 | 313 | * Mix a single output sample. |
nkeynes@66 | 314 | */ |
nkeynes@73 | 315 | void audio_mix_samples( int num_samples ) |
nkeynes@66 | 316 | { |
nkeynes@66 | 317 | int i, j; |
nkeynes@73 | 318 | int32_t result_buf[num_samples][2]; |
nkeynes@73 | 319 | |
nkeynes@73 | 320 | memset( &result_buf, 0, sizeof(result_buf) ); |
nkeynes@66 | 321 | |
nkeynes@465 | 322 | for( i=0; i < AUDIO_CHANNEL_COUNT; i++ ) { |
nkeynes@697 | 323 | audio_channel_t channel = &audio.channels[i]; |
nkeynes@697 | 324 | if( channel->active ) { |
nkeynes@697 | 325 | int32_t sample; |
nkeynes@697 | 326 | int vol_left = (channel->vol * (32 - channel->pan)) >> 5; |
nkeynes@697 | 327 | int vol_right = (channel->vol * (channel->pan + 1)) >> 5; |
nkeynes@697 | 328 | switch( channel->sample_format ) { |
nkeynes@697 | 329 | case AUDIO_FMT_16BIT: |
nkeynes@697 | 330 | for( j=0; j<num_samples; j++ ) { |
nkeynes@1089 | 331 | sample = *(int16_t *)(aica_main_ram + ((channel->start + channel->posn*2)&AUDIO_MEM_MASK)); |
nkeynes@697 | 332 | result_buf[j][0] += sample * vol_left; |
nkeynes@697 | 333 | result_buf[j][1] += sample * vol_right; |
nkeynes@697 | 334 | |
nkeynes@697 | 335 | channel->posn_left += channel->sample_rate; |
nkeynes@697 | 336 | while( channel->posn_left > audio.output_rate ) { |
nkeynes@697 | 337 | channel->posn_left -= audio.output_rate; |
nkeynes@697 | 338 | channel->posn++; |
nkeynes@697 | 339 | |
nkeynes@697 | 340 | if( channel->posn == channel->end ) { |
nkeynes@697 | 341 | if( channel->loop ) { |
nkeynes@697 | 342 | channel->posn = channel->loop_start; |
nkeynes@697 | 343 | channel->loop = LOOP_LOOPED; |
nkeynes@697 | 344 | } else { |
nkeynes@697 | 345 | audio_stop_channel(i); |
nkeynes@697 | 346 | j = num_samples; |
nkeynes@697 | 347 | break; |
nkeynes@697 | 348 | } |
nkeynes@697 | 349 | } |
nkeynes@697 | 350 | } |
nkeynes@697 | 351 | } |
nkeynes@697 | 352 | break; |
nkeynes@697 | 353 | case AUDIO_FMT_8BIT: |
nkeynes@697 | 354 | for( j=0; j<num_samples; j++ ) { |
nkeynes@1089 | 355 | sample = (*(int8_t *)(aica_main_ram + ((channel->start + channel->posn)&AUDIO_MEM_MASK))) << 8; |
nkeynes@697 | 356 | result_buf[j][0] += sample * vol_left; |
nkeynes@697 | 357 | result_buf[j][1] += sample * vol_right; |
nkeynes@697 | 358 | |
nkeynes@697 | 359 | channel->posn_left += channel->sample_rate; |
nkeynes@697 | 360 | while( channel->posn_left > audio.output_rate ) { |
nkeynes@697 | 361 | channel->posn_left -= audio.output_rate; |
nkeynes@697 | 362 | channel->posn++; |
nkeynes@697 | 363 | |
nkeynes@697 | 364 | if( channel->posn == channel->end ) { |
nkeynes@697 | 365 | if( channel->loop ) { |
nkeynes@697 | 366 | channel->posn = channel->loop_start; |
nkeynes@697 | 367 | channel->loop = LOOP_LOOPED; |
nkeynes@697 | 368 | } else { |
nkeynes@697 | 369 | audio_stop_channel(i); |
nkeynes@697 | 370 | j = num_samples; |
nkeynes@697 | 371 | break; |
nkeynes@697 | 372 | } |
nkeynes@697 | 373 | } |
nkeynes@697 | 374 | } |
nkeynes@697 | 375 | } |
nkeynes@697 | 376 | break; |
nkeynes@697 | 377 | case AUDIO_FMT_ADPCM: |
nkeynes@697 | 378 | for( j=0; j<num_samples; j++ ) { |
nkeynes@697 | 379 | sample = (int16_t)channel->adpcm_predict; |
nkeynes@697 | 380 | result_buf[j][0] += sample * vol_left; |
nkeynes@697 | 381 | result_buf[j][1] += sample * vol_right; |
nkeynes@697 | 382 | channel->posn_left += channel->sample_rate; |
nkeynes@697 | 383 | while( channel->posn_left > audio.output_rate ) { |
nkeynes@697 | 384 | channel->posn_left -= audio.output_rate; |
nkeynes@697 | 385 | channel->posn++; |
nkeynes@697 | 386 | if( channel->posn == channel->end ) { |
nkeynes@697 | 387 | if( channel->loop ) { |
nkeynes@697 | 388 | channel->posn = channel->loop_start; |
nkeynes@697 | 389 | channel->loop = LOOP_LOOPED; |
nkeynes@697 | 390 | channel->adpcm_predict = 0; |
nkeynes@697 | 391 | channel->adpcm_step = 0; |
nkeynes@697 | 392 | } else { |
nkeynes@697 | 393 | audio_stop_channel(i); |
nkeynes@697 | 394 | j = num_samples; |
nkeynes@697 | 395 | break; |
nkeynes@697 | 396 | } |
nkeynes@697 | 397 | } |
nkeynes@1089 | 398 | uint8_t data = *(uint8_t *)(aica_main_ram + ((channel->start + (channel->posn>>1))&AUDIO_MEM_MASK)); |
nkeynes@697 | 399 | if( channel->posn&1 ) { |
nkeynes@697 | 400 | adpcm_yamaha_decode_nibble( channel, (data >> 4) & 0x0F ); |
nkeynes@697 | 401 | } else { |
nkeynes@697 | 402 | adpcm_yamaha_decode_nibble( channel, data & 0x0F ); |
nkeynes@697 | 403 | } |
nkeynes@697 | 404 | } |
nkeynes@697 | 405 | } |
nkeynes@697 | 406 | break; |
nkeynes@697 | 407 | default: |
nkeynes@697 | 408 | break; |
nkeynes@697 | 409 | } |
nkeynes@697 | 410 | } |
nkeynes@66 | 411 | } |
nkeynes@736 | 412 | |
nkeynes@66 | 413 | /* Down-render to the final output format */ |
nkeynes@697 | 414 | audio_buffer_t buf = audio.output_buffers[audio.write_buffer]; |
nkeynes@697 | 415 | if( buf->status == BUFFER_FULL ) { |
nkeynes@697 | 416 | buf = audio_next_write_buffer(); |
nkeynes@697 | 417 | if( buf == NULL ) { // no available space |
nkeynes@697 | 418 | return; |
nkeynes@697 | 419 | } |
nkeynes@697 | 420 | } |
nkeynes@736 | 421 | |
nkeynes@697 | 422 | switch( audio.output_format & AUDIO_FMT_SAMPLE_MASK ) { |
nkeynes@697 | 423 | case AUDIO_FMT_FLOAT: { |
nkeynes@697 | 424 | float scale = 1.0/SHRT_MAX; |
nkeynes@697 | 425 | float *data = (float *)&buf->data[buf->posn]; |
nkeynes@697 | 426 | for( j=0; j<num_samples; j++ ) { |
nkeynes@697 | 427 | *data++ = scale * (result_buf[j][0] >> 6); |
nkeynes@697 | 428 | *data++ = scale * (result_buf[j][1] >> 6); |
nkeynes@697 | 429 | buf->posn += 8; |
nkeynes@697 | 430 | if( buf->posn == buf->length ) { |
nkeynes@697 | 431 | buf = audio_next_write_buffer(); |
nkeynes@697 | 432 | if( buf == NULL ) { |
nkeynes@697 | 433 | break; |
nkeynes@697 | 434 | } |
nkeynes@697 | 435 | data = (float *)&buf->data[0]; |
nkeynes@697 | 436 | } |
nkeynes@697 | 437 | } |
nkeynes@697 | 438 | break; |
nkeynes@697 | 439 | } |
nkeynes@697 | 440 | case AUDIO_FMT_16BIT: { |
nkeynes@697 | 441 | int16_t *data = (int16_t *)&buf->data[buf->posn]; |
nkeynes@697 | 442 | for( j=0; j < num_samples; j++ ) { |
nkeynes@697 | 443 | *data++ = (int16_t)(result_buf[j][0] >> 6); |
nkeynes@697 | 444 | *data++ = (int16_t)(result_buf[j][1] >> 6); |
nkeynes@697 | 445 | buf->posn += 4; |
nkeynes@697 | 446 | if( buf->posn == buf->length ) { |
nkeynes@697 | 447 | buf = audio_next_write_buffer(); |
nkeynes@697 | 448 | if( buf == NULL ) { |
nkeynes@697 | 449 | // All buffers are full |
nkeynes@697 | 450 | break; |
nkeynes@697 | 451 | } |
nkeynes@697 | 452 | data = (int16_t *)&buf->data[0]; |
nkeynes@697 | 453 | } |
nkeynes@697 | 454 | } |
nkeynes@697 | 455 | break; |
nkeynes@697 | 456 | } |
nkeynes@697 | 457 | case AUDIO_FMT_8BIT: { |
nkeynes@700 | 458 | int8_t *data = (int8_t *)&buf->data[buf->posn]; |
nkeynes@697 | 459 | for( j=0; j < num_samples; j++ ) { |
nkeynes@697 | 460 | *data++ = (int8_t)(result_buf[j][0] >> 16); |
nkeynes@697 | 461 | *data++ = (int8_t)(result_buf[j][1] >> 16); |
nkeynes@697 | 462 | buf->posn += 2; |
nkeynes@697 | 463 | if( buf->posn == buf->length ) { |
nkeynes@697 | 464 | buf = audio_next_write_buffer(); |
nkeynes@697 | 465 | if( buf == NULL ) { |
nkeynes@697 | 466 | // All buffers are full |
nkeynes@697 | 467 | break; |
nkeynes@697 | 468 | } |
nkeynes@697 | 469 | buf = audio.output_buffers[audio.write_buffer]; |
nkeynes@700 | 470 | data = (int8_t *)&buf->data[0]; |
nkeynes@697 | 471 | } |
nkeynes@697 | 472 | } |
nkeynes@697 | 473 | break; |
nkeynes@697 | 474 | } |
nkeynes@66 | 475 | } |
nkeynes@66 | 476 | } |
nkeynes@66 | 477 | |
nkeynes@66 | 478 | /********************** Internal AICA calls ***************************/ |
nkeynes@66 | 479 | |
nkeynes@66 | 480 | audio_channel_t audio_get_channel( int channel ) |
nkeynes@66 | 481 | { |
nkeynes@66 | 482 | return &audio.channels[channel]; |
nkeynes@66 | 483 | } |
nkeynes@66 | 484 | |
nkeynes@434 | 485 | void audio_start_stop_channel( int channel, gboolean start ) |
nkeynes@434 | 486 | { |
nkeynes@434 | 487 | if( audio.channels[channel].active ) { |
nkeynes@736 | 488 | if( !start ) { |
nkeynes@736 | 489 | audio_stop_channel(channel); |
nkeynes@736 | 490 | } |
nkeynes@434 | 491 | } else if( start ) { |
nkeynes@736 | 492 | audio_start_channel(channel); |
nkeynes@434 | 493 | } |
nkeynes@434 | 494 | } |
nkeynes@434 | 495 | |
nkeynes@66 | 496 | void audio_stop_channel( int channel ) |
nkeynes@66 | 497 | { |
nkeynes@66 | 498 | audio.channels[channel].active = FALSE; |
nkeynes@66 | 499 | } |
nkeynes@66 | 500 | |
nkeynes@66 | 501 | |
nkeynes@66 | 502 | void audio_start_channel( int channel ) |
nkeynes@66 | 503 | { |
nkeynes@66 | 504 | audio.channels[channel].posn = 0; |
nkeynes@66 | 505 | audio.channels[channel].posn_left = 0; |
nkeynes@66 | 506 | audio.channels[channel].active = TRUE; |
nkeynes@434 | 507 | if( audio.channels[channel].sample_format == AUDIO_FMT_ADPCM ) { |
nkeynes@736 | 508 | audio.channels[channel].adpcm_step = 0; |
nkeynes@736 | 509 | audio.channels[channel].adpcm_predict = 0; |
nkeynes@934 | 510 | uint8_t data = ((uint8_t *)(aica_main_ram + audio.channels[channel].start))[0]; |
nkeynes@736 | 511 | adpcm_yamaha_decode_nibble( &audio.channels[channel], data & 0x0F ); |
nkeynes@434 | 512 | } |
nkeynes@66 | 513 | } |
.