Files
86Box/src/SOUND/snd_sb.c

1297 lines
43 KiB
C

#include <stdlib.h>
#include "../ibm.h"
#include "../io.h"
#include "../mca.h"
#include "../mem.h"
#include "../rom.h"
#include "../device.h"
#include "sound.h"
#include "snd_emu8k.h"
#include "snd_mpu401.h"
#include "snd_opl.h"
#include "snd_sb.h"
#include "snd_sb_dsp.h"
#include "filters.h"
typedef struct sb_mixer_t
{
int master_l, master_r;
int voice_l, voice_r;
int fm_l, fm_r;
int cd_l, cd_r;
int bass_l, bass_r;
int treble_l, treble_r;
int filter;
int index;
uint8_t regs[256];
} sb_mixer_t;
typedef struct sb_t
{
opl_t opl;
sb_dsp_t dsp;
sb_mixer_t mixer;
mpu_t mpu;
emu8k_t emu8k;
int pos;
uint8_t pos_regs[8];
} sb_t;
static int sb_att[]=
{
310,368,437,520,618,735,873,1038,1234,1467,1743,2072,2463,2927,3479,
4134,4914,5840,6941,8250,9805,11653,13850,16461,19564,23252,27635,32845,
39036,46395,55140,65535
};
static void sb_get_buffer_opl2(int32_t *buffer, int len, void *p)
{
sb_t *sb = (sb_t *)p;
sb_mixer_t *mixer = &sb->mixer;
int c;
opl2_update2(&sb->opl);
sb_dsp_update(&sb->dsp);
for (c = 0; c < len * 2; c += 2)
{
int32_t out_l, out_r;
out_l = ((sb->opl.buffer[c] * mixer->fm_l) >> 16);
out_r = ((sb->opl.buffer[c + 1] * mixer->fm_r) >> 16);
if (sb->mixer.filter)
{
out_l += (int)(((sb_iir(0, (float)sb->dsp.buffer[c]) / 1.3) * mixer->voice_l) / 3) >> 16;
out_r += (int)(((sb_iir(1, (float)sb->dsp.buffer[c + 1]) / 1.3) * mixer->voice_r) / 3) >> 16;
}
else
{
out_l += ((int32_t)(sb->dsp.buffer[c] * mixer->voice_l) / 3) >> 16;
out_r += ((int32_t)(sb->dsp.buffer[c + 1] * mixer->voice_r) / 3) >> 16;
}
out_l = (out_l * mixer->master_l) >> 15;
out_r = (out_r * mixer->master_r) >> 15;
if (mixer->bass_l != 8 || mixer->bass_r != 8 || mixer->treble_l != 8 || mixer->treble_r != 8)
{
if (mixer->bass_l>8) out_l = (out_l + (((int16_t) low_iir(0, (float)out_l) * (mixer->bass_l - 8)) >> 1)) * ((15 - mixer->bass_l) + 16) >> 5;
if (mixer->bass_r>8) out_r = (out_r + (((int16_t) low_iir(1, (float)out_r) * (mixer->bass_r - 8)) >> 1)) * ((15 - mixer->bass_r) + 16) >> 5;
if (mixer->treble_l>8) out_l = (out_l + (((int16_t) high_iir(0, (float)out_l) * (mixer->treble_l - 8)) >> 1)) * ((15 - mixer->treble_l) + 16) >> 5;
if (mixer->treble_r>8) out_r = (out_r + (((int16_t) high_iir(1, (float)out_r) * (mixer->treble_r - 8)) >> 1)) * ((15 - mixer->treble_r) + 16) >> 5;
if (mixer->bass_l<8) out_l = (out_l + (((int16_t) low_cut_iir(0, (float)out_l) * (8 - mixer->bass_l)) >> 1)) * (mixer->bass_l + 16) >> 5;
if (mixer->bass_r<8) out_r = (out_r + (((int16_t) low_cut_iir(1, (float)out_r) * (8 - mixer->bass_r)) >> 1)) * (mixer->bass_r + 16) >> 5;
if (mixer->treble_l<8) out_l = (out_l + (((int16_t)high_cut_iir(0, (float)out_l) * (8 - mixer->treble_l)) >> 1)) * (mixer->treble_l + 16) >> 5;
if (mixer->treble_r<8) out_r = (out_r + (((int16_t)high_cut_iir(1, (float)out_r) * (8 - mixer->treble_r)) >> 1)) * (mixer->treble_r + 16) >> 5;
}
buffer[c] += out_l;
buffer[c + 1] += out_r;
}
sb->pos = 0;
sb->opl.pos = 0;
sb->dsp.pos = 0;
}
static void sb_get_buffer_opl3(int32_t *buffer, int len, void *p)
{
sb_t *sb = (sb_t *)p;
sb_mixer_t *mixer = &sb->mixer;
int c;
opl3_update2(&sb->opl);
sb_dsp_update(&sb->dsp);
for (c = 0; c < len * 2; c += 2)
{
int32_t out_l, out_r;
out_l = ((sb->opl.buffer[c] * mixer->fm_l) >> 16);
out_r = ((sb->opl.buffer[c + 1] * mixer->fm_r) >> 16);
if (sb->mixer.filter)
{
out_l += (int)(((sb_iir(0, (float)sb->dsp.buffer[c]) / 1.3) * mixer->voice_l) / 3) >> 16;
out_r += (int)(((sb_iir(1, (float)sb->dsp.buffer[c + 1]) / 1.3) * mixer->voice_r) / 3) >> 16;
}
else
{
out_l += ((int32_t)(sb->dsp.buffer[c] * mixer->voice_l) / 3) >> 16;
out_r += ((int32_t)(sb->dsp.buffer[c + 1] * mixer->voice_r) / 3) >> 16;
}
out_l = (out_l * mixer->master_l) >> 15;
out_r = (out_r * mixer->master_r) >> 15;
if (mixer->bass_l != 8 || mixer->bass_r != 8 || mixer->treble_l != 8 || mixer->treble_r != 8)
{
if (mixer->bass_l>8) out_l = (out_l + (((int16_t) low_iir(0, (float)out_l) * (mixer->bass_l - 8)) >> 1)) * ((15 - mixer->bass_l) + 16) >> 5;
if (mixer->bass_r>8) out_r = (out_r + (((int16_t) low_iir(1, (float)out_r) * (mixer->bass_r - 8)) >> 1)) * ((15 - mixer->bass_r) + 16) >> 5;
if (mixer->treble_l>8) out_l = (out_l + (((int16_t) high_iir(0, (float)out_l) * (mixer->treble_l - 8)) >> 1)) * ((15 - mixer->treble_l) + 16) >> 5;
if (mixer->treble_r>8) out_r = (out_r + (((int16_t) high_iir(1, (float)out_r) * (mixer->treble_r - 8)) >> 1)) * ((15 - mixer->treble_r) + 16) >> 5;
if (mixer->bass_l<8) out_l = (out_l + (((int16_t) low_cut_iir(0, (float)out_l) * (8 - mixer->bass_l)) >> 1)) * (mixer->bass_l + 16) >> 5;
if (mixer->bass_r<8) out_r = (out_r + (((int16_t) low_cut_iir(1, (float)out_r) * (8 - mixer->bass_r)) >> 1)) * (mixer->bass_r + 16) >> 5;
if (mixer->treble_l<8) out_l = (out_l + (((int16_t)high_cut_iir(0, (float)out_l) * (8 - mixer->treble_l)) >> 1)) * (mixer->treble_l + 16) >> 5;
if (mixer->treble_r<8) out_r = (out_r + (((int16_t)high_cut_iir(1, (float)out_r) * (8 - mixer->treble_r)) >> 1)) * (mixer->treble_r + 16) >> 5;
}
buffer[c] += out_l;
buffer[c + 1] += out_r;
}
sb->pos = 0;
sb->opl.pos = 0;
sb->dsp.pos = 0;
sb->emu8k.pos = 0;
}
static void sb_get_buffer_emu8k(int32_t *buffer, int len, void *p)
{
sb_t *sb = (sb_t *)p;
sb_mixer_t *mixer = &sb->mixer;
int c;
opl3_update2(&sb->opl);
sb_dsp_update(&sb->dsp);
emu8k_update(&sb->emu8k);
for (c = 0; c < len * 2; c += 2)
{
int c_emu8k = (((c/2) * 44100) / 48000)*2;
int32_t out_l, out_r;
out_l = (((int32_t)sb->opl.buffer[c] * (int32_t)mixer->fm_l) >> 16);
out_r = (((int32_t)sb->opl.buffer[c + 1] * (int32_t)mixer->fm_r) >> 16);
out_l += ((sb->emu8k.buffer[c_emu8k] * mixer->fm_l) >> 16);
out_r += ((sb->emu8k.buffer[c_emu8k + 1] * mixer->fm_l) >> 16);
if (sb->mixer.filter)
{
out_l += (int)(((sb_iir(0, (float)sb->dsp.buffer[c]) / 1.3) * mixer->voice_l) / 3) >> 16;
out_r += (int)(((sb_iir(1, (float)sb->dsp.buffer[c + 1]) / 1.3) * mixer->voice_r) / 3) >> 16;
}
else
{
out_l += ((int32_t)(sb->dsp.buffer[c] * mixer->voice_l) / 3) >> 16;
out_r += ((int32_t)(sb->dsp.buffer[c + 1] * mixer->voice_r) / 3) >> 16;
}
out_l = (out_l * mixer->master_l) >> 15;
out_r = (out_r * mixer->master_r) >> 15;
if (mixer->bass_l != 8 || mixer->bass_r != 8 || mixer->treble_l != 8 || mixer->treble_r != 8)
{
if (mixer->bass_l>8) out_l = (out_l + (((int16_t) low_iir(0, (float)out_l) * (mixer->bass_l - 8)) >> 1)) * ((15 - mixer->bass_l) + 16) >> 5;
if (mixer->bass_r>8) out_r = (out_r + (((int16_t) low_iir(1, (float)out_r) * (mixer->bass_r - 8)) >> 1)) * ((15 - mixer->bass_r) + 16) >> 5;
if (mixer->treble_l>8) out_l = (out_l + (((int16_t) high_iir(0, (float)out_l) * (mixer->treble_l - 8)) >> 1)) * ((15 - mixer->treble_l) + 16) >> 5;
if (mixer->treble_r>8) out_r = (out_r + (((int16_t) high_iir(1, (float)out_r) * (mixer->treble_r - 8)) >> 1)) * ((15 - mixer->treble_r) + 16) >> 5;
if (mixer->bass_l<8) out_l = (out_l + (((int16_t) low_cut_iir(0, (float)out_l) * (8 - mixer->bass_l)) >> 1)) * (mixer->bass_l + 16) >> 5;
if (mixer->bass_r<8) out_r = (out_r + (((int16_t) low_cut_iir(1, (float)out_r) * (8 - mixer->bass_r)) >> 1)) * (mixer->bass_r + 16) >> 5;
if (mixer->treble_l<8) out_l = (out_l + (((int16_t)high_cut_iir(0, (float)out_l) * (8 - mixer->treble_l)) >> 1)) * (mixer->treble_l + 16) >> 5;
if (mixer->treble_r<8) out_r = (out_r + (((int16_t)high_cut_iir(1, (float)out_r) * (8 - mixer->treble_r)) >> 1)) * (mixer->treble_r + 16) >> 5;
}
buffer[c] += out_l;
buffer[c + 1] += out_r;
}
sb->pos = 0;
sb->opl.pos = 0;
sb->dsp.pos = 0;
sb->emu8k.pos = 0;
}
void sb_pro_mixer_write(uint16_t addr, uint8_t val, void *p)
{
sb_t *sb = (sb_t *)p;
sb_mixer_t *mixer = &sb->mixer;
if (!(addr & 1))
mixer->index = val & 0xff;
else
{
mixer->regs[mixer->index] = val;
mixer->master_l = sb_att[(mixer->regs[0x22] >> 4) | 0x11];
mixer->master_r = sb_att[(mixer->regs[0x22] & 0xf) | 0x11];
mixer->voice_l = sb_att[(mixer->regs[0x04] >> 4) | 0x11];
mixer->voice_r = sb_att[(mixer->regs[0x04] & 0xf) | 0x11];
mixer->fm_l = sb_att[(mixer->regs[0x26] >> 4) | 0x11];
mixer->fm_r = sb_att[(mixer->regs[0x26] & 0xf) | 0x11];
mixer->cd_l = sb_att[(mixer->regs[0x28] >> 4) | 0x11];
mixer->cd_r = sb_att[(mixer->regs[0x28] & 0xf) | 0x11];
mixer->filter = !(mixer->regs[0xe] & 0x20);
mixer->bass_l = mixer->bass_r = 8;
mixer->treble_l = mixer->treble_r = 8;
sound_set_cd_volume(((uint32_t)mixer->master_l * (uint32_t)mixer->cd_l) / 65535,
((uint32_t)mixer->master_r * (uint32_t)mixer->cd_r) / 65535);
if (mixer->index == 0xe)
sb_dsp_set_stereo(&sb->dsp, val & 2);
}
}
uint8_t sb_pro_mixer_read(uint16_t addr, void *p)
{
sb_t *sb = (sb_t *)p;
sb_mixer_t *mixer = &sb->mixer;
if (!(addr & 1))
return mixer->index;
return mixer->regs[mixer->index];
}
void sb_16_mixer_write(uint16_t addr, uint8_t val, void *p)
{
sb_t *sb = (sb_t *)p;
sb_mixer_t *mixer = &sb->mixer;
if (!(addr & 1))
mixer->index = val;
else
{
mixer->regs[mixer->index] = val;
switch (mixer->index)
{
case 0x22:
mixer->regs[0x30] = ((mixer->regs[0x22] >> 4) | 0x11) << 3;
mixer->regs[0x31] = ((mixer->regs[0x22] & 0xf) | 0x11) << 3;
break;
case 0x04:
mixer->regs[0x32] = ((mixer->regs[0x04] >> 4) | 0x11) << 3;
mixer->regs[0x33] = ((mixer->regs[0x04] & 0xf) | 0x11) << 3;
break;
case 0x26:
mixer->regs[0x34] = ((mixer->regs[0x26] >> 4) | 0x11) << 3;
mixer->regs[0x35] = ((mixer->regs[0x26] & 0xf) | 0x11) << 3;
break;
case 0x28:
mixer->regs[0x36] = ((mixer->regs[0x28] >> 4) | 0x11) << 3;
mixer->regs[0x37] = ((mixer->regs[0x28] & 0xf) | 0x11) << 3;
break;
case 0x80:
if (val & 1) sb->dsp.sb_irqnum = 2;
if (val & 2) sb->dsp.sb_irqnum = 5;
if (val & 4) sb->dsp.sb_irqnum = 7;
if (val & 8) sb->dsp.sb_irqnum = 10;
case 0x81:
if (val & 1) sb->dsp.sb_8_dmanum = 0;
if (val & 2) sb->dsp.sb_8_dmanum = 1;
if (val & 8) sb->dsp.sb_8_dmanum = 3;
if (val & 0x20) sb->dsp.sb_16_dmanum = 5;
if (val & 0x40) sb->dsp.sb_16_dmanum = 6;
if (val & 0x80) sb->dsp.sb_16_dmanum = 7;
break;
}
mixer->master_l = sb_att[mixer->regs[0x30] >> 3];
mixer->master_r = sb_att[mixer->regs[0x31] >> 3];
mixer->voice_l = sb_att[mixer->regs[0x32] >> 3];
mixer->voice_r = sb_att[mixer->regs[0x33] >> 3];
mixer->fm_l = sb_att[mixer->regs[0x34] >> 3];
mixer->fm_r = sb_att[mixer->regs[0x35] >> 3];
mixer->cd_l = sb_att[mixer->regs[0x36] >> 3];
mixer->cd_r = sb_att[mixer->regs[0x37] >> 3];
mixer->bass_l = mixer->regs[0x46] >> 4;
mixer->bass_r = mixer->regs[0x47] >> 4;
mixer->treble_l = mixer->regs[0x44] >> 4;
mixer->treble_r = mixer->regs[0x45] >> 4;
mixer->filter = 0;
sound_set_cd_volume(((uint32_t)mixer->master_l * (uint32_t)mixer->cd_l) / 65535,
((uint32_t)mixer->master_r * (uint32_t)mixer->cd_r) / 65535);
}
}
uint8_t sb_16_mixer_read(uint16_t addr, void *p)
{
sb_t *sb = (sb_t *)p;
sb_mixer_t *mixer = &sb->mixer;
uint8_t temp = 0;
if (!(addr & 1))
return mixer->index;
switch (mixer->index)
{
case 0x80:
switch (sb->dsp.sb_irqnum)
{
case 2: return 1; /*IRQ 7*/
case 5: return 2; /*IRQ 7*/
case 7: return 4; /*IRQ 7*/
case 10: return 8; /*IRQ 7*/
}
break;
case 0x81:
switch (sb->dsp.sb_8_dmanum)
{
case 0:
temp = 1;
break;
case 1:
temp = 2;
break;
case 3:
temp = 8;
break;
default:
temp = 0;
break;
}
switch (sb->dsp.sb_16_dmanum)
{
case 5:
temp |= 0x20;
break;
case 6:
temp |= 0x40;
break;
case 7:
temp |= 0x80;
break;
default:
temp |= 0x00;
break;
}
return temp;
case 0x82:
return ((sb->dsp.sb_irq8) ? 1 : 0) | ((sb->dsp.sb_irq16) ? 2 : 0);
}
return mixer->regs[mixer->index];
}
void sb_mixer_init(sb_mixer_t *mixer)
{
mixer->master_l = mixer->master_r = 65535;
mixer->voice_l = mixer->voice_r = 65535;
mixer->fm_l = mixer->fm_r = 65535;
mixer->cd_l = mixer->cd_r = 65535;
mixer->bass_l = mixer->bass_r = 8;
mixer->treble_l = mixer->treble_r = 8;
mixer->filter = 1;
sound_set_cd_volume(((uint32_t)mixer->master_l * (uint32_t)mixer->cd_l) / 65535,
((uint32_t)mixer->master_r * (uint32_t)mixer->cd_r) / 65535);
}
static uint16_t sb_mcv_addr[8] = {0x200, 0x210, 0x220, 0x230, 0x240, 0x250, 0x260, 0x270};
uint8_t sb_mcv_read(int port, void *p)
{
sb_t *sb = (sb_t *)p;
pclog("sb_mcv_read: port=%04x\n", port);
return sb->pos_regs[port & 7];
}
void sb_mcv_write(int port, uint8_t val, void *p)
{
uint16_t addr;
sb_t *sb = (sb_t *)p;
if (port < 0x102)
return;
pclog("sb_mcv_write: port=%04x val=%02x\n", port, val);
addr = sb_mcv_addr[sb->pos_regs[4] & 7];
io_removehandler(addr+8, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl);
io_removehandler(0x0388, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl);
sb_dsp_setaddr(&sb->dsp, 0);
sb->pos_regs[port & 7] = val;
if (sb->pos_regs[2] & 1)
{
addr = sb_mcv_addr[sb->pos_regs[4] & 7];
io_sethandler(addr+8, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl);
io_sethandler(0x0388, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl);
sb_dsp_setaddr(&sb->dsp, addr);
}
}
static int sb_pro_mcv_irqs[4] = {7, 5, 3, 3};
uint8_t sb_pro_mcv_read(int port, void *p)
{
sb_t *sb = (sb_t *)p;
pclog("sb_pro_mcv_read: port=%04x\n", port);
return sb->pos_regs[port & 7];
}
void sb_pro_mcv_write(int port, uint8_t val, void *p)
{
uint16_t addr;
sb_t *sb = (sb_t *)p;
if (port < 0x102)
return;
pclog("sb_pro_mcv_write: port=%04x val=%02x\n", port, val);
addr = (sb->pos_regs[2] & 0x20) ? 0x220 : 0x240;
io_removehandler(addr+0, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl);
io_removehandler(addr+8, 0x0002, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl);
io_removehandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl);
io_removehandler(addr+4, 0x0002, sb_pro_mixer_read, NULL, NULL, sb_pro_mixer_write, NULL, NULL, sb);
sb_dsp_setaddr(&sb->dsp, 0);
sb->pos_regs[port & 7] = val;
if (sb->pos_regs[2] & 1)
{
addr = (sb->pos_regs[2] & 0x20) ? 0x220 : 0x240;
io_sethandler(addr+0, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl);
io_sethandler(addr+8, 0x0002, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl);
io_sethandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl);
io_sethandler(addr+4, 0x0002, sb_pro_mixer_read, NULL, NULL, sb_pro_mixer_write, NULL, NULL, sb);
sb_dsp_setaddr(&sb->dsp, addr);
}
sb_dsp_setirq(&sb->dsp, sb_pro_mcv_irqs[(sb->pos_regs[5] >> 4) & 3]);
sb_dsp_setdma8(&sb->dsp, sb->pos_regs[4] & 3);
}
void *sb_1_init()
{
sb_t *sb = malloc(sizeof(sb_t));
uint16_t addr = device_get_config_int("addr");
memset(sb, 0, sizeof(sb_t));
opl2_init(&sb->opl);
sb_dsp_init(&sb->dsp, SB1);
sb_dsp_setaddr(&sb->dsp, addr);
sb_dsp_setirq(&sb->dsp, device_get_config_int("irq"));
sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma"));
sb_mixer_init(&sb->mixer);
io_sethandler(addr+8, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl);
io_sethandler(0x0388, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl);
sound_add_handler(sb_get_buffer_opl2, sb);
return sb;
}
void *sb_15_init()
{
sb_t *sb = malloc(sizeof(sb_t));
uint16_t addr = device_get_config_int("addr");
memset(sb, 0, sizeof(sb_t));
opl2_init(&sb->opl);
sb_dsp_init(&sb->dsp, SB15);
sb_dsp_setaddr(&sb->dsp, addr);
sb_dsp_setirq(&sb->dsp, device_get_config_int("irq"));
sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma"));
sb_mixer_init(&sb->mixer);
io_sethandler(addr+8, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl);
io_sethandler(0x0388, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl);
sound_add_handler(sb_get_buffer_opl2, sb);
return sb;
}
void *sb_mcv_init()
{
sb_t *sb = malloc(sizeof(sb_t));
memset(sb, 0, sizeof(sb_t));
opl2_init(&sb->opl);
sb_dsp_init(&sb->dsp, SB15);
sb_dsp_setaddr(&sb->dsp, 0);
sb_dsp_setirq(&sb->dsp, device_get_config_int("irq"));
sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma"));
sb_mixer_init(&sb->mixer);
sound_add_handler(sb_get_buffer_opl2, sb);
mca_add(sb_mcv_read, sb_mcv_write, sb);
sb->pos_regs[0] = 0x84;
sb->pos_regs[1] = 0x50;
return sb;
}
void *sb_2_init()
{
sb_t *sb = malloc(sizeof(sb_t));
uint16_t addr = device_get_config_int("addr");
memset(sb, 0, sizeof(sb_t));
opl2_init(&sb->opl);
sb_dsp_init(&sb->dsp, SB2);
sb_dsp_setaddr(&sb->dsp, addr);
sb_dsp_setirq(&sb->dsp, device_get_config_int("irq"));
sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma"));
sb_mixer_init(&sb->mixer);
io_sethandler(addr+8, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl);
io_sethandler(0x0388, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl);
sound_add_handler(sb_get_buffer_opl2, sb);
return sb;
}
void *sb_pro_v1_init()
{
sb_t *sb = malloc(sizeof(sb_t));
uint16_t addr = device_get_config_int("addr");
memset(sb, 0, sizeof(sb_t));
opl2_init(&sb->opl);
sb_dsp_init(&sb->dsp, SBPRO);
sb_dsp_setaddr(&sb->dsp, addr);
sb_dsp_setirq(&sb->dsp, device_get_config_int("irq"));
sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma"));
sb_mixer_init(&sb->mixer);
io_sethandler(addr+0, 0x0002, opl2_l_read, NULL, NULL, opl2_l_write, NULL, NULL, &sb->opl);
io_sethandler(addr+2, 0x0002, opl2_r_read, NULL, NULL, opl2_r_write, NULL, NULL, &sb->opl);
io_sethandler(addr+8, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl);
io_sethandler(0x0388, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl);
io_sethandler(addr+4, 0x0002, sb_pro_mixer_read, NULL, NULL, sb_pro_mixer_write, NULL, NULL, sb);
sound_add_handler(sb_get_buffer_opl2, sb);
sb->mixer.regs[0x22] = 0xff;
sb->mixer.regs[0x04] = 0xff;
sb->mixer.regs[0x26] = 0xff;
sb->mixer.regs[0x28] = 0xff;
sb->mixer.regs[0xe] = 0;
return sb;
}
void *sb_pro_v2_init()
{
sb_t *sb = malloc(sizeof(sb_t));
uint16_t addr = device_get_config_int("addr");
memset(sb, 0, sizeof(sb_t));
opl3_init(&sb->opl);
sb_dsp_init(&sb->dsp, SBPRO2);
sb_dsp_setaddr(&sb->dsp, addr);
sb_dsp_setirq(&sb->dsp, device_get_config_int("irq"));
sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma"));
sb_mixer_init(&sb->mixer);
io_sethandler(addr+0, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl);
io_sethandler(addr+8, 0x0002, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl);
io_sethandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl);
io_sethandler(addr+4, 0x0002, sb_pro_mixer_read, NULL, NULL, sb_pro_mixer_write, NULL, NULL, sb);
sound_add_handler(sb_get_buffer_opl3, sb);
sb->mixer.regs[0x22] = 0xff;
sb->mixer.regs[0x04] = 0xff;
sb->mixer.regs[0x26] = 0xff;
sb->mixer.regs[0x28] = 0xff;
sb->mixer.regs[0xe] = 0;
return sb;
}
void *sb_pro_mcv_init()
{
sb_t *sb = malloc(sizeof(sb_t));
memset(sb, 0, sizeof(sb_t));
opl3_init(&sb->opl);
sb_dsp_init(&sb->dsp, SBPRO2);
/*sb_dsp_setaddr(&sb->dsp, addr);
sb_dsp_setirq(&sb->dsp, device_get_config_int("irq"));
sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma"));*/
sb_mixer_init(&sb->mixer);
io_sethandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl);
sound_add_handler(sb_get_buffer_opl3, sb);
sb->mixer.regs[0x22] = 0xff;
sb->mixer.regs[0x04] = 0xff;
sb->mixer.regs[0x26] = 0xff;
sb->mixer.regs[0xe] = 0;
mca_add(sb_pro_mcv_read, sb_pro_mcv_write, sb);
sb->pos_regs[0] = 0x03;
sb->pos_regs[1] = 0x51;
return sb;
}
void *sb_16_init()
{
sb_t *sb = malloc(sizeof(sb_t));
uint16_t addr = device_get_config_int("addr");
memset(sb, 0, sizeof(sb_t));
opl3_init(&sb->opl);
sb_dsp_init(&sb->dsp, SB16);
sb_dsp_setaddr(&sb->dsp, addr);
sb_dsp_setirq(&sb->dsp, device_get_config_int("irq"));
sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma"));
sb_dsp_setdma16(&sb->dsp, device_get_config_int("dma16"));
sb_mixer_init(&sb->mixer);
io_sethandler(addr + 0, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl);
io_sethandler(addr + 8, 0x0002, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl);
io_sethandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl);
io_sethandler(addr + 4, 0x0002, sb_16_mixer_read, NULL, NULL, sb_16_mixer_write, NULL, NULL, sb);
sound_add_handler(sb_get_buffer_opl3, sb);
mpu401_init(&sb->mpu, device_get_config_int("addr401"), device_get_config_int("irq401"), device_get_config_int("mode401"));
sb->mixer.regs[0x30] = 31 << 3;
sb->mixer.regs[0x31] = 31 << 3;
sb->mixer.regs[0x32] = 31 << 3;
sb->mixer.regs[0x33] = 31 << 3;
sb->mixer.regs[0x34] = 31 << 3;
sb->mixer.regs[0x35] = 31 << 3;
sb->mixer.regs[0x36] = 31 << 3;
sb->mixer.regs[0x37] = 31 << 3;
sb->mixer.regs[0x44] = 8 << 4;
sb->mixer.regs[0x45] = 8 << 4;
sb->mixer.regs[0x46] = 8 << 4;
sb->mixer.regs[0x47] = 8 << 4;
sb->mixer.regs[0x22] = (sb->mixer.regs[0x30] & 0xf0) | (sb->mixer.regs[0x31] >> 4);
sb->mixer.regs[0x04] = (sb->mixer.regs[0x32] & 0xf0) | (sb->mixer.regs[0x33] >> 4);
sb->mixer.regs[0x26] = (sb->mixer.regs[0x34] & 0xf0) | (sb->mixer.regs[0x35] >> 4);
sb->mixer.regs[0x28] = (sb->mixer.regs[0x36] & 0xf0) | (sb->mixer.regs[0x37] >> 4);
return sb;
}
int sb_awe32_available()
{
return rom_present(L"roms/awe32.raw");
}
void *sb_awe32_init()
{
sb_t *sb = malloc(sizeof(sb_t));
uint16_t addr = device_get_config_int("addr");
int onboard_ram = device_get_config_int("onboard_ram");
memset(sb, 0, sizeof(sb_t));
opl3_init(&sb->opl);
sb_dsp_init(&sb->dsp, SB16 + 1);
sb_dsp_setaddr(&sb->dsp, addr);
sb_dsp_setirq(&sb->dsp, device_get_config_int("irq"));
sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma"));
sb_dsp_setdma16(&sb->dsp, device_get_config_int("dma16"));
sb_mixer_init(&sb->mixer);
io_sethandler(addr + 0, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl);
io_sethandler(addr + 8, 0x0002, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl);
io_sethandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl);
io_sethandler(addr + 4, 0x0002, sb_16_mixer_read, NULL, NULL, sb_16_mixer_write, NULL, NULL, sb);
sound_add_handler(sb_get_buffer_emu8k, sb);
mpu401_init(&sb->mpu, device_get_config_int("addr401"), device_get_config_int("irq401"), device_get_config_int("mode401"));
emu8k_init(&sb->emu8k, onboard_ram);
sb->mixer.regs[0x30] = 31 << 3;
sb->mixer.regs[0x31] = 31 << 3;
sb->mixer.regs[0x32] = 31 << 3;
sb->mixer.regs[0x33] = 31 << 3;
sb->mixer.regs[0x34] = 31 << 3;
sb->mixer.regs[0x35] = 31 << 3;
sb->mixer.regs[0x36] = 31 << 3;
sb->mixer.regs[0x37] = 31 << 3;
sb->mixer.regs[0x44] = 8 << 4;
sb->mixer.regs[0x45] = 8 << 4;
sb->mixer.regs[0x46] = 8 << 4;
sb->mixer.regs[0x47] = 8 << 4;
sb->mixer.regs[0x22] = (sb->mixer.regs[0x30] & 0xf0) | (sb->mixer.regs[0x31] >> 4);
sb->mixer.regs[0x04] = (sb->mixer.regs[0x32] & 0xf0) | (sb->mixer.regs[0x33] >> 4);
sb->mixer.regs[0x26] = (sb->mixer.regs[0x34] & 0xf0) | (sb->mixer.regs[0x35] >> 4);
sb->mixer.regs[0x28] = (sb->mixer.regs[0x36] & 0xf0) | (sb->mixer.regs[0x37] >> 4);
return sb;
}
void sb_close(void *p)
{
sb_t *sb = (sb_t *)p;
free(sb);
}
void sb_awe32_close(void *p)
{
sb_t *sb = (sb_t *)p;
emu8k_close(&sb->emu8k);
free(sb);
}
void sb_speed_changed(void *p)
{
sb_t *sb = (sb_t *)p;
sb_dsp_speed_changed(&sb->dsp);
}
void sb_add_status_info(char *s, int max_len, void *p)
{
sb_t *sb = (sb_t *)p;
sb_dsp_add_status_info(s, max_len, &sb->dsp);
}
static device_config_t sb_config[] =
{
{
"addr", "Address", CONFIG_SELECTION, "", 0x220,
{
{
"0x220", 0x220
},
{
"0x240", 0x240
},
{
""
}
}
},
{
"irq", "IRQ", CONFIG_SELECTION, "", 7,
{
{
"IRQ 2", 2
},
{
"IRQ 3", 3
},
{
"IRQ 5", 5
},
{
"IRQ 7", 7
},
{
""
}
}
},
{
"dma", "DMA", CONFIG_SELECTION, "", 1,
{
{
"DMA 1", 1
},
{
"DMA 3", 3
},
{
""
}
}
},
{
"midi", "MIDI out device", CONFIG_MIDI, "", 0
},
{
"", "", -1
}
};
static device_config_t sb_mcv_config[] =
{
{
"irq", "IRQ", CONFIG_SELECTION, "", 7,
{
{
"IRQ 3", 3
},
{
"IRQ 5", 5
},
{
"IRQ 7", 7
},
{
""
}
}
},
{
"dma", "DMA", CONFIG_SELECTION, "", 1,
{
{
"DMA 1", 1
},
{
"DMA 3", 3
},
{
""
}
}
},
{
"midi", "MIDI out device", CONFIG_MIDI, "", 0
},
{
"", "", -1
}
};
static device_config_t sb_pro_config[] =
{
{
"addr", "Address", CONFIG_SELECTION, "", 0x220,
{
{
"0x220", 0x220
},
{
"0x240", 0x240
},
{
""
}
}
},
{
"irq", "IRQ", CONFIG_SELECTION, "", 7,
{
{
"IRQ 2", 2
},
{
"IRQ 5", 5
},
{
"IRQ 7", 7
},
{
"IRQ 10", 10
},
{
""
}
}
},
{
"dma", "DMA", CONFIG_SELECTION, "", 1,
{
{
"DMA 1", 1
},
{
"DMA 3", 3
},
{
""
}
}
},
{
"midi", "MIDI out device", CONFIG_MIDI, "", 0
},
{
"", "", -1
}
};
static device_config_t sb_16_config[] =
{
{
"addr", "Address", CONFIG_SELECTION, "", 0x220,
{
{
"0x220", 0x220
},
{
"0x240", 0x240
},
{
"0x260", 0x260
},
{
"0x280", 0x280
},
{
""
}
}
},
{
"addr401", "MPU-401 Address", CONFIG_SELECTION, "", 0x330,
{
{
"0x300", 0x300
},
{
"0x330", 0x330
},
{
""
}
}
},
{
"irq", "IRQ", CONFIG_SELECTION, "", 5,
{
{
"IRQ 2", 2
},
{
"IRQ 5", 5
},
{
"IRQ 7", 7
},
{
"IRQ 10", 10
},
{
""
}
}
},
{
"irq401", "MPU-401 IRQ", CONFIG_SELECTION, "", 9,
{
{
"IRQ 9", 9
},
{
"IRQ 3", 3
},
{
"IRQ 4", 4
},
{
"IRQ 5", 5
},
{
"IRQ 7", 7
},
{
"IRQ 10", 10
},
{
""
}
}
},
{
"dma", "Low DMA channel", CONFIG_SELECTION, "", 1,
{
{
"DMA 0", 0
},
{
"DMA 1", 1
},
{
"DMA 3", 3
},
{
""
}
}
},
{
"dma16", "High DMA channel", CONFIG_SELECTION, "", 5,
{
{
"DMA 5", 5
},
{
"DMA 6", 6
},
{
"DMA 7", 7
},
{
""
}
}
},
{
"midi", "MIDI out device", CONFIG_MIDI, "", 0
},
{
"mode401", "MPU-401 mode", CONFIG_SELECTION, "", 1,
{
{
"UART", M_UART
},
{
"Intelligent", M_INTELLIGENT
},
{
""
}
}
},
{
"", "", -1
}
};
static device_config_t sb_awe32_config[] =
{
{
"addr", "Address", CONFIG_SELECTION, "", 0x220,
{
{
"0x220", 0x220
},
{
"0x240", 0x240
},
{
"0x260", 0x260
},
{
"0x280", 0x280
},
{
""
}
}
},
{
"addr401", "MPU-401 Address", CONFIG_SELECTION, "", 0x330,
{
{
"0x300", 0x300
},
{
"0x330", 0x330
},
{
""
}
}
},
{
"irq", "IRQ", CONFIG_SELECTION, "", 5,
{
{
"IRQ 2", 2
},
{
"IRQ 5", 5
},
{
"IRQ 7", 7
},
{
"IRQ 10", 10
},
{
""
}
}
},
{
"irq401", "MPU-401 IRQ", CONFIG_SELECTION, "", 9,
{
{
"IRQ 9", 9
},
{
"IRQ 3", 3
},
{
"IRQ 4", 4
},
{
"IRQ 5", 5
},
{
"IRQ 7", 7
},
{
"IRQ 10", 10
},
{
""
}
}
},
{
"dma", "Low DMA channel", CONFIG_SELECTION, "", 1,
{
{
"DMA 0", 0
},
{
"DMA 1", 1
},
{
"DMA 3", 3
},
{
""
}
}
},
{
"dma16", "High DMA channel", CONFIG_SELECTION, "", 5,
{
{
"DMA 5", 5
},
{
"DMA 6", 6
},
{
"DMA 7", 7
},
{
""
}
}
},
{
"midi", "MIDI out device", CONFIG_MIDI, "", 0
},
{
"mode401", "MPU-401 mode", CONFIG_SELECTION, "", 1,
{
{
"UART", M_UART
},
{
"Intelligent", M_INTELLIGENT
},
{
""
}
}
},
{
"onboard_ram", "Onboard RAM", CONFIG_SELECTION, "", 512,
{
{
"None", 0
},
{
"512 KB", 512
},
{
"2 MB", 2048
},
{
"8 MB", 8192
},
{
"28 MB", 28*1024
},
{
""
}
}
},
{
"", "", -1
}
};
device_t sb_1_device =
{
"Sound Blaster v1.0",
0,
sb_1_init,
sb_close,
NULL,
sb_speed_changed,
NULL,
sb_add_status_info,
sb_config
};
device_t sb_15_device =
{
"Sound Blaster v1.5",
0,
sb_15_init,
sb_close,
NULL,
sb_speed_changed,
NULL,
sb_add_status_info,
sb_config
};
device_t sb_mcv_device =
{
"Sound Blaster MCV",
DEVICE_MCA,
sb_mcv_init,
sb_close,
NULL,
sb_speed_changed,
NULL,
sb_add_status_info,
sb_mcv_config
};
device_t sb_2_device =
{
"Sound Blaster v2.0",
0,
sb_2_init,
sb_close,
NULL,
sb_speed_changed,
NULL,
sb_add_status_info,
sb_config
};
device_t sb_pro_v1_device =
{
"Sound Blaster Pro v1",
0,
sb_pro_v1_init,
sb_close,
NULL,
sb_speed_changed,
NULL,
sb_add_status_info,
sb_pro_config
};
device_t sb_pro_v2_device =
{
"Sound Blaster Pro v2",
0,
sb_pro_v2_init,
sb_close,
NULL,
sb_speed_changed,
NULL,
sb_add_status_info,
sb_pro_config
};
device_t sb_pro_mcv_device =
{
"Sound Blaster Pro MCV",
DEVICE_MCA,
sb_pro_mcv_init,
sb_close,
NULL,
sb_speed_changed,
NULL,
sb_add_status_info,
NULL
};
device_t sb_16_device =
{
"Sound Blaster 16",
0,
sb_16_init,
sb_close,
NULL,
sb_speed_changed,
NULL,
sb_add_status_info,
sb_16_config
};
device_t sb_awe32_device =
{
"Sound Blaster AWE32",
0,
sb_awe32_init,
sb_close,
sb_awe32_available,
sb_speed_changed,
NULL,
sb_add_status_info,
sb_awe32_config
};