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 +};
