Search
lxdream.org :: lxdream/src/aica/audio.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/aica/audio.c
changeset 736:a02d1475ccfd
prev700:4650d0c7f6f9
next759:f16975739abc
author nkeynes
date Mon Jul 14 07:44:42 2008 +0000 (15 years ago)
permissions -rw-r--r--
last change Re-indent everything consistently
Fix include guards for consistency as well
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@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
extern char *arm_mem;
nkeynes@66
    72
nkeynes@66
    73
/**
nkeynes@465
    74
 * Preserve audio channel state only - don't bother saving the buffers
nkeynes@465
    75
 */
nkeynes@465
    76
void audio_save_state( FILE *f )
nkeynes@465
    77
{
nkeynes@465
    78
    fwrite( &audio.channels[0], sizeof(struct audio_channel), AUDIO_CHANNEL_COUNT, f );
nkeynes@465
    79
}
nkeynes@465
    80
nkeynes@465
    81
int audio_load_state( FILE *f )
nkeynes@465
    82
{
nkeynes@465
    83
    int read = fread( &audio.channels[0], sizeof(struct audio_channel), AUDIO_CHANNEL_COUNT, f );
nkeynes@465
    84
    return (read == AUDIO_CHANNEL_COUNT ? 0 : -1 );
nkeynes@465
    85
}
nkeynes@465
    86
nkeynes@531
    87
audio_driver_t get_audio_driver_by_name( const char *name )
nkeynes@531
    88
{
nkeynes@531
    89
    int i;
nkeynes@531
    90
    if( name == NULL ) {
nkeynes@697
    91
        return audio_driver_list[0];
nkeynes@531
    92
    }
nkeynes@531
    93
    for( i=0; audio_driver_list[i] != NULL; i++ ) {
nkeynes@697
    94
        if( strcasecmp( audio_driver_list[i]->name, name ) == 0 ) {
nkeynes@697
    95
            return audio_driver_list[i];
nkeynes@697
    96
        }
nkeynes@531
    97
    }
nkeynes@531
    98
nkeynes@531
    99
    return NULL;
nkeynes@531
   100
}
nkeynes@531
   101
nkeynes@700
   102
void print_audio_drivers( FILE * out )
nkeynes@700
   103
{
nkeynes@700
   104
    int i;
nkeynes@700
   105
    fprintf( out, "Available audio drivers:\n" );
nkeynes@700
   106
    for( i=0; audio_driver_list[i] != NULL; i++ ) {
nkeynes@700
   107
        fprintf( out, "  %-8s %s\n", audio_driver_list[i]->name,
nkeynes@736
   108
                gettext(audio_driver_list[i]->description) );
nkeynes@700
   109
    }
nkeynes@700
   110
}
nkeynes@700
   111
nkeynes@697
   112
audio_driver_t audio_init_driver( const char *preferred_driver )
nkeynes@697
   113
{
nkeynes@697
   114
    audio_driver_t audio_driver = get_audio_driver_by_name(preferred_driver);
nkeynes@697
   115
    if( audio_driver == NULL ) {
nkeynes@697
   116
        ERROR( "Audio driver '%s' not found, aborting.", preferred_driver );
nkeynes@697
   117
        exit(2);
nkeynes@697
   118
    } else if( audio_set_driver( audio_driver ) == FALSE ) {
nkeynes@697
   119
        ERROR( "Failed to initialize audio driver '%s', using null driver", 
nkeynes@697
   120
                audio_driver->name );
nkeynes@697
   121
        audio_set_driver( &audio_null_driver );
nkeynes@697
   122
    }    
nkeynes@697
   123
}
nkeynes@697
   124
nkeynes@465
   125
/**
nkeynes@66
   126
 * Set the output driver, sample rate and format. Also initializes the 
nkeynes@66
   127
 * output buffers, flushing any current data and reallocating as 
nkeynes@66
   128
 * necessary.
nkeynes@66
   129
 */
nkeynes@697
   130
gboolean audio_set_driver( audio_driver_t driver )
nkeynes@66
   131
{
nkeynes@66
   132
    uint32_t bytes_per_sample = 1;
nkeynes@66
   133
    uint32_t samples_per_buffer;
nkeynes@66
   134
    int i;
nkeynes@66
   135
nkeynes@111
   136
    if( audio_driver == NULL || driver != NULL ) {
nkeynes@697
   137
        if( driver == NULL  )
nkeynes@697
   138
            driver = &audio_null_driver;
nkeynes@697
   139
        if( driver != audio_driver ) {	
nkeynes@697
   140
            if( !driver->init() )
nkeynes@697
   141
                return FALSE;
nkeynes@697
   142
            audio_driver = driver;
nkeynes@697
   143
        }
nkeynes@111
   144
    }
nkeynes@111
   145
nkeynes@697
   146
    switch( driver->sample_format & AUDIO_FMT_SAMPLE_MASK ) {
nkeynes@697
   147
    case AUDIO_FMT_8BIT:
nkeynes@697
   148
        bytes_per_sample = 1;
nkeynes@697
   149
        break;
nkeynes@697
   150
    case AUDIO_FMT_16BIT:
nkeynes@697
   151
        bytes_per_sample = 2;
nkeynes@697
   152
        break;
nkeynes@697
   153
    case AUDIO_FMT_FLOAT:
nkeynes@697
   154
        bytes_per_sample = 4;
nkeynes@697
   155
        break;
nkeynes@697
   156
    }
nkeynes@697
   157
nkeynes@697
   158
    if( driver->sample_format & AUDIO_FMT_STEREO )
nkeynes@697
   159
        bytes_per_sample <<= 1;
nkeynes@697
   160
    if( driver->sample_rate == audio.output_rate &&
nkeynes@697
   161
            bytes_per_sample == audio.output_sample_size )
nkeynes@697
   162
        return TRUE;
nkeynes@697
   163
    samples_per_buffer = (driver->sample_rate * MS_PER_BUFFER / 1000);
nkeynes@66
   164
    for( i=0; i<NUM_BUFFERS; i++ ) {
nkeynes@697
   165
        if( audio.output_buffers[i] != NULL )
nkeynes@697
   166
            free(audio.output_buffers[i]);
nkeynes@697
   167
        audio.output_buffers[i] = g_malloc0( sizeof(struct audio_buffer) + samples_per_buffer * bytes_per_sample );
nkeynes@697
   168
        audio.output_buffers[i]->length = samples_per_buffer * bytes_per_sample;
nkeynes@697
   169
        audio.output_buffers[i]->posn = 0;
nkeynes@697
   170
        audio.output_buffers[i]->status = BUFFER_EMPTY;
nkeynes@66
   171
    }
nkeynes@697
   172
    audio.output_format = driver->sample_format;
nkeynes@697
   173
    audio.output_rate = driver->sample_rate;
nkeynes@66
   174
    audio.output_sample_size = bytes_per_sample;
nkeynes@66
   175
    audio.write_buffer = 0;
nkeynes@66
   176
    audio.read_buffer = 0;
nkeynes@66
   177
nkeynes@111
   178
    return TRUE;
nkeynes@66
   179
}
nkeynes@66
   180
nkeynes@66
   181
/**
nkeynes@66
   182
 * Mark the current write buffer as full and prepare the next buffer for
nkeynes@66
   183
 * writing. Returns the next buffer to write to.
nkeynes@66
   184
 * If all buffers are full, returns NULL.
nkeynes@66
   185
 */
nkeynes@66
   186
audio_buffer_t audio_next_write_buffer( )
nkeynes@66
   187
{
nkeynes@66
   188
    audio_buffer_t result = NULL;
nkeynes@66
   189
    audio_buffer_t current = audio.output_buffers[audio.write_buffer];
nkeynes@66
   190
    current->status = BUFFER_FULL;
nkeynes@66
   191
    if( audio.read_buffer == audio.write_buffer &&
nkeynes@697
   192
            audio_driver->process_buffer( current ) ) {
nkeynes@697
   193
        audio_next_read_buffer();
nkeynes@66
   194
    }
nkeynes@697
   195
    int next_buffer = NEXT_BUFFER();
nkeynes@697
   196
    result = audio.output_buffers[next_buffer];
nkeynes@66
   197
    if( result->status == BUFFER_FULL )
nkeynes@697
   198
        return NULL;
nkeynes@66
   199
    else {
nkeynes@697
   200
        audio.write_buffer = next_buffer;
nkeynes@697
   201
        result->status = BUFFER_WRITING;
nkeynes@697
   202
        return result;
nkeynes@66
   203
    }
nkeynes@66
   204
}
nkeynes@66
   205
nkeynes@66
   206
/**
nkeynes@66
   207
 * Mark the current read buffer as empty and return the next buffer for
nkeynes@66
   208
 * reading. If there is no next buffer yet, returns NULL.
nkeynes@66
   209
 */
nkeynes@66
   210
audio_buffer_t audio_next_read_buffer( )
nkeynes@66
   211
{
nkeynes@66
   212
    audio_buffer_t current = audio.output_buffers[audio.read_buffer];
nkeynes@697
   213
    if( current->status == BUFFER_FULL ) {
nkeynes@697
   214
        // Current read buffer has data, which we've just emptied
nkeynes@697
   215
        current->status = BUFFER_EMPTY;
nkeynes@697
   216
        current->posn = 0;
nkeynes@697
   217
        audio.read_buffer++;
nkeynes@697
   218
        if( audio.read_buffer == NUM_BUFFERS )
nkeynes@697
   219
            audio.read_buffer = 0;
nkeynes@697
   220
nkeynes@697
   221
        current = audio.output_buffers[audio.read_buffer];
nkeynes@697
   222
        if( current->status == BUFFER_FULL ) {
nkeynes@697
   223
            current->posn = 0;
nkeynes@697
   224
            return current;
nkeynes@697
   225
        }
nkeynes@697
   226
        else return NULL;
nkeynes@697
   227
    } else {
nkeynes@697
   228
        return NULL;
nkeynes@697
   229
    }
nkeynes@697
   230
nkeynes@66
   231
}
nkeynes@66
   232
nkeynes@66
   233
/*************************** ADPCM ***********************************/
nkeynes@66
   234
nkeynes@66
   235
/**
nkeynes@66
   236
 * The following section borrows heavily from ffmpeg, which is
nkeynes@66
   237
 * copyright (c) 2001-2003 by the fine folks at the ffmpeg project,
nkeynes@66
   238
 * distributed under the GPL version 2 or later.
nkeynes@66
   239
 */
nkeynes@66
   240
nkeynes@66
   241
#define CLAMP_TO_SHORT(value) \
nkeynes@736
   242
    if (value > 32767) \
nkeynes@66
   243
    value = 32767; \
nkeynes@736
   244
    else if (value < -32768) \
nkeynes@66
   245
    value = -32768; \
nkeynes@66
   246
nkeynes@66
   247
static const int yamaha_indexscale[] = {
nkeynes@736
   248
        230, 230, 230, 230, 307, 409, 512, 614,
nkeynes@736
   249
        230, 230, 230, 230, 307, 409, 512, 614
nkeynes@66
   250
};
nkeynes@66
   251
nkeynes@66
   252
static const int yamaha_difflookup[] = {
nkeynes@736
   253
        1, 3, 5, 7, 9, 11, 13, 15,
nkeynes@736
   254
        -1, -3, -5, -7, -9, -11, -13, -15
nkeynes@66
   255
};
nkeynes@66
   256
nkeynes@66
   257
static inline short adpcm_yamaha_decode_nibble( audio_channel_t c, 
nkeynes@736
   258
                                                unsigned char nibble )
nkeynes@66
   259
{
nkeynes@66
   260
    if( c->adpcm_step == 0 ) {
nkeynes@66
   261
        c->adpcm_predict = 0;
nkeynes@66
   262
        c->adpcm_step = 127;
nkeynes@66
   263
    }
nkeynes@66
   264
nkeynes@66
   265
    c->adpcm_predict += (c->adpcm_step * yamaha_difflookup[nibble]) >> 3;
nkeynes@66
   266
    CLAMP_TO_SHORT(c->adpcm_predict);
nkeynes@66
   267
    c->adpcm_step = (c->adpcm_step * yamaha_indexscale[nibble]) >> 8;
nkeynes@66
   268
    c->adpcm_step = CLAMP(c->adpcm_step, 127, 24567);
nkeynes@66
   269
    return c->adpcm_predict;
nkeynes@66
   270
}
nkeynes@66
   271
nkeynes@66
   272
/*************************** Sample mixer *****************************/
nkeynes@66
   273
nkeynes@66
   274
/**
nkeynes@66
   275
 * Mix a single output sample.
nkeynes@66
   276
 */
nkeynes@73
   277
void audio_mix_samples( int num_samples )
nkeynes@66
   278
{
nkeynes@66
   279
    int i, j;
nkeynes@73
   280
    int32_t result_buf[num_samples][2];
nkeynes@73
   281
nkeynes@73
   282
    memset( &result_buf, 0, sizeof(result_buf) );
nkeynes@66
   283
nkeynes@465
   284
    for( i=0; i < AUDIO_CHANNEL_COUNT; i++ ) {
nkeynes@697
   285
        audio_channel_t channel = &audio.channels[i];
nkeynes@697
   286
        if( channel->active ) {
nkeynes@697
   287
            int32_t sample;
nkeynes@697
   288
            int vol_left = (channel->vol * (32 - channel->pan)) >> 5;
nkeynes@697
   289
            int vol_right = (channel->vol * (channel->pan + 1)) >> 5;
nkeynes@697
   290
            switch( channel->sample_format ) {
nkeynes@697
   291
            case AUDIO_FMT_16BIT:
nkeynes@697
   292
                for( j=0; j<num_samples; j++ ) {
nkeynes@697
   293
                    sample = ((int16_t *)(arm_mem + channel->start))[channel->posn];
nkeynes@697
   294
                    result_buf[j][0] += sample * vol_left;
nkeynes@697
   295
                    result_buf[j][1] += sample * vol_right;
nkeynes@697
   296
nkeynes@697
   297
                    channel->posn_left += channel->sample_rate;
nkeynes@697
   298
                    while( channel->posn_left > audio.output_rate ) {
nkeynes@697
   299
                        channel->posn_left -= audio.output_rate;
nkeynes@697
   300
                        channel->posn++;
nkeynes@697
   301
nkeynes@697
   302
                        if( channel->posn == channel->end ) {
nkeynes@697
   303
                            if( channel->loop ) {
nkeynes@697
   304
                                channel->posn = channel->loop_start;
nkeynes@697
   305
                                channel->loop = LOOP_LOOPED;
nkeynes@697
   306
                            } else {
nkeynes@697
   307
                                audio_stop_channel(i);
nkeynes@697
   308
                                j = num_samples;
nkeynes@697
   309
                                break;
nkeynes@697
   310
                            }
nkeynes@697
   311
                        }
nkeynes@697
   312
                    }
nkeynes@697
   313
                }
nkeynes@697
   314
                break;
nkeynes@697
   315
            case AUDIO_FMT_8BIT:
nkeynes@697
   316
                for( j=0; j<num_samples; j++ ) {
nkeynes@697
   317
                    sample = ((int8_t *)(arm_mem + channel->start))[channel->posn] << 8;
nkeynes@697
   318
                    result_buf[j][0] += sample * vol_left;
nkeynes@697
   319
                    result_buf[j][1] += sample * vol_right;
nkeynes@697
   320
nkeynes@697
   321
                    channel->posn_left += channel->sample_rate;
nkeynes@697
   322
                    while( channel->posn_left > audio.output_rate ) {
nkeynes@697
   323
                        channel->posn_left -= audio.output_rate;
nkeynes@697
   324
                        channel->posn++;
nkeynes@697
   325
nkeynes@697
   326
                        if( channel->posn == channel->end ) {
nkeynes@697
   327
                            if( channel->loop ) {
nkeynes@697
   328
                                channel->posn = channel->loop_start;
nkeynes@697
   329
                                channel->loop = LOOP_LOOPED;
nkeynes@697
   330
                            } else {
nkeynes@697
   331
                                audio_stop_channel(i);
nkeynes@697
   332
                                j = num_samples;
nkeynes@697
   333
                                break;
nkeynes@697
   334
                            }
nkeynes@697
   335
                        }
nkeynes@697
   336
                    }
nkeynes@697
   337
                }
nkeynes@697
   338
                break;
nkeynes@697
   339
            case AUDIO_FMT_ADPCM:
nkeynes@697
   340
                for( j=0; j<num_samples; j++ ) {
nkeynes@697
   341
                    sample = (int16_t)channel->adpcm_predict;
nkeynes@697
   342
                    result_buf[j][0] += sample * vol_left;
nkeynes@697
   343
                    result_buf[j][1] += sample * vol_right;
nkeynes@697
   344
                    channel->posn_left += channel->sample_rate;
nkeynes@697
   345
                    while( channel->posn_left > audio.output_rate ) {
nkeynes@697
   346
                        channel->posn_left -= audio.output_rate;
nkeynes@697
   347
                        channel->posn++;
nkeynes@697
   348
                        if( channel->posn == channel->end ) {
nkeynes@697
   349
                            if( channel->loop ) {
nkeynes@697
   350
                                channel->posn = channel->loop_start;
nkeynes@697
   351
                                channel->loop = LOOP_LOOPED;
nkeynes@697
   352
                                channel->adpcm_predict = 0;
nkeynes@697
   353
                                channel->adpcm_step = 0;
nkeynes@697
   354
                            } else {
nkeynes@697
   355
                                audio_stop_channel(i);
nkeynes@697
   356
                                j = num_samples;
nkeynes@697
   357
                                break;
nkeynes@697
   358
                            }
nkeynes@697
   359
                        }
nkeynes@697
   360
                        uint8_t data = ((uint8_t *)(arm_mem + channel->start))[channel->posn>>1];
nkeynes@697
   361
                        if( channel->posn&1 ) {
nkeynes@697
   362
                            adpcm_yamaha_decode_nibble( channel, (data >> 4) & 0x0F );
nkeynes@697
   363
                        } else {
nkeynes@697
   364
                            adpcm_yamaha_decode_nibble( channel, data & 0x0F );
nkeynes@697
   365
                        }
nkeynes@697
   366
                    }
nkeynes@697
   367
                }
nkeynes@697
   368
                break;
nkeynes@697
   369
            default:
nkeynes@697
   370
                break;
nkeynes@697
   371
            }
nkeynes@697
   372
        }
nkeynes@66
   373
    }
nkeynes@736
   374
nkeynes@66
   375
    /* Down-render to the final output format */
nkeynes@697
   376
    audio_buffer_t buf = audio.output_buffers[audio.write_buffer];
nkeynes@697
   377
    if( buf->status == BUFFER_FULL ) {
nkeynes@697
   378
        buf = audio_next_write_buffer();
nkeynes@697
   379
        if( buf == NULL ) { // no available space
nkeynes@697
   380
            return;
nkeynes@697
   381
        }
nkeynes@697
   382
    }
nkeynes@736
   383
nkeynes@697
   384
    switch( audio.output_format & AUDIO_FMT_SAMPLE_MASK ) {
nkeynes@697
   385
    case AUDIO_FMT_FLOAT: {
nkeynes@697
   386
        float scale = 1.0/SHRT_MAX;
nkeynes@697
   387
        float *data = (float *)&buf->data[buf->posn];
nkeynes@697
   388
        for( j=0; j<num_samples; j++ ) {
nkeynes@697
   389
            *data++ = scale * (result_buf[j][0] >> 6);
nkeynes@697
   390
            *data++ = scale * (result_buf[j][1] >> 6);
nkeynes@697
   391
            buf->posn += 8;
nkeynes@697
   392
            if( buf->posn == buf->length ) {
nkeynes@697
   393
                buf = audio_next_write_buffer();
nkeynes@697
   394
                if( buf == NULL ) {
nkeynes@697
   395
                    break;
nkeynes@697
   396
                }
nkeynes@697
   397
                data = (float *)&buf->data[0];
nkeynes@697
   398
            }
nkeynes@697
   399
        }
nkeynes@697
   400
        break;
nkeynes@697
   401
    }
nkeynes@697
   402
    case AUDIO_FMT_16BIT: {
nkeynes@697
   403
        int16_t *data = (int16_t *)&buf->data[buf->posn];
nkeynes@697
   404
        for( j=0; j < num_samples; j++ ) {
nkeynes@697
   405
            *data++ = (int16_t)(result_buf[j][0] >> 6);
nkeynes@697
   406
            *data++ = (int16_t)(result_buf[j][1] >> 6);	
nkeynes@697
   407
            buf->posn += 4;
nkeynes@697
   408
            if( buf->posn == buf->length ) {
nkeynes@697
   409
                buf = audio_next_write_buffer();
nkeynes@697
   410
                if( buf == NULL ) {
nkeynes@697
   411
                    // All buffers are full
nkeynes@697
   412
                    break;
nkeynes@697
   413
                }
nkeynes@697
   414
                data = (int16_t *)&buf->data[0];
nkeynes@697
   415
            }
nkeynes@697
   416
        }
nkeynes@697
   417
        break;
nkeynes@697
   418
    }
nkeynes@697
   419
    case AUDIO_FMT_8BIT: {
nkeynes@700
   420
        int8_t *data = (int8_t *)&buf->data[buf->posn];
nkeynes@697
   421
        for( j=0; j < num_samples; j++ ) {
nkeynes@697
   422
            *data++ = (int8_t)(result_buf[j][0] >> 16);
nkeynes@697
   423
            *data++ = (int8_t)(result_buf[j][1] >> 16);	
nkeynes@697
   424
            buf->posn += 2;
nkeynes@697
   425
            if( buf->posn == buf->length ) {
nkeynes@697
   426
                buf = audio_next_write_buffer();
nkeynes@697
   427
                if( buf == NULL ) {
nkeynes@697
   428
                    // All buffers are full
nkeynes@697
   429
                    break;
nkeynes@697
   430
                }
nkeynes@697
   431
                buf = audio.output_buffers[audio.write_buffer];
nkeynes@700
   432
                data = (int8_t *)&buf->data[0];
nkeynes@697
   433
            }
nkeynes@697
   434
        }
nkeynes@697
   435
        break;
nkeynes@697
   436
    }
nkeynes@66
   437
    }
nkeynes@66
   438
}
nkeynes@66
   439
nkeynes@66
   440
/********************** Internal AICA calls ***************************/
nkeynes@66
   441
nkeynes@66
   442
audio_channel_t audio_get_channel( int channel ) 
nkeynes@66
   443
{
nkeynes@66
   444
    return &audio.channels[channel];
nkeynes@66
   445
}
nkeynes@66
   446
nkeynes@434
   447
void audio_start_stop_channel( int channel, gboolean start )
nkeynes@434
   448
{
nkeynes@434
   449
    if( audio.channels[channel].active ) {
nkeynes@736
   450
        if( !start ) {
nkeynes@736
   451
            audio_stop_channel(channel);
nkeynes@736
   452
        }
nkeynes@434
   453
    } else if( start ) {
nkeynes@736
   454
        audio_start_channel(channel);
nkeynes@434
   455
    }
nkeynes@434
   456
}
nkeynes@434
   457
nkeynes@66
   458
void audio_stop_channel( int channel ) 
nkeynes@66
   459
{
nkeynes@66
   460
    audio.channels[channel].active = FALSE;
nkeynes@66
   461
}
nkeynes@66
   462
nkeynes@66
   463
nkeynes@66
   464
void audio_start_channel( int channel )
nkeynes@66
   465
{
nkeynes@66
   466
    audio.channels[channel].posn = 0;
nkeynes@66
   467
    audio.channels[channel].posn_left = 0;
nkeynes@66
   468
    audio.channels[channel].active = TRUE;
nkeynes@434
   469
    if( audio.channels[channel].sample_format == AUDIO_FMT_ADPCM ) {
nkeynes@736
   470
        audio.channels[channel].adpcm_step = 0;
nkeynes@736
   471
        audio.channels[channel].adpcm_predict = 0;
nkeynes@736
   472
        uint8_t data = ((uint8_t *)(arm_mem + audio.channels[channel].start))[0];
nkeynes@736
   473
        adpcm_yamaha_decode_nibble( &audio.channels[channel], data & 0x0F );
nkeynes@434
   474
    }
nkeynes@66
   475
}
.