Search
lxdream.org :: lxdream/src/aica/aica.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/aica/aica.c
changeset 929:fd8cb0c82f5f
prev829:517425d04f1b
next934:3acd3b3ee6d1
author nkeynes
date Tue Dec 23 05:48:05 2008 +0000 (15 years ago)
branchlxdream-mem
permissions -rw-r--r--
last change More refactoring and general cleanup. Most things should be working again now.
Split off cache and start real implementation, breaking save states in the process
file annotate diff log raw
nkeynes@11
     1
/**
nkeynes@561
     2
 * $Id$
nkeynes@11
     3
 * 
nkeynes@465
     4
 * This module implements the AICA's IO interfaces, as well
nkeynes@465
     5
 * as providing the core AICA module to the system.
nkeynes@11
     6
 *
nkeynes@11
     7
 * Copyright (c) 2005 Nathan Keynes.
nkeynes@11
     8
 *
nkeynes@11
     9
 * This program is free software; you can redistribute it and/or modify
nkeynes@11
    10
 * it under the terms of the GNU General Public License as published by
nkeynes@11
    11
 * the Free Software Foundation; either version 2 of the License, or
nkeynes@11
    12
 * (at your option) any later version.
nkeynes@11
    13
 *
nkeynes@11
    14
 * This program is distributed in the hope that it will be useful,
nkeynes@11
    15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
nkeynes@11
    16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
nkeynes@11
    17
 * GNU General Public License for more details.
nkeynes@11
    18
 */
nkeynes@11
    19
nkeynes@35
    20
#define MODULE aica_module
nkeynes@35
    21
nkeynes@131
    22
#include <time.h>
nkeynes@11
    23
#include "dream.h"
nkeynes@66
    24
#include "dreamcast.h"
nkeynes@15
    25
#include "mem.h"
nkeynes@106
    26
#include "aica/aica.h"
nkeynes@61
    27
#include "armcore.h"
nkeynes@106
    28
#include "aica/audio.h"
nkeynes@11
    29
#define MMIO_IMPL
nkeynes@11
    30
#include "aica.h"
nkeynes@11
    31
nkeynes@11
    32
MMIO_REGION_READ_DEFFN( AICA0 )
nkeynes@11
    33
MMIO_REGION_READ_DEFFN( AICA1 )
nkeynes@11
    34
nkeynes@23
    35
void aica_init( void );
nkeynes@23
    36
void aica_reset( void );
nkeynes@23
    37
void aica_start( void );
nkeynes@23
    38
void aica_stop( void );
nkeynes@35
    39
void aica_save_state( FILE *f );
nkeynes@35
    40
int aica_load_state( FILE *f );
nkeynes@30
    41
uint32_t aica_run_slice( uint32_t );
nkeynes@23
    42
nkeynes@23
    43
struct dreamcast_module aica_module = { "AICA", aica_init, aica_reset, 
nkeynes@736
    44
        aica_start, aica_run_slice, aica_stop,
nkeynes@736
    45
        aica_save_state, aica_load_state };
nkeynes@15
    46
nkeynes@465
    47
struct aica_state_struct {
nkeynes@465
    48
    uint32_t time_of_day;
nkeynes@465
    49
    /**
nkeynes@465
    50
     * Keep track of what we've done so far this second, to try to keep the
nkeynes@465
    51
     * precision of samples/second.
nkeynes@465
    52
     */
nkeynes@465
    53
    uint32_t samples_done;
nkeynes@465
    54
    uint32_t nanosecs_done;
nkeynes@465
    55
    /**
nkeynes@465
    56
     * Event (IRQ) state
nkeynes@465
    57
     */
nkeynes@465
    58
    int event_pending;
nkeynes@465
    59
    int clear_count;
nkeynes@465
    60
};
nkeynes@465
    61
nkeynes@465
    62
static struct aica_state_struct aica_state;
nkeynes@465
    63
nkeynes@173
    64
nkeynes@11
    65
/**
nkeynes@11
    66
 * Initialize the AICA subsystem. Note requires that 
nkeynes@11
    67
 */
nkeynes@11
    68
void aica_init( void )
nkeynes@11
    69
{
nkeynes@11
    70
    register_io_regions( mmio_list_spu );
nkeynes@11
    71
    MMIO_NOTRACE(AICA0);
nkeynes@11
    72
    MMIO_NOTRACE(AICA1);
nkeynes@11
    73
    arm_mem_init();
nkeynes@66
    74
    aica_reset();
nkeynes@11
    75
}
nkeynes@11
    76
nkeynes@11
    77
void aica_reset( void )
nkeynes@11
    78
{
nkeynes@35
    79
    arm_reset();
nkeynes@465
    80
    aica_state.time_of_day = 0x5bfc8900;
nkeynes@465
    81
    aica_state.samples_done = 0;
nkeynes@465
    82
    aica_state.nanosecs_done = 0;
nkeynes@465
    83
    aica_state.event_pending = 0;
nkeynes@465
    84
    aica_state.clear_count = 0;
nkeynes@736
    85
    //    aica_event(2); /* Pre-deliver a timer interrupt */
nkeynes@11
    86
}
nkeynes@11
    87
nkeynes@23
    88
void aica_start( void )
nkeynes@23
    89
{
nkeynes@23
    90
nkeynes@23
    91
}
nkeynes@23
    92
nkeynes@30
    93
uint32_t aica_run_slice( uint32_t nanosecs )
nkeynes@23
    94
{
nkeynes@23
    95
    /* Run arm instructions */
nkeynes@35
    96
    int reset = MMIO_READ( AICA2, AICA_RESET );
nkeynes@66
    97
    if( (reset & 1) == 0 ) { /* Running */
nkeynes@736
    98
        int num_samples = (int)((uint64_t)AICA_SAMPLE_RATE * (aica_state.nanosecs_done + nanosecs) / 1000000000) - aica_state.samples_done;
nkeynes@736
    99
        num_samples = arm_run_slice( num_samples );
nkeynes@736
   100
        audio_mix_samples( num_samples );
nkeynes@73
   101
nkeynes@736
   102
        aica_state.samples_done += num_samples;
nkeynes@736
   103
        aica_state.nanosecs_done += nanosecs;
nkeynes@35
   104
    }
nkeynes@465
   105
    if( aica_state.nanosecs_done > 1000000000 ) {
nkeynes@736
   106
        aica_state.samples_done -= AICA_SAMPLE_RATE;
nkeynes@736
   107
        aica_state.nanosecs_done -= 1000000000;
nkeynes@736
   108
        aica_state.time_of_day++;
nkeynes@73
   109
    }
nkeynes@43
   110
    return nanosecs;
nkeynes@23
   111
}
nkeynes@23
   112
nkeynes@23
   113
void aica_stop( void )
nkeynes@23
   114
{
nkeynes@23
   115
nkeynes@23
   116
}
nkeynes@23
   117
nkeynes@35
   118
void aica_save_state( FILE *f )
nkeynes@35
   119
{
nkeynes@465
   120
    fwrite( &aica_state, sizeof(struct aica_state_struct), 1, f );
nkeynes@35
   121
    arm_save_state( f );
nkeynes@465
   122
    audio_save_state(f);
nkeynes@35
   123
}
nkeynes@35
   124
nkeynes@35
   125
int aica_load_state( FILE *f )
nkeynes@35
   126
{
nkeynes@465
   127
    fread( &aica_state, sizeof(struct aica_state_struct), 1, f );
nkeynes@465
   128
    arm_load_state( f );
nkeynes@465
   129
    return audio_load_state(f);
nkeynes@35
   130
}
nkeynes@35
   131
nkeynes@61
   132
/* Note: This is probably not necessarily technically correct but it should
nkeynes@61
   133
 * work in the meantime.
nkeynes@61
   134
 */
nkeynes@61
   135
nkeynes@61
   136
void aica_event( int event )
nkeynes@61
   137
{
nkeynes@465
   138
    if( aica_state.event_pending == 0 )
nkeynes@736
   139
        armr.int_pending |= CPSR_F;
nkeynes@465
   140
    aica_state.event_pending |= (1<<event);
nkeynes@736
   141
nkeynes@61
   142
    int pending = MMIO_READ( AICA2, AICA_IRQ );
nkeynes@61
   143
    if( pending == 0 || event < pending )
nkeynes@736
   144
        MMIO_WRITE( AICA2, AICA_IRQ, event );
nkeynes@61
   145
}
nkeynes@61
   146
nkeynes@61
   147
void aica_clear_event( )
nkeynes@61
   148
{
nkeynes@465
   149
    aica_state.clear_count++;
nkeynes@465
   150
    if( aica_state.clear_count == 4 ) {
nkeynes@736
   151
        int i;
nkeynes@736
   152
        aica_state.clear_count = 0;
nkeynes@61
   153
nkeynes@736
   154
        for( i=0; i<8; i++ ) {
nkeynes@736
   155
            if( aica_state.event_pending & (1<<i) ) {
nkeynes@736
   156
                aica_state.event_pending &= ~(1<<i);
nkeynes@736
   157
                break;
nkeynes@736
   158
            }
nkeynes@736
   159
        }
nkeynes@736
   160
        for( ;i<8; i++ ) {
nkeynes@736
   161
            if( aica_state.event_pending & (1<<i) ) {
nkeynes@736
   162
                MMIO_WRITE( AICA2, AICA_IRQ, i );
nkeynes@736
   163
                break;
nkeynes@736
   164
            }
nkeynes@736
   165
        }
nkeynes@736
   166
        if( aica_state.event_pending == 0 )
nkeynes@736
   167
            armr.int_pending &= ~CPSR_F;
nkeynes@61
   168
    }
nkeynes@61
   169
}
nkeynes@66
   170
nkeynes@86
   171
void aica_enable( void )
nkeynes@86
   172
{
nkeynes@86
   173
    mmio_region_AICA2_write( AICA_RESET, MMIO_READ(AICA2,AICA_RESET) & ~1 );
nkeynes@86
   174
}
nkeynes@86
   175
nkeynes@11
   176
/** Channel register structure:
nkeynes@43
   177
 * 00  4  Channel config
nkeynes@43
   178
 * 04  4  Waveform address lo (16 bits)
nkeynes@11
   179
 * 08  4  Loop start address
nkeynes@11
   180
 * 0C  4  Loop end address
nkeynes@11
   181
 * 10  4  Volume envelope
nkeynes@43
   182
 * 14  4  Init to 0x1F
nkeynes@43
   183
 * 18  4  Frequency (floating point)
nkeynes@43
   184
 * 1C  4  ?? 
nkeynes@43
   185
 * 20  4  ??
nkeynes@11
   186
 * 24  1  Pan
nkeynes@11
   187
 * 25  1  ??
nkeynes@11
   188
 * 26  
nkeynes@11
   189
 * 27  
nkeynes@11
   190
 * 28  1  ??
nkeynes@11
   191
 * 29  1  Volume
nkeynes@11
   192
 * 2C
nkeynes@11
   193
 * 30
nkeynes@431
   194
 */
nkeynes@11
   195
nkeynes@11
   196
/* Write to channels 0-31 */
nkeynes@929
   197
MMIO_REGION_WRITE_FN( AICA0, reg, val )
nkeynes@11
   198
{
nkeynes@929
   199
    reg &= 0xFFF;
nkeynes@35
   200
    MMIO_WRITE( AICA0, reg, val );
nkeynes@66
   201
    aica_write_channel( reg >> 7, reg % 128, val );
nkeynes@37
   202
    //    DEBUG( "AICA0 Write %08X => %08X", val, reg );
nkeynes@11
   203
}
nkeynes@11
   204
nkeynes@11
   205
/* Write to channels 32-64 */
nkeynes@929
   206
MMIO_REGION_WRITE_FN( AICA1, reg, val )
nkeynes@11
   207
{
nkeynes@929
   208
    reg &= 0xFFF;
nkeynes@35
   209
    MMIO_WRITE( AICA1, reg, val );
nkeynes@66
   210
    aica_write_channel( (reg >> 7) + 32, reg % 128, val );
nkeynes@37
   211
    // DEBUG( "AICA1 Write %08X => %08X", val, reg );
nkeynes@11
   212
}
nkeynes@11
   213
nkeynes@66
   214
/**
nkeynes@66
   215
 * AICA control registers 
nkeynes@66
   216
 */
nkeynes@929
   217
MMIO_REGION_WRITE_FN( AICA2, reg, val )
nkeynes@11
   218
{
nkeynes@35
   219
    uint32_t tmp;
nkeynes@929
   220
    reg &= 0xFFF;
nkeynes@929
   221
    
nkeynes@35
   222
    switch( reg ) {
nkeynes@35
   223
    case AICA_RESET:
nkeynes@736
   224
        tmp = MMIO_READ( AICA2, AICA_RESET );
nkeynes@736
   225
        if( (tmp & 1) == 1 && (val & 1) == 0 ) {
nkeynes@736
   226
            /* ARM enabled - execute a core reset */
nkeynes@736
   227
            DEBUG( "ARM enabled" );
nkeynes@736
   228
            arm_reset();
nkeynes@736
   229
            aica_state.samples_done = 0;
nkeynes@736
   230
            aica_state.nanosecs_done = 0;
nkeynes@736
   231
        } else if( (tmp&1) == 0 && (val&1) == 1 ) {
nkeynes@736
   232
            DEBUG( "ARM disabled" );
nkeynes@736
   233
        }
nkeynes@736
   234
        MMIO_WRITE( AICA2, AICA_RESET, val );
nkeynes@736
   235
        break;
nkeynes@61
   236
    case AICA_IRQCLEAR:
nkeynes@736
   237
        aica_clear_event();
nkeynes@736
   238
        break;
nkeynes@829
   239
    case AICA_FIFOIN: /* Read-only */
nkeynes@829
   240
        break;
nkeynes@35
   241
    default:
nkeynes@736
   242
        MMIO_WRITE( AICA2, reg, val );
nkeynes@736
   243
        break;
nkeynes@35
   244
    }
nkeynes@11
   245
}
nkeynes@66
   246
nkeynes@929
   247
MMIO_REGION_READ_FN( AICA2, reg )
nkeynes@463
   248
{
nkeynes@463
   249
    audio_channel_t channel;
nkeynes@463
   250
    uint32_t channo;
nkeynes@463
   251
    int32_t val;
nkeynes@929
   252
    reg &= 0xFFF;
nkeynes@463
   253
    switch( reg ) {
nkeynes@463
   254
    case AICA_CHANSTATE:
nkeynes@736
   255
        channo = (MMIO_READ( AICA2, AICA_CHANSEL ) >> 8) & 0x3F;
nkeynes@736
   256
        channel = audio_get_channel(channo);
nkeynes@736
   257
        if( channel->loop == LOOP_LOOPED ) {
nkeynes@736
   258
            val = 0x8000;
nkeynes@736
   259
            channel->loop = LOOP_ON;
nkeynes@736
   260
        } else {
nkeynes@736
   261
            val = 0;
nkeynes@736
   262
        }
nkeynes@736
   263
        return val;
nkeynes@463
   264
    case AICA_CHANPOSN:
nkeynes@736
   265
        channo = (MMIO_READ( AICA2, AICA_CHANSEL ) >> 8) & 0x3F;
nkeynes@736
   266
        channel = audio_get_channel(channo);
nkeynes@736
   267
        return channel->posn;
nkeynes@463
   268
    default:
nkeynes@736
   269
        return MMIO_READ( AICA2, reg );
nkeynes@463
   270
    }
nkeynes@463
   271
}
nkeynes@131
   272
nkeynes@929
   273
MMIO_REGION_READ_FN( AICARTC, reg )
nkeynes@131
   274
{
nkeynes@173
   275
    int32_t rv = 0;
nkeynes@929
   276
    reg &= 0xFFF;
nkeynes@131
   277
    switch( reg ) {
nkeynes@131
   278
    case AICA_RTCHI:
nkeynes@465
   279
        rv = (aica_state.time_of_day >> 16) & 0xFFFF;
nkeynes@736
   280
        break;
nkeynes@131
   281
    case AICA_RTCLO:
nkeynes@736
   282
        rv = aica_state.time_of_day & 0xFFFF;
nkeynes@736
   283
        break;
nkeynes@131
   284
    }
nkeynes@241
   285
    // DEBUG( "Read AICA RTC %d => %08X", reg, rv );
nkeynes@173
   286
    return rv;
nkeynes@131
   287
}
nkeynes@131
   288
nkeynes@929
   289
MMIO_REGION_WRITE_FN( AICARTC, reg, val )
nkeynes@301
   290
{
nkeynes@929
   291
    reg &= 0xFFF;
nkeynes@301
   292
    switch( reg ) {
nkeynes@301
   293
    case AICA_RTCEN:
nkeynes@736
   294
        MMIO_WRITE( AICARTC, reg, val&0x01 );
nkeynes@736
   295
        break;
nkeynes@301
   296
    case AICA_RTCLO:
nkeynes@736
   297
        if( MMIO_READ( AICARTC, AICA_RTCEN ) & 0x01 ) {
nkeynes@736
   298
            aica_state.time_of_day = (aica_state.time_of_day & 0xFFFF0000) | (val & 0xFFFF);
nkeynes@736
   299
        }
nkeynes@736
   300
        break;
nkeynes@301
   301
    case AICA_RTCHI:
nkeynes@736
   302
        if( MMIO_READ( AICARTC, AICA_RTCEN ) & 0x01 ) {
nkeynes@736
   303
            aica_state.time_of_day = (aica_state.time_of_day & 0xFFFF) | (val<<16);
nkeynes@736
   304
            MMIO_WRITE( AICARTC, AICA_RTCEN, 0 );
nkeynes@736
   305
        }
nkeynes@736
   306
        break;
nkeynes@301
   307
    }
nkeynes@301
   308
}
nkeynes@736
   309
nkeynes@66
   310
/**
nkeynes@66
   311
 * Translate the channel frequency to a sample rate. The frequency is a
nkeynes@66
   312
 * 14-bit floating point number, where bits 0..9 is the mantissa,
nkeynes@66
   313
 * 11..14 is the signed exponent (-8 to +7). Bit 10 appears to
nkeynes@66
   314
 * be unused.
nkeynes@66
   315
 *
nkeynes@66
   316
 * @return sample rate in samples per second.
nkeynes@66
   317
 */
nkeynes@66
   318
uint32_t aica_frequency_to_sample_rate( uint32_t freq )
nkeynes@66
   319
{
nkeynes@66
   320
    uint32_t exponent = (freq & 0x3800) >> 11;
nkeynes@66
   321
    uint32_t mantissa = freq & 0x03FF;
nkeynes@82
   322
    uint32_t rate;
nkeynes@66
   323
    if( freq & 0x4000 ) {
nkeynes@736
   324
        /* neg exponent - rate < 44100 */
nkeynes@736
   325
        exponent = 8 - exponent;
nkeynes@736
   326
        rate = (44100 >> exponent) +
nkeynes@736
   327
        ((44100 * mantissa) >> (10+exponent));
nkeynes@66
   328
    } else {
nkeynes@736
   329
        /* pos exponent - rate > 44100 */
nkeynes@736
   330
        rate = (44100 << exponent) +
nkeynes@736
   331
        ((44100 * mantissa) >> (10-exponent));
nkeynes@66
   332
    }
nkeynes@82
   333
    return rate;
nkeynes@66
   334
}
nkeynes@66
   335
nkeynes@434
   336
void aica_start_stop_channels()
nkeynes@434
   337
{
nkeynes@434
   338
    int i;
nkeynes@434
   339
    for( i=0; i<32; i++ ) {
nkeynes@736
   340
        uint32_t val = MMIO_READ( AICA0, i<<7 );
nkeynes@736
   341
        audio_start_stop_channel(i, val&0x4000);
nkeynes@434
   342
    }
nkeynes@434
   343
    for( ; i<64; i++ ) {
nkeynes@736
   344
        uint32_t val = MMIO_READ( AICA1, (i-32)<<7 );
nkeynes@736
   345
        audio_start_stop_channel(i, val&0x4000);
nkeynes@434
   346
    }
nkeynes@434
   347
}
nkeynes@434
   348
nkeynes@82
   349
/**
nkeynes@82
   350
 * Derived directly from Dan Potter's log table
nkeynes@82
   351
 */
nkeynes@82
   352
uint8_t aica_volume_table[256] = {
nkeynes@736
   353
        0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   1,
nkeynes@736
   354
        1,   1,   1,   1,   1,   1,   2,   2,   2,   2,   2,   3,   3,   3,   3,   4,
nkeynes@736
   355
        4,   4,   4,   5,   5,   5,   5,   6,   6,   6,   7,   7,   7,   8,   8,   9,
nkeynes@736
   356
        9,   9,  10,  10,  11,  11,  11,  12,  12,  13,  13,  14,  14,  15,  15,  16,
nkeynes@736
   357
        16,  17,  17,  18,  18,  19,  19,  20,  20,  21,  22,  22,  23,  23,  24,  25,
nkeynes@736
   358
        25,  26,  27,  27,  28,  29,  29,  30,  31,  31,  32,  33,  34,  34,  35,  36,
nkeynes@736
   359
        37,  37,  38,  39,  40,  40,  41,  42,  43,  44,  45,  45,  46,  47,  48,  49,
nkeynes@736
   360
        50,  51,  52,  52,  53,  54,  55,  56,  57,  58,  59,  60,  61,  62,  63,  64,
nkeynes@736
   361
        65,  66,  67,  68,  69,  70,  71,  72,  73,  74,  76,  77,  78,  79,  80,  81,
nkeynes@736
   362
        82,  83,  85,  86,  87,  88,  89,  90,  92,  93,  94,  95,  97,  98,  99, 100,
nkeynes@736
   363
        102, 103, 104, 105, 107, 108, 109, 111, 112, 113, 115, 116, 117, 119, 120, 121,
nkeynes@736
   364
        123, 124, 126, 127, 128, 130, 131, 133, 134, 136, 137, 139, 140, 142, 143, 145,
nkeynes@736
   365
        146, 148, 149, 151, 152, 154, 155, 157, 159, 160, 162, 163, 165, 167, 168, 170,
nkeynes@736
   366
        171, 173, 175, 176, 178, 180, 181, 183, 185, 187, 188, 190, 192, 194, 195, 197,
nkeynes@736
   367
        199, 201, 202, 204, 206, 208, 210, 211, 213, 215, 217, 219, 221, 223, 224, 226,
nkeynes@736
   368
        228, 230, 232, 234, 236, 238, 240, 242, 244, 246, 248, 250, 252, 253, 254, 255 };
nkeynes@82
   369
nkeynes@82
   370
nkeynes@66
   371
void aica_write_channel( int channelNo, uint32_t reg, uint32_t val ) 
nkeynes@66
   372
{
nkeynes@66
   373
    val &= 0x0000FFFF;
nkeynes@66
   374
    audio_channel_t channel = audio_get_channel(channelNo);
nkeynes@66
   375
    switch( reg ) {
nkeynes@66
   376
    case 0x00: /* Config + high address bits*/
nkeynes@736
   377
        channel->start = (channel->start & 0xFFFF) | ((val&0x1F) << 16);
nkeynes@736
   378
        if( val & 0x200 ) 
nkeynes@736
   379
            channel->loop = LOOP_ON;
nkeynes@736
   380
        else 
nkeynes@736
   381
            channel->loop = LOOP_OFF;
nkeynes@736
   382
        switch( (val >> 7) & 0x03 ) {
nkeynes@736
   383
        case 0:
nkeynes@736
   384
            channel->sample_format = AUDIO_FMT_16BIT;
nkeynes@736
   385
            break;
nkeynes@736
   386
        case 1:
nkeynes@736
   387
            channel->sample_format = AUDIO_FMT_8BIT;
nkeynes@736
   388
            break;
nkeynes@736
   389
        case 2:
nkeynes@736
   390
        case 3:
nkeynes@736
   391
            channel->sample_format = AUDIO_FMT_ADPCM;
nkeynes@736
   392
            break;
nkeynes@736
   393
        }
nkeynes@736
   394
        if( val & 0x8000 ) {
nkeynes@736
   395
            aica_start_stop_channels();
nkeynes@736
   396
        }
nkeynes@736
   397
        break;
nkeynes@736
   398
        case 0x04: /* Low 16 address bits */
nkeynes@736
   399
            channel->start = (channel->start & 0x001F0000) | val;
nkeynes@736
   400
            break;
nkeynes@736
   401
        case 0x08: /* Loop start */
nkeynes@736
   402
            channel->loop_start = val;
nkeynes@736
   403
            break;
nkeynes@736
   404
        case 0x0C: /* End */
nkeynes@736
   405
            channel->end = val;
nkeynes@736
   406
            break;
nkeynes@736
   407
        case 0x10: /* Envelope register 1 */
nkeynes@736
   408
            break;
nkeynes@736
   409
        case 0x14: /* Envelope register 2 */
nkeynes@736
   410
            break;
nkeynes@736
   411
        case 0x18: /* Frequency */
nkeynes@736
   412
            channel->sample_rate = aica_frequency_to_sample_rate ( val );
nkeynes@736
   413
            break;
nkeynes@736
   414
        case 0x1C: /* ??? */
nkeynes@736
   415
        case 0x20: /* ??? */
nkeynes@736
   416
        case 0x24: /* Volume? /pan */
nkeynes@736
   417
            val = val & 0x1F;
nkeynes@736
   418
            if( val <= 0x0F ) 
nkeynes@736
   419
                val = 0x0F - val; /* Convert to smooth pan over 0..31 */
nkeynes@736
   420
            channel->pan = val;
nkeynes@736
   421
            break;
nkeynes@736
   422
        case 0x28: /* Volume */
nkeynes@736
   423
            // This isn't remotely correct, but it will have to suffice until I have
nkeynes@736
   424
            // time to figure out what's actually going on here... 
nkeynes@736
   425
            channel->vol = aica_volume_table[max((val & 0xFF),((val>>8)&0xFF))];
nkeynes@736
   426
            break;
nkeynes@736
   427
        default: /* ??? */
nkeynes@736
   428
            break;
nkeynes@66
   429
    }
nkeynes@66
   430
nkeynes@66
   431
}
.