PCem

changeset 13:2d237b9ded0f

SB AWE32 emulation.
author TomW
date Tue Jul 23 22:04:17 2013 +0100
parents a87be069d268
children 7dbba9693027
files src/Makefile.mingw src/sound.c src/sound_emu8k.c src/sound_emu8k.h src/sound_sb.c src/sound_sb.h
diffstat 6 files changed, 814 insertions(+), 2 deletions(-) [+]
line diff
     1.1 --- a/src/Makefile.mingw	Sat Jul 20 13:42:31 2013 +0100
     1.2 +++ b/src/Makefile.mingw	Tue Jul 23 22:04:17 2013 +0100
     1.3 @@ -8,8 +8,8 @@
     1.4  	headland.o i430vx.o ide.o io.o jim.o keyboard.o keyboard_amstrad.o keyboard_at.o \
     1.5  	keyboard_olim24.o keyboard_xt.o lpt.o mcr.o mem.o model.o \
     1.6  	mouse.o mouse_ps2.o mouse_serial.o neat.o nvr.o olivetti_m24.o \
     1.7 -     opti.o pc.o pci.o pic.o piix.o pit.o ppi.o serial.o sound.o sound_adlib.o \
     1.8 -	sound_adlibgold.o sound_cms.o sound_gus.o sound_mpu401_uart.o sound_opl.o \
     1.9 +     opti.o pc.o pci.o pic.o piix.o pit.o ppi.o serial.o sis496.o sound.o sound_adlib.o \
    1.10 +	sound_adlibgold.o sound_cms.o sound_emu8k.o sound_gus.o sound_mpu401_uart.o sound_opl.o \
    1.11  	sound_pas16.o sound_sb.o sound_sb_dsp.o sound_sn76489.o sound_speaker.o \
    1.12  	sound_wss.o soundopenal.o timer.o um8881f.o um8669f.o vid_ati_eeprom.o \
    1.13  	vid_ati_mach64.o vid_ati18800.o vid_ati28800.o vid_ati68860_ramdac.o vid_cga.o \
     2.1 --- a/src/sound.c	Sat Jul 20 13:42:31 2013 +0100
     2.2 +++ b/src/sound.c	Tue Jul 23 22:04:17 2013 +0100
     2.3 @@ -36,6 +36,7 @@
     2.4          {"Sound Blaster Pro v1",  &sb_pro_v1_device},
     2.5          {"Sound Blaster Pro v2",  &sb_pro_v1_device},
     2.6          {"Sound Blaster 16",      &sb_16_device},
     2.7 +        {"Sound Blaster AWE32",   &sb_awe32_device},
     2.8          {"Adlib Gold",            &adgold_device},
     2.9          {"Windows Sound System",  &wss_device},        
    2.10          {"Pro Audio Spectrum 16", &pas16_device},
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/src/sound_emu8k.c	Tue Jul 23 22:04:17 2013 +0100
     3.3 @@ -0,0 +1,668 @@
     3.4 +/*12log2(r) * 4096
     3.5 +
     3.6 +  freq = 2^((in - 0xe000) / 4096)*/
     3.7 +/*LFO - lowest (0.042 Hz) = 2^20 steps = 1048576
     3.8 +        highest (10.72 Hz) = 2^12 steps = 4096*/
     3.9 +#include <stdlib.h>
    3.10 +#include <math.h>
    3.11 +#include "ibm.h"
    3.12 +#include "device.h"
    3.13 +#include "sound.h"
    3.14 +#include "sound_emu8k.h"
    3.15 +#include "timer.h"
    3.16 +
    3.17 +enum
    3.18 +{
    3.19 +        ENV_STOPPED = 0,
    3.20 +        ENV_ATTACK  = 1,
    3.21 +        ENV_DECAY   = 2,
    3.22 +        ENV_SUSTAIN = 3,
    3.23 +        ENV_RELEASE = 4
    3.24 +};
    3.25 +
    3.26 +static int64_t freqtable[65536];
    3.27 +static int attentable[256];
    3.28 +static int envtable[4096];
    3.29 +static int lfotable[4096];
    3.30 +
    3.31 +static int32_t filt_w0[256];
    3.32 +/*static float filt_w0[256];*/
    3.33 +
    3.34 +#define READ16(addr, var)       switch ((addr) & 2)                                     \
    3.35 +                                {                                                       \
    3.36 +                                        case 0: ret = (var) & 0xffff;         break;    \
    3.37 +                                        case 2: ret = ((var) >> 16) & 0xffff; break;    \
    3.38 +                                }
    3.39 +                                
    3.40 +#define WRITE16(addr, var, val) switch ((addr) & 2)                                               \
    3.41 +                                {                                                                 \
    3.42 +                                        case 0: var = (var & 0xffff0000) | (val);         break;  \
    3.43 +                                        case 2: var = (var & 0x0000ffff) | ((val) << 16); break;  \
    3.44 +                                }
    3.45 +
    3.46 +static inline int16_t EMU8K_READ(emu8k_t *emu8k, uint32_t addr)
    3.47 +{
    3.48 +        addr &= 0xffffff;
    3.49 +        if (addr < 0x80000)
    3.50 +                return emu8k->rom[addr];
    3.51 +        if (addr < 0x200000 || addr >= 0x240000)
    3.52 +                return 0;
    3.53 +        return emu8k->ram[addr & 0x3ffff];
    3.54 +}
    3.55 +
    3.56 +static inline int16_t EMU8K_READ_INTERP(emu8k_t *emu8k, uint32_t addr)
    3.57 +{
    3.58 +        int16_t dat1 = EMU8K_READ(emu8k, addr >> 8);
    3.59 +        int16_t dat2 = EMU8K_READ(emu8k, (addr >> 8) + 1);
    3.60 +        return ((dat1 * (0xff - (addr & 0xff))) + (dat2 * (addr & 0xff))) >> 8;
    3.61 +}
    3.62 +
    3.63 +static inline void EMU8K_WRITE(emu8k_t *emu8k, uint32_t addr, uint16_t val)
    3.64 +{
    3.65 +        addr &= 0xffffff;
    3.66 +        if (addr >= 0x200000 && addr <= 0x240000)
    3.67 +                emu8k->ram[addr & 0x3ffff] = val;
    3.68 +}
    3.69 +
    3.70 +uint16_t emu8k_inw(uint32_t addr, void *p)
    3.71 +{
    3.72 +        emu8k_t *emu8k = (emu8k_t *)p;
    3.73 +        uint16_t ret;
    3.74 +/*        pclog("emu8k_inw %04X  reg=%i voice=%i\n", addr, emu8k->cur_reg, emu8k->cur_voice);*/
    3.75 +        addr -= 0x220;
    3.76 +        switch (addr & 0xc02)
    3.77 +        {
    3.78 +                case 0x400: case 0x402: /*Data0*/
    3.79 +                switch (emu8k->cur_reg)
    3.80 +                {
    3.81 +                        case 0:
    3.82 +                        READ16(addr, emu8k->voice[emu8k->cur_voice].cpf);
    3.83 +                        return ret;
    3.84 +                        
    3.85 +                        case 1:
    3.86 +                        READ16(addr, emu8k->voice[emu8k->cur_voice].ptrx);
    3.87 +                        return ret;
    3.88 +                        
    3.89 +                        case 2:
    3.90 +                        READ16(addr, emu8k->voice[emu8k->cur_voice].cvcf);
    3.91 +                        return ret;
    3.92 +                        
    3.93 +                        case 3:
    3.94 +                        READ16(addr, emu8k->voice[emu8k->cur_voice].vtft);
    3.95 +                        return ret;
    3.96 +                        
    3.97 +                        case 4: case 5: /*???*/
    3.98 +                        return 0xffff;
    3.99 +                        
   3.100 +                        case 6:
   3.101 +                        READ16(addr, emu8k->voice[emu8k->cur_voice].psst);
   3.102 +                        return ret;
   3.103 +                                                
   3.104 +                        case 7:
   3.105 +                        READ16(addr, emu8k->voice[emu8k->cur_voice].cpf);
   3.106 +                        return ret;
   3.107 +                }
   3.108 +                break;
   3.109 +
   3.110 +                case 0x800: /*Data1*/
   3.111 +                switch (emu8k->cur_reg)
   3.112 +                {
   3.113 +                        case 0:
   3.114 +                        {
   3.115 +                                uint32_t val = (emu8k->voice[emu8k->cur_voice].ccca & 0xff000000) | (emu8k->voice[emu8k->cur_voice].addr >> 8);
   3.116 +                                READ16(addr, emu8k->voice[emu8k->cur_voice].ccca);
   3.117 +                                return ret;
   3.118 +                        }
   3.119 +
   3.120 +                        case 1:
   3.121 +                        switch (emu8k->cur_voice)
   3.122 +                        {
   3.123 +                                case 20:
   3.124 +                                READ16(addr, emu8k->smalr);
   3.125 +                                return ret;
   3.126 +                                case 21:
   3.127 +                                READ16(addr, emu8k->smarr);
   3.128 +                                return ret;
   3.129 +                                case 22:
   3.130 +                                READ16(addr, emu8k->smalw);
   3.131 +                                return ret;
   3.132 +                                case 23:
   3.133 +                                READ16(addr, emu8k->smarw);
   3.134 +                                return ret;
   3.135 +                                
   3.136 +                                case 26:
   3.137 +                                {
   3.138 +                                        uint16_t val = emu8k->smld_buffer;
   3.139 +                                        emu8k->smld_buffer = EMU8K_READ(emu8k, emu8k->smalr);
   3.140 +                                        emu8k->smalr++;
   3.141 +                                        return val;
   3.142 +                                }
   3.143 +
   3.144 +                                case 29: /*Configuration Word 1*/
   3.145 +                                return emu8k->hwcf1;
   3.146 +                                case 30: /*Configuration Word 2*/
   3.147 +                                return emu8k->hwcf2 | 3;
   3.148 +                                case 31: /*Configuration Word 3*/
   3.149 +                                return emu8k->hwcf3;
   3.150 +                        }
   3.151 +                        break;
   3.152 +
   3.153 +                        case 2: /*INIT1*/
   3.154 +                        case 3: /*INIT3*/
   3.155 +                        return 0xffff; /*Can we read anything useful from here?*/
   3.156 +                        
   3.157 +                        case 5:
   3.158 +                        return emu8k->voice[emu8k->cur_voice].dcysusv;
   3.159 +
   3.160 +                        case 7:
   3.161 +                        return emu8k->voice[emu8k->cur_voice].dcysus;
   3.162 +                }
   3.163 +                break;
   3.164 +
   3.165 +                case 0x802: /*Data2*/
   3.166 +                switch (emu8k->cur_reg)
   3.167 +                {
   3.168 +                        case 0:
   3.169 +                        {
   3.170 +                                uint32_t val = (emu8k->voice[emu8k->cur_voice].ccca & 0xff000000) | (emu8k->voice[emu8k->cur_voice].addr >> 8);
   3.171 +                                READ16(addr, emu8k->voice[emu8k->cur_voice].ccca);
   3.172 +                                return ret;
   3.173 +                        }
   3.174 +
   3.175 +                        case 1:
   3.176 +                        switch (emu8k->cur_voice)
   3.177 +                        {
   3.178 +                                case 20:
   3.179 +                                READ16(addr, emu8k->smalr);
   3.180 +                                return ret;
   3.181 +                                case 21:
   3.182 +                                READ16(addr, emu8k->smarr);
   3.183 +                                return ret;
   3.184 +                                case 22:
   3.185 +                                READ16(addr, emu8k->smalw);
   3.186 +                                return ret;
   3.187 +                                case 23:
   3.188 +                                READ16(addr, emu8k->smarw);
   3.189 +                                return ret;
   3.190 +                                
   3.191 +                                case 26:
   3.192 +                                {
   3.193 +                                        uint16_t val = emu8k->smrd_buffer;
   3.194 +                                        emu8k->smrd_buffer = EMU8K_READ(emu8k, emu8k->smarr);
   3.195 +                                        emu8k->smarr++;
   3.196 +                                        return val;
   3.197 +                                }
   3.198 +
   3.199 +                                case 27: /*Sample Counter*/
   3.200 +                                return emu8k->wc;
   3.201 +                        }
   3.202 +                        break;
   3.203 +
   3.204 +                        case 2: /*INIT2*/
   3.205 +                        case 3: /*INIT4*/
   3.206 +                        return 0xffff; /*Can we read anything useful from here?*/
   3.207 +                        
   3.208 +                        case 4:                        
   3.209 +                        return emu8k->voice[emu8k->cur_voice].atkhldv;
   3.210 +                }
   3.211 +                break;
   3.212 +                                
   3.213 +                case 0xc00: /*Data3*/
   3.214 +                switch (emu8k->cur_reg)
   3.215 +                {
   3.216 +                        case 0:
   3.217 +                        return emu8k->voice[emu8k->cur_voice].ip;
   3.218 +
   3.219 +                        case 1:
   3.220 +                        return emu8k->voice[emu8k->cur_voice].ifatn;
   3.221 +
   3.222 +                        case 2:
   3.223 +                        return emu8k->voice[emu8k->cur_voice].pefe;
   3.224 +
   3.225 +                        case 3:
   3.226 +                        return emu8k->voice[emu8k->cur_voice].fmmod;
   3.227 +
   3.228 +                        case 4:
   3.229 +                        return emu8k->voice[emu8k->cur_voice].tremfrq;
   3.230 +
   3.231 +                        case 5:
   3.232 +                        return emu8k->voice[emu8k->cur_voice].fm2frq2;
   3.233 +
   3.234 +                        case 6:
   3.235 +                        return 0xffff;
   3.236 +                        
   3.237 +                        case 7: /*ID?*/
   3.238 +                        return 0xc;
   3.239 +                }
   3.240 +                break;
   3.241 +                case 0xc02: /*Status - I think!*/
   3.242 +                emu8k->c02_read ^= 0x1000;
   3.243 +                return emu8k->c02_read;
   3.244 +        }
   3.245 +/*        fatal("Bad EMU8K inw from %08X\n", addr);*/
   3.246 +        return 0xffff;
   3.247 +}
   3.248 +
   3.249 +void emu8k_outw(uint32_t addr, uint16_t val, void *p)
   3.250 +{
   3.251 +        emu8k_t *emu8k = (emu8k_t *)p;
   3.252 +
   3.253 +/*        pclog("emu8k_outw : addr=%08X reg=%i voice=%i  val=%04X\n", addr, emu8k->cur_reg, emu8k->cur_voice, val);*/
   3.254 +        addr -= 0x220;
   3.255 +        switch (addr & 0xc02)
   3.256 +        {
   3.257 +                case 0x400: case 0x402: /*Data0*/
   3.258 +                switch (emu8k->cur_reg)
   3.259 +                {
   3.260 +                        case 0:
   3.261 +                        WRITE16(addr, emu8k->voice[emu8k->cur_voice].cpf, val);
   3.262 +                        return;
   3.263 +                        
   3.264 +                        case 1:
   3.265 +                        WRITE16(addr, emu8k->voice[emu8k->cur_voice].ptrx, val);
   3.266 +                        return;
   3.267 +                        
   3.268 +                        case 2:
   3.269 +                        WRITE16(addr, emu8k->voice[emu8k->cur_voice].cvcf, val);
   3.270 +                        return;
   3.271 +                        
   3.272 +                        case 3:
   3.273 +                        WRITE16(addr, emu8k->voice[emu8k->cur_voice].vtft, val);
   3.274 +                        return;
   3.275 +                        
   3.276 +                        case 6:
   3.277 +                        WRITE16(addr, emu8k->voice[emu8k->cur_voice].psst, val);
   3.278 +                        emu8k->voice[emu8k->cur_voice].loop_start = (uint64_t)(emu8k->voice[emu8k->cur_voice].psst & 0xffffff) << 32;
   3.279 +                        if (addr & 2)
   3.280 +                        {
   3.281 +                                emu8k->voice[emu8k->cur_voice].vol_l = val >> 8;
   3.282 +                                emu8k->voice[emu8k->cur_voice].vol_r = 255 - (val >> 8);
   3.283 +                        }
   3.284 +/*                        pclog("emu8k_outl : write PSST %08X l %i r %i\n", emu8k->voice[emu8k->cur_voice].psst, emu8k->voice[emu8k->cur_voice].vol_l, emu8k->voice[emu8k->cur_voice].vol_r);*/
   3.285 +                        return;
   3.286 +                        
   3.287 +                        case 7:
   3.288 +                        WRITE16(addr, emu8k->voice[emu8k->cur_voice].cpf, val);
   3.289 +                        emu8k->voice[emu8k->cur_voice].loop_end = (uint64_t)(emu8k->voice[emu8k->cur_voice].cpf & 0xffffff) << 32;
   3.290 +/*                        pclog("emu8k_outl : write CPF %08X\n", emu8k->voice[emu8k->cur_voice].cpf);*/
   3.291 +                        return;
   3.292 +                }
   3.293 +                break;
   3.294 +
   3.295 +                case 0x800: /*Data1*/
   3.296 +                switch (emu8k->cur_reg)
   3.297 +                {
   3.298 +                        case 0:
   3.299 +                        WRITE16(addr, emu8k->voice[emu8k->cur_voice].ccca, val);
   3.300 +                        emu8k->voice[emu8k->cur_voice].addr = (uint64_t)(emu8k->voice[emu8k->cur_voice].ccca & 0xffffff) << 32;
   3.301 +/*                        pclog("emu8k_outl : write CCCA %08X\n", emu8k->voice[emu8k->cur_voice].ccca);*/
   3.302 +                        return;
   3.303 +
   3.304 +                        case 1:
   3.305 +                        switch (emu8k->cur_voice)
   3.306 +                        {
   3.307 +                                case 20:
   3.308 +                                WRITE16(addr, emu8k->smalr, val);
   3.309 +                                return;
   3.310 +                                case 21:
   3.311 +                                WRITE16(addr, emu8k->smarr, val);
   3.312 +                                return;
   3.313 +                                case 22:
   3.314 +                                WRITE16(addr, emu8k->smalw, val);
   3.315 +                                return;
   3.316 +                                case 23:
   3.317 +                                WRITE16(addr, emu8k->smarw, val);
   3.318 +                                return;
   3.319 +                                
   3.320 +                                case 26:
   3.321 +                                EMU8K_WRITE(emu8k, emu8k->smalw, val);
   3.322 +                                emu8k->smalw++;
   3.323 +                                break;
   3.324 +
   3.325 +                                case 29: /*Configuration Word 1*/
   3.326 +                                emu8k->hwcf1 = val;
   3.327 +                                return;
   3.328 +                                case 30: /*Configuration Word 2*/
   3.329 +                                emu8k->hwcf2 = val;
   3.330 +                                return;
   3.331 +                                case 31: /*Configuration Word 3*/
   3.332 +                                emu8k->hwcf3 = val;
   3.333 +                                return;
   3.334 +                        }
   3.335 +                        break;
   3.336 +
   3.337 +                        case 5:
   3.338 +/*                        pclog("emu8k_outw : write DCYSUSV %04X\n", val);*/
   3.339 +                        emu8k->voice[emu8k->cur_voice].dcysusv = val;
   3.340 +                        emu8k->voice[emu8k->cur_voice].env_sustain = (((val >> 8) & 0x7f) << 5) << 9;
   3.341 +                        if (val & 0x8000) /*Release*/
   3.342 +                        {
   3.343 +                                emu8k->voice[emu8k->cur_voice].env_state = ENV_RELEASE;
   3.344 +                                emu8k->voice[emu8k->cur_voice].env_release = val & 0x7f;
   3.345 +                        }
   3.346 +                        else    /*Decay*/
   3.347 +                                emu8k->voice[emu8k->cur_voice].env_decay = val & 0x7f;
   3.348 +                        if (val & 0x80)
   3.349 +                                emu8k->voice[emu8k->cur_voice].env_state = ENV_STOPPED;
   3.350 +                        return;
   3.351 +
   3.352 +                        case 7:
   3.353 +/*                        pclog("emu8k_outw : write DCYSUS %04X\n", val);*/
   3.354 +                        emu8k->voice[emu8k->cur_voice].dcysus = val;
   3.355 +                        emu8k->voice[emu8k->cur_voice].menv_sustain = (((val >> 8) & 0x7f) << 5) << 9;
   3.356 +                        if (val & 0x8000) /*Release*/
   3.357 +                        {
   3.358 +                                emu8k->voice[emu8k->cur_voice].menv_state = ENV_RELEASE;
   3.359 +                                emu8k->voice[emu8k->cur_voice].menv_release = val & 0x7f;
   3.360 +                        }
   3.361 +                        else    /*Decay*/
   3.362 +                                emu8k->voice[emu8k->cur_voice].menv_decay = val & 0x7f;
   3.363 +                        if (val & 0x80)
   3.364 +                                emu8k->voice[emu8k->cur_voice].menv_state = ENV_STOPPED;
   3.365 +                        return;
   3.366 +                }
   3.367 +                break;
   3.368 +                
   3.369 +                case 0x802: /*Data2*/
   3.370 +                switch (emu8k->cur_reg)
   3.371 +                {
   3.372 +                        case 0:
   3.373 +                        {
   3.374 +                                float q;
   3.375 +                                
   3.376 +                                WRITE16(addr, emu8k->voice[emu8k->cur_voice].ccca, val);
   3.377 +                                emu8k->voice[emu8k->cur_voice].addr = (uint64_t)(emu8k->voice[emu8k->cur_voice].ccca & 0xffffff) << 32;
   3.378 +
   3.379 +                                q = (float)(emu8k->voice[emu8k->cur_voice].ccca >> 28) / 15.0f;
   3.380 +                                q /= 10.0f; /*Horrible and wrong hack*/
   3.381 +                                emu8k->voice[emu8k->cur_voice].q = (int32_t)((1.0f / (0.707f + q)) * 256.0f);
   3.382 +
   3.383 +/*                                pclog("emu8k_outl : write CCCA %08X Q %f invQ %X\n", emu8k->voice[emu8k->cur_voice].ccca, q, emu8k->voice[emu8k->cur_voice].q);*/
   3.384 +                        }
   3.385 +                        return;
   3.386 +
   3.387 +                        case 1:
   3.388 +                        switch (emu8k->cur_voice)
   3.389 +                        {
   3.390 +                                case 20:
   3.391 +                                WRITE16(addr, emu8k->smalr, val);
   3.392 +                                return;
   3.393 +                                case 21:
   3.394 +                                WRITE16(addr, emu8k->smarr, val);
   3.395 +                                return;
   3.396 +                                case 22:
   3.397 +                                WRITE16(addr, emu8k->smalw, val);
   3.398 +                                return;
   3.399 +                                case 23:
   3.400 +                                WRITE16(addr, emu8k->smarw, val);
   3.401 +                                return;
   3.402 +
   3.403 +                                case 26:
   3.404 +                                EMU8K_WRITE(emu8k, emu8k->smarw, val);
   3.405 +                                emu8k->smarw++;
   3.406 +                                break;
   3.407 +                        }
   3.408 +                        break;
   3.409 +
   3.410 +                        case 4:
   3.411 +/*                        pclog("emu8k_outw : write ATKHLDV %04X\n", val);*/
   3.412 +                        emu8k->voice[emu8k->cur_voice].atkhldv = val;
   3.413 +                        emu8k->voice[emu8k->cur_voice].env_attack = (val & 0x7f) << 6;
   3.414 +                        if (!(val & 0x8000)) /*Trigger attack*/
   3.415 +                                emu8k->voice[emu8k->cur_voice].env_state = ENV_ATTACK;
   3.416 +                        return;
   3.417 +
   3.418 +                        case 6:
   3.419 +/*                        pclog("emu8k_outw : write ATKHLD %04X\n", val);*/
   3.420 +                        emu8k->voice[emu8k->cur_voice].atkhld = val;
   3.421 +                        emu8k->voice[emu8k->cur_voice].menv_attack = (val & 0x7f) << 6;
   3.422 +                        if (!(val & 0x8000)) /*Trigger attack*/
   3.423 +                                emu8k->voice[emu8k->cur_voice].menv_state = ENV_ATTACK;
   3.424 +                        return;
   3.425 +                }
   3.426 +                break;
   3.427 +                
   3.428 +                case 0xc00: /*Data3*/
   3.429 +                switch (emu8k->cur_reg)
   3.430 +                {
   3.431 +                        case 0:
   3.432 +                        emu8k->voice[emu8k->cur_voice].ip = val;
   3.433 +                        emu8k->voice[emu8k->cur_voice].pitch = val;
   3.434 +                        return;
   3.435 +                        
   3.436 +                        case 1:
   3.437 +                        emu8k->voice[emu8k->cur_voice].ifatn = val;
   3.438 +                        emu8k->voice[emu8k->cur_voice].attenuation = attentable[val & 0xff];
   3.439 +                        emu8k->voice[emu8k->cur_voice].cutoff = (val >> 8);
   3.440 +/*                        pclog("Attenuation now %02X %i\n", val & 0xff, emu8k->voice[emu8k->cur_voice].attenuation);*/
   3.441 +                        return;
   3.442 +
   3.443 +                        case 2:
   3.444 +                        emu8k->voice[emu8k->cur_voice].pefe = val;
   3.445 +                        emu8k->voice[emu8k->cur_voice].fe_height = (int8_t)(val & 0xff);
   3.446 +                        return;
   3.447 +
   3.448 +                        case 3:
   3.449 +                        emu8k->voice[emu8k->cur_voice].fmmod = val;
   3.450 +                        emu8k->voice[emu8k->cur_voice].lfo1_fmmod = (val >> 8);
   3.451 +                        return;
   3.452 +
   3.453 +                        case 4:
   3.454 +                        emu8k->voice[emu8k->cur_voice].tremfrq = val;
   3.455 +                        emu8k->voice[emu8k->cur_voice].lfo1_trem = (val >> 8);
   3.456 +                        return;
   3.457 +
   3.458 +                        case 5:
   3.459 +                        emu8k->voice[emu8k->cur_voice].fm2frq2 = val;
   3.460 +                        emu8k->voice[emu8k->cur_voice].lfo2_fmmod = (val >> 8);
   3.461 +                        return;
   3.462 +                }
   3.463 +                break;
   3.464 +                
   3.465 +                case 0xc02: /*Pointer*/
   3.466 +                emu8k->cur_voice = (val & 31);
   3.467 +                emu8k->cur_reg   = ((val >> 5) & 7);
   3.468 +                return;
   3.469 +        }
   3.470 +}
   3.471 +
   3.472 +void emu8k_poll(void *p)
   3.473 +{
   3.474 +        emu8k_t *emu8k = (emu8k_t *)p;
   3.475 +        int c;
   3.476 +        int32_t out_l = 0, out_r = 0;
   3.477 +        
   3.478 +        emu8k->timer_count += (int)(TIMER_USEC * (1000000.0 / 44100.0));
   3.479 +        
   3.480 +        for (c = 0; c < 32; c++)
   3.481 +        {
   3.482 +                int32_t voice_l, voice_r;
   3.483 +                int32_t dat;
   3.484 +                int lfo1_vibrato, lfo2_vibrato;
   3.485 +                int tremolo;
   3.486 +                
   3.487 +                tremolo = ((lfotable[(emu8k->voice[c].lfo1_count >> 8) & 4095] * emu8k->voice[c].lfo1_trem) * 4) >> 12;
   3.488 +
   3.489 +                if (freqtable[emu8k->voice[c].pitch] >> 32)
   3.490 +                        dat = EMU8K_READ(emu8k, emu8k->voice[c].addr >> 32);
   3.491 +                else
   3.492 +                        dat = EMU8K_READ_INTERP(emu8k, emu8k->voice[c].addr >> 24);
   3.493 +
   3.494 +                dat = (dat * emu8k->voice[c].attenuation) >> 16;
   3.495 +
   3.496 +                dat = (dat * envtable[emu8k->voice[c].env_vol >> 9]) >> 16;
   3.497 +                        
   3.498 +                if ((emu8k->voice[c].ccca >> 28) || (emu8k->voice[c].cutoff != 0xff))
   3.499 +                {
   3.500 +                        int cutoff = emu8k->voice[c].cutoff + ((emu8k->voice[c].menv_vol * emu8k->voice[c].fe_height) >> 20);
   3.501 +                        if (cutoff < 0)
   3.502 +                                cutoff = 0;
   3.503 +                        if (cutoff > 255)
   3.504 +                                cutoff = 255;
   3.505 +
   3.506 +                        emu8k->voice[c].vhp = ((-emu8k->voice[c].vbp * emu8k->voice[c].q) >> 8) - emu8k->voice[c].vlp - dat;
   3.507 +                        emu8k->voice[c].vlp += (emu8k->voice[c].vbp * filt_w0[cutoff]) >> 8;
   3.508 +                        emu8k->voice[c].vbp += (emu8k->voice[c].vhp * filt_w0[cutoff]) >> 8;
   3.509 +                        if (emu8k->voice[c].vlp < -32767)
   3.510 +                                dat = -32767;
   3.511 +                        else if (emu8k->voice[c].vlp > 32767)
   3.512 +                                dat = 32767;
   3.513 +                        else
   3.514 +                                dat = (int16_t)emu8k->voice[c].vlp;
   3.515 +                }
   3.516 +                        
   3.517 +                voice_l = (dat * emu8k->voice[c].vol_l) >> 7;
   3.518 +                voice_r = (dat * emu8k->voice[c].vol_r) >> 7;
   3.519 +                        
   3.520 +                out_l += voice_l * 8192;
   3.521 +                out_r += voice_r * 8192;
   3.522 +
   3.523 +                switch (emu8k->voice[c].env_state)
   3.524 +                {
   3.525 +                        case ENV_ATTACK:
   3.526 +                        emu8k->voice[c].env_vol += emu8k->voice[c].env_attack;
   3.527 +                        if (emu8k->voice[c].env_vol >= (1 << 21))
   3.528 +                        {
   3.529 +                                emu8k->voice[c].env_vol = 1 << 21;
   3.530 +                                emu8k->voice[c].env_state = ENV_DECAY;
   3.531 +                        }
   3.532 +                        break;
   3.533 +                        
   3.534 +                        case ENV_DECAY:
   3.535 +                        emu8k->voice[c].env_vol -= emu8k->voice[c].env_decay;
   3.536 +                        if (emu8k->voice[c].env_vol <= emu8k->voice[c].env_sustain)
   3.537 +                        {
   3.538 +                                emu8k->voice[c].env_vol = emu8k->voice[c].env_sustain;
   3.539 +                                emu8k->voice[c].env_state = ENV_SUSTAIN;
   3.540 +                        }
   3.541 +                        break;
   3.542 +
   3.543 +                        case ENV_RELEASE:
   3.544 +                        emu8k->voice[c].env_vol -= emu8k->voice[c].env_release;
   3.545 +                        if (emu8k->voice[c].env_vol <= 0)
   3.546 +                        {
   3.547 +                                emu8k->voice[c].env_vol = 0;
   3.548 +                                emu8k->voice[c].env_state = ENV_STOPPED;
   3.549 +                        }
   3.550 +                        break;
   3.551 +                }
   3.552 +
   3.553 +                switch (emu8k->voice[c].menv_state)
   3.554 +                {
   3.555 +                        case ENV_ATTACK:
   3.556 +                        emu8k->voice[c].menv_vol += emu8k->voice[c].menv_attack;
   3.557 +                        if (emu8k->voice[c].menv_vol >= (1 << 21))
   3.558 +                        {
   3.559 +                                emu8k->voice[c].menv_vol = 1 << 21;
   3.560 +                                emu8k->voice[c].menv_state = ENV_DECAY;
   3.561 +                        }
   3.562 +                        break;
   3.563 +                        
   3.564 +                        case ENV_DECAY:
   3.565 +                        emu8k->voice[c].menv_vol -= emu8k->voice[c].menv_decay;
   3.566 +                        if (emu8k->voice[c].menv_vol <= emu8k->voice[c].menv_sustain)
   3.567 +                        {
   3.568 +                                emu8k->voice[c].menv_vol = emu8k->voice[c].menv_sustain;
   3.569 +                                emu8k->voice[c].menv_state = ENV_SUSTAIN;
   3.570 +                        }
   3.571 +                        break;
   3.572 +
   3.573 +                        case ENV_RELEASE:
   3.574 +                        emu8k->voice[c].menv_vol -= emu8k->voice[c].menv_release;
   3.575 +                        if (emu8k->voice[c].menv_vol <= 0)
   3.576 +                        {
   3.577 +                                emu8k->voice[c].menv_vol = 0;
   3.578 +                                emu8k->voice[c].menv_state = ENV_STOPPED;
   3.579 +                        }
   3.580 +                        break;
   3.581 +                }
   3.582 +
   3.583 +                lfo1_vibrato = (lfotable[(emu8k->voice[c].lfo1_count >> 8) & 4095] * emu8k->voice[c].lfo1_fmmod) >> 9;
   3.584 +                lfo2_vibrato = (lfotable[(emu8k->voice[c].lfo2_count >> 8) & 4095] * emu8k->voice[c].lfo2_fmmod) >> 9;
   3.585 +                                
   3.586 +                emu8k->voice[c].addr += freqtable[(emu8k->voice[c].pitch + lfo1_vibrato + lfo2_vibrato) & 0xffff];
   3.587 +                if (emu8k->voice[c].addr >= emu8k->voice[c].loop_end)
   3.588 +                        emu8k->voice[c].addr -= (emu8k->voice[c].loop_end - emu8k->voice[c].loop_start);
   3.589 +
   3.590 +                emu8k->voice[c].lfo1_count += (emu8k->voice[c].tremfrq & 0xff);
   3.591 +                emu8k->voice[c].lfo2_count += (emu8k->voice[c].fm2frq2 & 0xff);
   3.592 +        }
   3.593 +        
   3.594 +        emu8k->out_l = out_l >> 16;
   3.595 +        emu8k->out_r = out_r >> 16;
   3.596 +        
   3.597 +        emu8k->wc++;
   3.598 +}
   3.599 +
   3.600 +void emu8k_poll_getsamp(emu8k_t *emu8k, int16_t *l, int16_t *r)
   3.601 +{
   3.602 +        *l = emu8k->out_l;
   3.603 +        *r = emu8k->out_r;
   3.604 +}
   3.605 +
   3.606 +void emu8k_init(emu8k_t *emu8k)
   3.607 +{
   3.608 +        FILE *f;
   3.609 +        int c;
   3.610 +        double out;
   3.611 +        
   3.612 +        f = romfopen("roms/awe32.raw", "rb");
   3.613 +        if (!f)
   3.614 +                fatal("ROMS/AWE32.RAW not found\n");
   3.615 +                
   3.616 +        emu8k->ram = malloc(512 * 1024);
   3.617 +        emu8k->rom = malloc(1024 * 1024);        
   3.618 +        
   3.619 +        fread(emu8k->rom, 1024 * 1024, 1, f);
   3.620 +        fclose(f);
   3.621 +        
   3.622 +        io_sethandler(0x0620, 0x0004, NULL, emu8k_inw, NULL, NULL, emu8k_outw, NULL, emu8k);
   3.623 +        io_sethandler(0x0a20, 0x0004, NULL, emu8k_inw, NULL, NULL, emu8k_outw, NULL, emu8k);
   3.624 +        io_sethandler(0x0e20, 0x0004, NULL, emu8k_inw, NULL, NULL, emu8k_outw, NULL, emu8k);
   3.625 +
   3.626 +        timer_add(emu8k_poll, &emu8k->timer_count, TIMER_ALWAYS_ENABLED, emu8k);
   3.627 +                        
   3.628 +        /*Create frequency table*/
   3.629 +        for (c = 0; c < 0x10000; c++)
   3.630 +        {
   3.631 +                freqtable[c] = (uint64_t)(exp2((double)(c - 0xe000) / 4096.0) * 65536.0 * 65536.0);
   3.632 +        }
   3.633 +
   3.634 +        out = 65536.0;
   3.635 +        
   3.636 +        for (c = 0; c < 256; c++)
   3.637 +        {
   3.638 +                attentable[c] = (int)out;     
   3.639 +                out /= sqrt(1.09018); /*0.375 dB steps*/
   3.640 +        }
   3.641 +        
   3.642 +        out = 65536;
   3.643 +        
   3.644 +        for (c = 0; c < 4096; c++)
   3.645 +        {
   3.646 +                envtable[4095 - c] = (int)out;
   3.647 +                out /= 1.002709201; /*0.0235 dB Steps*/
   3.648 +        }
   3.649 +        
   3.650 +        for (c = 0; c < 4096; c++)
   3.651 +        {
   3.652 +                int d = (c + 1024) & 4095;
   3.653 +                if (d >= 2048)
   3.654 +                        lfotable[c] = 4096 - ((2048 - d) * 4);
   3.655 +                else
   3.656 +                        lfotable[c] = (d * 4) - 4096;
   3.657 +        }
   3.658 +
   3.659 +        out = 125.0;
   3.660 +        for (c = 0; c < 256; c++)
   3.661 +        {
   3.662 +/*                filt_w0[c] = (int32_t)((2.0 * 3.142 * (out / 44100.0)) * 0.707 * 256.0);*/
   3.663 +/*                filt_w0[c] = 2.0 * 3.142 * (out / 44100.0);*/
   3.664 +                filt_w0[c] = (int32_t)(2.0 * 3.142 * (out / 44100.0) * 256.0);
   3.665 +                out *= 1.016378315;
   3.666 +        }
   3.667 +        
   3.668 +        emu8k->hwcf1 = 0x59;
   3.669 +        emu8k->hwcf2 = 0x03;
   3.670 +}
   3.671 +
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/src/sound_emu8k.h	Tue Jul 23 22:04:17 2013 +0100
     4.3 @@ -0,0 +1,81 @@
     4.4 +typedef struct emu8k_t
     4.5 +{
     4.6 +        struct
     4.7 +        {
     4.8 +                uint32_t cpf;
     4.9 +                uint32_t ptrx;
    4.10 +                uint32_t cvcf;
    4.11 +                uint32_t vtft;
    4.12 +                uint32_t psst;
    4.13 +                uint32_t csl;
    4.14 +                
    4.15 +                uint32_t ccca;
    4.16 +
    4.17 +                uint16_t init1, init2, init3, init4;
    4.18 +                
    4.19 +                uint16_t envvol;
    4.20 +                uint16_t dcysusv;
    4.21 +                uint16_t envval;
    4.22 +                uint16_t dcysus;
    4.23 +                uint16_t atkhldv;
    4.24 +                uint16_t lfo1val, lfo2val;
    4.25 +                uint16_t atkhld;
    4.26 +                uint16_t ip;
    4.27 +                uint16_t ifatn;
    4.28 +                uint16_t pefe;
    4.29 +                uint16_t fmmod;
    4.30 +                uint16_t tremfrq;
    4.31 +                uint16_t fm2frq2;
    4.32 +                
    4.33 +                int voice_on;
    4.34 +                
    4.35 +                uint64_t addr;
    4.36 +                uint64_t loop_start, loop_end;
    4.37 +                
    4.38 +                uint16_t pitch;
    4.39 +                int attenuation;
    4.40 +                int env_state, env_vol;
    4.41 +                int env_attack, env_decay, env_sustain, env_release;
    4.42 +
    4.43 +                int menv_state, menv_vol;
    4.44 +                int menv_attack, menv_decay, menv_sustain, menv_release;
    4.45 +                
    4.46 +                int lfo1_count, lfo2_count;
    4.47 +                int8_t lfo1_fmmod, lfo2_fmmod;
    4.48 +                int8_t lfo1_trem;
    4.49 +                int vol_l, vol_r;
    4.50 +                
    4.51 +                int8_t fe_height;
    4.52 +                
    4.53 +                int64_t vlp, vbp, vhp;
    4.54 +                int32_t q;
    4.55 +                
    4.56 +                int filter_offset;
    4.57 +                
    4.58 +/*                float vlp, vbp, vhp;
    4.59 +                float q;*/
    4.60 +                
    4.61 +                int cutoff;
    4.62 +        } voice[32];
    4.63 +
    4.64 +        uint32_t hwcf1, hwcf2, hwcf3;
    4.65 +        uint32_t hwcf4, hwcf5, hwcf6;
    4.66 +                
    4.67 +        uint32_t smalr, smarr, smalw, smarw;
    4.68 +        uint16_t smld_buffer, smrd_buffer;
    4.69 +
    4.70 +        uint16_t wc;
    4.71 +        
    4.72 +        uint16_t c02_read;
    4.73 +        
    4.74 +        int16_t *ram, *rom;
    4.75 +        
    4.76 +        int cur_reg, cur_voice;
    4.77 +        
    4.78 +        int timer_count;
    4.79 +        
    4.80 +        int16_t out_l, out_r;
    4.81 +} emu8k_t;
    4.82 +
    4.83 +void emu8k_init(emu8k_t *emu8k);
    4.84 +void emu8k_poll_getsamp(emu8k_t *dsp, int16_t *l, int16_t *r);
     5.1 --- a/src/sound_sb.c	Sat Jul 20 13:42:31 2013 +0100
     5.2 +++ b/src/sound_sb.c	Tue Jul 23 22:04:17 2013 +0100
     5.3 @@ -1,6 +1,7 @@
     5.4  #include <stdlib.h>
     5.5  #include "ibm.h"
     5.6  #include "device.h"
     5.7 +#include "sound_emu8k.h"
     5.8  #include "sound_mpu401_uart.h"
     5.9  #include "sound_opl.h"
    5.10  #include "sound_sb.h"
    5.11 @@ -27,9 +28,11 @@
    5.12          sb_dsp_t        dsp;
    5.13          sb_mixer_t      mixer;
    5.14          mpu401_uart_t   mpu;
    5.15 +        emu8k_t         emu8k;
    5.16  
    5.17          int16_t opl_buffer[SOUNDBUFLEN * 2];
    5.18          int16_t dsp_buffer[SOUNDBUFLEN * 2];
    5.19 +        int16_t emu8k_buffer[SOUNDBUFLEN * 2];
    5.20  
    5.21          int pos;
    5.22  } sb_t;
    5.23 @@ -65,6 +68,18 @@
    5.24          sb->pos++;
    5.25  }
    5.26  
    5.27 +static void sb_emu8k_poll(void *p)
    5.28 +{
    5.29 +        sb_t *sb = (sb_t *)p;
    5.30 +        
    5.31 +        if (sb->pos >= SOUNDBUFLEN) return;
    5.32 +        
    5.33 +        opl3_poll(&sb->opl, &sb->opl_buffer[sb->pos * 2], &sb->opl_buffer[(sb->pos * 2) + 1]);
    5.34 +        sb_dsp_poll(&sb->dsp, &sb->dsp_buffer[sb->pos * 2], &sb->dsp_buffer[(sb->pos * 2) + 1]);
    5.35 +        emu8k_poll_getsamp(&sb->emu8k, &sb->emu8k_buffer[sb->pos * 2], &sb->emu8k_buffer[(sb->pos * 2) + 1]);
    5.36 +        sb->pos++;
    5.37 +}
    5.38 +
    5.39  static void sb_get_buffer(int16_t *buffer, int len, void *p)
    5.40  {
    5.41          sb_t *sb = (sb_t *)p;
    5.42 @@ -78,6 +93,10 @@
    5.43                  
    5.44                  out_l = ((sb->opl_buffer[c]     * mixer->fm_l) >> 16);
    5.45                  out_r = ((sb->opl_buffer[c + 1] * mixer->fm_r) >> 16);
    5.46 +
    5.47 +                out_l += ((sb->emu8k_buffer[c]     * mixer->fm_l) >> 16);
    5.48 +                out_r += ((sb->emu8k_buffer[c + 1] * mixer->fm_l) >> 16);
    5.49 +
    5.50                  if (sb->mixer.filter)
    5.51                  {
    5.52                          out_l += (int)(((sb_iir(0, (float)sb->dsp_buffer[c])     / 1.3) * mixer->voice_l) / 3) >> 16;
    5.53 @@ -357,6 +376,40 @@
    5.54          return sb;
    5.55  }
    5.56  
    5.57 +void *sb_awe32_init()
    5.58 +{
    5.59 +        sb_t *sb = malloc(sizeof(sb_t));
    5.60 +        memset(sb, 0, sizeof(sb_t));
    5.61 +
    5.62 +        opl3_init(&sb->opl);
    5.63 +        sb_dsp_init(&sb->dsp, SB16);
    5.64 +        sb_dsp_setaddr(&sb->dsp, 0x0220);
    5.65 +        sb_mixer_init(&sb->mixer);
    5.66 +        io_sethandler(0x0220, 0x0004, opl3_read,   NULL, NULL, opl3_write,   NULL, NULL, &sb->opl);
    5.67 +        io_sethandler(0x0228, 0x0002, opl3_read,   NULL, NULL, opl3_write,   NULL, NULL, &sb->opl);
    5.68 +        io_sethandler(0x0388, 0x0002, opl3_read,   NULL, NULL, opl3_write,   NULL, NULL, &sb->opl);
    5.69 +        io_sethandler(0x0224, 0x0002, sb_16_mixer_read, NULL, NULL, sb_16_mixer_write, NULL, NULL, sb);
    5.70 +        sound_add_handler(sb_emu8k_poll, sb_get_buffer, sb);
    5.71 +        mpu401_uart_init(&sb->mpu, 0x330);       
    5.72 +        emu8k_init(&sb->emu8k);
    5.73 +
    5.74 +        sb->mixer.regs[0x30] = 31 << 3;
    5.75 +        sb->mixer.regs[0x31] = 31 << 3;
    5.76 +        sb->mixer.regs[0x32] = 31 << 3;
    5.77 +        sb->mixer.regs[0x33] = 31 << 3;
    5.78 +        sb->mixer.regs[0x34] = 31 << 3;
    5.79 +        sb->mixer.regs[0x35] = 31 << 3;
    5.80 +        sb->mixer.regs[0x44] =  8 << 4;
    5.81 +        sb->mixer.regs[0x45] =  8 << 4;
    5.82 +        sb->mixer.regs[0x46] =  8 << 4;
    5.83 +        sb->mixer.regs[0x47] =  8 << 4;
    5.84 +        sb->mixer.regs[0x22] = (sb->mixer.regs[0x30] & 0xf0) | (sb->mixer.regs[0x31] >> 4);
    5.85 +        sb->mixer.regs[0x04] = (sb->mixer.regs[0x32] & 0xf0) | (sb->mixer.regs[0x33] >> 4);
    5.86 +        sb->mixer.regs[0x26] = (sb->mixer.regs[0x34] & 0xf0) | (sb->mixer.regs[0x35] >> 4);
    5.87 +        
    5.88 +        return sb;
    5.89 +}
    5.90 +
    5.91  void sb_close(void *p)
    5.92  {
    5.93          sb_t *sb = (sb_t *)p;
    5.94 @@ -419,3 +472,11 @@
    5.95          sb_speed_changed,
    5.96          NULL
    5.97  };
    5.98 +device_t sb_awe32_device =
    5.99 +{
   5.100 +        "Sound Blaster AWE32",
   5.101 +        sb_awe32_init,
   5.102 +        sb_close,
   5.103 +        sb_speed_changed,
   5.104 +        NULL
   5.105 +};
     6.1 --- a/src/sound_sb.h	Sat Jul 20 13:42:31 2013 +0100
     6.2 +++ b/src/sound_sb.h	Tue Jul 23 22:04:17 2013 +0100
     6.3 @@ -4,3 +4,4 @@
     6.4  extern device_t sb_pro_v1_device;
     6.5  extern device_t sb_pro_v2_device;
     6.6  extern device_t sb_16_device;
     6.7 +extern device_t sb_awe32_device;