diff --git a/src/sound_ad1848.c b/src/sound_ad1848.c new file mode 100644 index 0000000..499fd15 --- /dev/null +++ b/src/sound_ad1848.c @@ -0,0 +1,204 @@ +/*PCem v0.8 by Tom Walker + + AD1848 CODEC emulation (Windows Sound System compatible)*/ + +#include "ibm.h" +#include "sound_ad1848.h" + +static int ad1848_vols[64]; + +void ad1848_setirq(ad1848_t *ad1848, int irq) +{ + ad1848->irq = irq; +} + +void ad1848_setdma(ad1848_t *ad1848, int dma) +{ + ad1848->dma = dma; +} + +uint8_t ad1848_read(uint16_t addr, void *p) +{ + ad1848_t *ad1848 = (ad1848_t *)p; + uint8_t temp = 0xff; +// pclog("ad1848_read - addr %04X %04X(%08X):%08X ", addr, CS, cs, pc); + switch (addr & 3) + { + case 0: /*Index*/ + temp = ad1848->index | ad1848->trd | ad1848->mce; + break; + case 1: + temp = ad1848->regs[ad1848->index]; + break; + case 2: + temp = ad1848->status; + break; + } +// pclog("return %02X\n", temp); + return temp; +} + +void ad1848_write(uint16_t addr, uint8_t val, void *p) +{ + ad1848_t *ad1848 = (ad1848_t *)p; + double freq; +// pclog("ad1848_write - addr %04X val %02X %04X(%08X):%08X\n", addr, val, CS, cs, pc); + switch (addr & 3) + { + case 0: /*Index*/ + ad1848->index = val & 0xf; + ad1848->trd = val & 0x20; + ad1848->mce = val & 0x40; + break; + case 1: + switch (ad1848->index) + { + case 8: + freq = (val & 1) ? 16934400 : 24576000; + switch ((val >> 1) & 7) + { + case 0: freq /= 3072; break; + case 1: freq /= 1536; break; + case 2: freq /= 896; break; + case 3: freq /= 768; break; + case 4: freq /= 448; break; + case 5: freq /= 384; break; + case 6: freq /= 512; break; + case 7: freq /= 2560; break; + } + ad1848->inc = (int)((freq * 65536) / 48000); + break; + + case 9: + if (!ad1848->enable) + ad1848->interp_count = 0; + + ad1848->enable = ((val & 0x41) == 0x01); + break; + + case 12: + return; + + case 14: + ad1848->count = ad1848->regs[15] | (val << 8); + break; + } + ad1848->regs[ad1848->index] = val; + break; + case 2: + ad1848->status &= 0xfe; + break; + } +} + +void ad1848_poll(void *p, int16_t *l, int16_t *r) +{ + ad1848_t *ad1848 = (ad1848_t *)p; + +// opl3_poll(&ad1848->opl, &ad1848->opl_buffer[ad1848->pos * 2], &ad1848->opl_buffer[(ad1848->pos * 2) + 1]); + + if (ad1848->enable) + { + int32_t temp; + + if (ad1848->regs[6] & 0x80) + *l = 0; + else + *l = (ad1848->out_l * ad1848_vols[ad1848->regs[6] & 0x3f]) >> 16; + + if (ad1848->regs[7] & 0x80) + *r = 0; + else + *r = (ad1848->out_r * ad1848_vols[ad1848->regs[7] & 0x3f]) >> 16; + + ad1848->interp_count += ad1848->inc; + if (ad1848->interp_count >= 0x10000) + { + ad1848->interp_count -= 0x10000; + + if (ad1848->count < 0) + { + ad1848->count = ad1848->regs[15] | (ad1848->regs[14] << 8); + if (!(ad1848->status & 0x01)) + { + ad1848->status |= 0x01; + if (ad1848->regs[0xa] & 2) + picint(1 << ad1848->irq); + } + } + + switch (ad1848->regs[8] & 0x70) + { + case 0x00: /*Mono, 8-bit PCM*/ + ad1848->out_l = ad1848->out_r = (dma_channel_read(ad1848->dma) ^ 0x80) * 256; + break; + case 0x10: /*Stereo, 8-bit PCM*/ + ad1848->out_l = (dma_channel_read(ad1848->dma) ^ 0x80) * 256; + ad1848->out_r = (dma_channel_read(ad1848->dma) ^ 0x80) * 256; + break; + + case 0x40: /*Mono, 16-bit PCM*/ + temp = dma_channel_read(ad1848->dma); + ad1848->out_l = ad1848->out_r = dma_channel_read(ad1848->dma) | (temp << 8); + break; + case 0x50: /*Stereo, 16-bit PCM*/ + temp = dma_channel_read(ad1848->dma); + ad1848->out_l = dma_channel_read(ad1848->dma) | (temp << 8); + temp = dma_channel_read(ad1848->dma); + ad1848->out_r = dma_channel_read(ad1848->dma) | (temp << 8); + break; + } + + ad1848->count--; + } +// pclog("ad1848_poll : enable %X %X %X %X %X %X\n", ad1848->pcm_buffer[0][ad1848->pos], ad1848->pcm_buffer[1][ad1848->pos], ad1848->out_l[0], ad1848->out_r[0], ad1848->out_l[1], ad1848->out_r[1]); + } + else + { + *l = *r = 0; +// pclog("ad1848_poll : not enable\n"); + } +} + +void ad1848_init(ad1848_t *ad1848) +{ + int c; + double attenuation; + + ad1848->enable = 0; + + ad1848->status = 0xcc; + ad1848->index = ad1848->trd = 0; + ad1848->mce = 0x40; + + ad1848->regs[0] = ad1848->regs[1] = 0; + ad1848->regs[2] = ad1848->regs[3] = 0x80; + ad1848->regs[4] = ad1848->regs[5] = 0x80; + ad1848->regs[6] = ad1848->regs[7] = 0x80; + ad1848->regs[8] = 0; + ad1848->regs[9] = 0x08; + ad1848->regs[10] = ad1848->regs[11] = 0; + ad1848->regs[12] = 0xa; + ad1848->regs[13] = 0; + ad1848->regs[14] = ad1848->regs[15] = 0; + + ad1848->out_l = 0; + ad1848->out_r = 0; + ad1848->interp_count = 0; + + for (c = 0; c < 64; c++) + { + attenuation = 0.0; + if (c & 0x01) attenuation -= 1.5; + if (c & 0x02) attenuation -= 3.0; + if (c & 0x04) attenuation -= 6.0; + if (c & 0x08) attenuation -= 12.0; + if (c & 0x10) attenuation -= 24.0; + if (c & 0x20) attenuation -= 48.0; + + attenuation = pow(10, attenuation / 10); + + ad1848_vols[c] = (int)(attenuation * 65536); +// pclog("ad1848_vols %i = %f %i\n", c, attenuation, ad1848_vols[c]); + } +} diff --git a/src/sound_ad1848.h b/src/sound_ad1848.h new file mode 100644 index 0000000..bbed948 --- /dev/null +++ b/src/sound_ad1848.h @@ -0,0 +1,27 @@ +typedef struct ad1848_t +{ + int index; + uint8_t regs[16]; + uint8_t status; + + int trd; + int mce; + + int count; + + int16_t out_l, out_r; + + int interp_count, inc; + + int enable; + + int irq, dma; +} ad1848_t; + +void ad1848_setirq(ad1848_t *ad1848, int irq); +void ad1848_setdma(ad1848_t *ad1848, int dma); + +uint8_t ad1848_read(uint16_t addr, void *p); +void ad1848_write(uint16_t addr, uint8_t val, void *p); + +void ad1848_poll(void *p, int16_t *l, int16_t *r); diff --git a/src/sound_wss.c b/src/sound_wss.c index e6ee21a..f46bbc8 100644 --- a/src/sound_wss.c +++ b/src/sound_wss.c @@ -1,6 +1,6 @@ /*PCem v0.8 by Tom Walker - Windows Sound System compatible CODEC emulation (AD1848)*/ + Windows Sound System emulation*/ #include #include @@ -10,6 +10,7 @@ #include "dma.h" #include "io.h" #include "pic.h" +#include "sound_ad1848.h" #include "sound_opl.h" #include "sound_wss.h" @@ -31,24 +32,8 @@ static uint16_t wss_addr[4] = {0x530, 0x604, 0xe80, 0xf40}; typedef struct wss_t { uint8_t config; - - int index; - uint8_t regs[16]; - uint8_t status; - - int trd; - int mce; - - int count; - - int16_t out_l, out_r; - - int interp_count, inc; - int enable; - - int irq, dma; - + ad1848_t ad1848; opl_t opl; int16_t opl_buffer[SOUNDBUFLEN * 2]; @@ -57,29 +42,12 @@ typedef struct wss_t int pos; } wss_t; -static int wss_vols[64]; - uint8_t wss_read(uint16_t addr, void *p) { wss_t *wss = (wss_t *)p; - uint8_t temp = 0xff; + uint8_t temp; // pclog("wss_read - addr %04X %04X(%08X):%08X ", addr, CS, cs, pc); - switch (addr & 7) - { - case 0: case 1: case 2: case 3: /*Version*/ - temp = 4 | (wss->config & 0x40); - break; - - case 4: /*Index*/ - temp = wss->index | wss->trd | wss->mce; - break; - case 5: - temp = wss->regs[wss->index]; - break; - case 6: - temp = wss->status; - break; - } + temp = 4 | (wss->config & 0x40); // pclog("return %02X\n", temp); return temp; } @@ -87,60 +55,11 @@ uint8_t wss_read(uint16_t addr, void *p) void wss_write(uint16_t addr, uint8_t val, void *p) { wss_t *wss = (wss_t *)p; - double freq; - pclog("wss_write - addr %04X val %02X %04X(%08X):%08X\n", addr, val, CS, cs, pc); - switch (addr & 7) - { - case 0: case 1: case 2: case 3: /*Config*/ - wss->config = val; - wss->dma = wss_dma[val & 3]; - wss->irq = wss_irq[(val >> 3) & 7]; - break; - - case 4: /*Index*/ - wss->index = val & 0xf; - wss->trd = val & 0x20; - wss->mce = val & 0x40; - break; - case 5: - switch (wss->index) - { - case 8: - freq = (val & 1) ? 16934400 : 24576000; - switch ((val >> 1) & 7) - { - case 0: freq /= 3072; break; - case 1: freq /= 1536; break; - case 2: freq /= 896; break; - case 3: freq /= 768; break; - case 4: freq /= 448; break; - case 5: freq /= 384; break; - case 6: freq /= 512; break; - case 7: freq /= 2560; break; - } - wss->inc = (int)((freq * 65536) / 48000); - break; - - case 9: - if (!wss->enable) - wss->interp_count = 0; - - wss->enable = ((val & 0x41) == 0x01); - break; - - case 12: - return; - - case 14: - wss->count = wss->regs[15] | (val << 8); - break; - } - wss->regs[wss->index] = val; - break; - case 6: - wss->status &= 0xfe; - break; - } +// pclog("wss_write - addr %04X val %02X %04X(%08X):%08X\n", addr, val, CS, cs, pc); + + wss->config = val; + ad1848_setdma(&wss->ad1848, wss_dma[val & 3]); + ad1848_setirq(&wss->ad1848, wss_irq[(val >> 3) & 7]); } static void wss_poll(void *p) @@ -151,68 +70,8 @@ static void wss_poll(void *p) return; opl3_poll(&wss->opl, &wss->opl_buffer[wss->pos * 2], &wss->opl_buffer[(wss->pos * 2) + 1]); - - if (wss->enable) - { - int32_t temp; - - if (wss->regs[6] & 0x80) - wss->pcm_buffer[1][wss->pos] = 0; - else - wss->pcm_buffer[1][wss->pos] = (wss->out_l * wss_vols[wss->regs[6] & 0x3f]) >> 16; + ad1848_poll(&wss->ad1848, &wss->pcm_buffer[0][wss->pos], &wss->pcm_buffer[1][wss->pos]); - if (wss->regs[7] & 0x80) - wss->pcm_buffer[0][wss->pos] = 0; - else - wss->pcm_buffer[0][wss->pos] = (wss->out_r * wss_vols[wss->regs[7] & 0x3f]) >> 16; - - wss->interp_count += wss->inc; - if (wss->interp_count >= 0x10000) - { - wss->interp_count -= 0x10000; - - if (wss->count < 0) - { - wss->count = wss->regs[15] | (wss->regs[14] << 8); - if (!(wss->status & 0x01)) - { - wss->status |= 0x01; - if (wss->regs[0xa] & 2) - picint(1 << wss->irq); - } - } - - switch (wss->regs[8] & 0x70) - { - case 0x00: /*Mono, 8-bit PCM*/ - wss->out_l = wss->out_r = (dma_channel_read(wss->dma) ^ 0x80) * 256; - break; - case 0x10: /*Stereo, 8-bit PCM*/ - wss->out_l = (dma_channel_read(wss->dma) ^ 0x80) * 256; - wss->out_r = (dma_channel_read(wss->dma) ^ 0x80) * 256; - break; - - case 0x40: /*Mono, 16-bit PCM*/ - temp = dma_channel_read(wss->dma); - wss->out_l = wss->out_r = dma_channel_read(wss->dma) | (temp << 8); - break; - case 0x50: /*Stereo, 16-bit PCM*/ - temp = dma_channel_read(wss->dma); - wss->out_l = dma_channel_read(wss->dma) | (temp << 8); - temp = dma_channel_read(wss->dma); - wss->out_r = dma_channel_read(wss->dma) | (temp << 8); - break; - } - - wss->count--; - } -// pclog("wss_poll : enable %X %X %X %X %X %X\n", wss->pcm_buffer[0][wss->pos], wss->pcm_buffer[1][wss->pos], wss->out_l[0], wss->out_r[0], wss->out_l[1], wss->out_r[1]); - } - else - { - wss->pcm_buffer[0][wss->pos] = wss->pcm_buffer[1][wss->pos] = 0; -// pclog("wss_poll : not enable\n"); - } wss->pos++; } @@ -240,54 +99,17 @@ void *wss_init() memset(wss, 0, sizeof(wss_t)); opl3_init(&wss->opl); + ad1848_init(&wss->ad1848); - pclog("wss_init - %i %i\n", sbtype, SND_WSS); + ad1848_setirq(&wss->ad1848, 7); + ad1848_setdma(&wss->ad1848, 3); - wss->enable = 0; - - wss->status = 0xcc; - wss->index = wss->trd = 0; - wss->mce = 0x40; - - wss->regs[0] = wss->regs[1] = 0; - wss->regs[2] = wss->regs[3] = 0x80; - wss->regs[4] = wss->regs[5] = 0x80; - wss->regs[6] = wss->regs[7] = 0x80; - wss->regs[8] = 0; - wss->regs[9] = 0x08; - wss->regs[10] = wss->regs[11] = 0; - wss->regs[12] = 0xa; - wss->regs[13] = 0; - wss->regs[14] = wss->regs[15] = 0; - - wss->out_l = 0; - wss->out_r = 0; - wss->interp_count = 0; - - wss->irq = 7; - wss->dma = 3; - - io_sethandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &wss->opl); - io_sethandler(0x0530, 0x0008, wss_read, NULL, NULL, wss_write, NULL, NULL, wss); - + io_sethandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &wss->opl); + io_sethandler(0x0530, 0x0004, wss_read, NULL, NULL, wss_write, NULL, NULL, wss); + io_sethandler(0x0534, 0x0004, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &wss->ad1848); + sound_add_handler(wss_poll, wss_get_buffer, wss); - for (c = 0; c < 64; c++) - { - attenuation = 0.0; - if (c & 0x01) attenuation -= 1.5; - if (c & 0x02) attenuation -= 3.0; - if (c & 0x04) attenuation -= 6.0; - if (c & 0x08) attenuation -= 12.0; - if (c & 0x10) attenuation -= 24.0; - if (c & 0x20) attenuation -= 48.0; - - attenuation = pow(10, attenuation / 10); - - wss_vols[c] = (int)(attenuation * 65536); - pclog("wss_vols %i = %f %i\n", c, attenuation, wss_vols[c]); - } - return wss; }