#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#define _USE_MATH_DEFINES
#include <math.h>
#define HAVE_STDARG_H
#include <86box/86box.h>
#include <86box/device.h>
#include <86box/io.h>
#include <86box/nmi.h>
#include <86box/mem.h>
#include <86box/pci.h>
#include <86box/timer.h>
#include <86box/sound.h>
#include <86box/midi.h>
#include <86box/snd_mpu401.h>


#define N 16

#define ES1371_NCoef 91

static float low_fir_es1371_coef[ES1371_NCoef];

typedef struct {
    mpu_t mpu;

    uint8_t pci_command, pci_serr;

    uint32_t base_addr;

    uint8_t int_line;

    uint16_t pmcsr;

    uint32_t int_ctrl;
    uint32_t int_status;

    uint32_t legacy_ctrl;

    int mem_page;

    uint32_t si_cr;

    uint32_t sr_cir;
    uint16_t sr_ram[128];

    uint8_t uart_ctrl;
    uint8_t uart_status;

    uint16_t codec_regs[128];
    uint32_t codec_ctrl;

    struct {
	uint32_t addr, addr_latch;
	uint16_t count, size;

	uint16_t samp_ct;
	int curr_samp_ct;

	pc_timer_t timer;
	uint64_t latch;

	uint32_t vf, ac;

	int16_t buffer_l[64], buffer_r[64];
	int buffer_pos, buffer_pos_end;

	int filtered_l[32], filtered_r[32];
	int f_pos;

	int16_t out_l, out_r;

	int32_t vol_l, vol_r;
    } dac[2], adc;

    int64_t dac_latch, dac_time;

    int master_vol_l, master_vol_r;
    int cd_vol_l, cd_vol_r;

    int card;

    int pos;
    int16_t buffer[SOUNDBUFLEN * 2];

    int type;
} es1371_t;


#define LEGACY_SB_ADDR			(1<<29)
#define LEGACY_SSCAPE_ADDR_SHIFT	27
#define LEGACY_CODEC_ADDR_SHIFT		25
#define LEGACY_FORCE_IRQ		(1<<24)
#define LEGACY_CAPTURE_SLAVE_DMA	(1<<23)
#define LEGACY_CAPTURE_SLAVE_PIC	(1<<22)
#define LEGACY_CAPTURE_MASTER_DMA	(1<<21)
#define LEGACY_CAPTURE_MASTER_PIC	(1<<20)
#define LEGACY_CAPTURE_ADLIB		(1<<19)
#define LEGACY_CAPTURE_SB		(1<<18)
#define LEGACY_CAPTURE_CODEC		(1<<17)
#define LEGACY_CAPTURE_SSCAPE		(1<<16)
#define LEGACY_EVENT_SSCAPE		(0<<8)
#define LEGACY_EVENT_CODEC		(1<<8)
#define LEGACY_EVENT_SB			(2<<8)
#define LEGACY_EVENT_ADLIB		(3<<8)
#define LEGACY_EVENT_MASTER_PIC		(4<<8)
#define LEGACY_EVENT_MASTER_DMA		(5<<8)
#define LEGACY_EVENT_SLAVE_PIC		(6<<8)
#define LEGACY_EVENT_SLAVE_DMA		(7<<8)
#define LEGACY_EVENT_MASK		(7<<8)
#define LEGACY_EVENT_ADDR_SHIFT		3
#define LEGACY_EVENT_ADDR_MASK		(0x1f<<3)
#define LEGACY_EVENT_TYPE_RW		(1<<2)
#define LEGACY_INT			(1<<0)

#define SRC_RAM_WE			(1<<24)

#define CODEC_READ			(1<<23)
#define CODEC_READY			(1<<31)

#define INT_DAC1_EN			(1<<6)
#define INT_DAC2_EN			(1<<5)
#define INT_UART_EN			(1<<3)

#define SI_P2_INTR_EN			(1<<9)
#define SI_P1_INTR_EN			(1<<8)

#define INT_STATUS_INTR			(1<<31)
#define INT_STATUS_UART			(1<<3)
#define INT_STATUS_DAC1			(1<<2)
#define INT_STATUS_DAC2			(1<<1)

#define UART_CTRL_RXINTEN		(1<<7)
#define UART_CTRL_TXINTEN		(1<<5)

#define UART_STATUS_RXINT		(1<<7)
#define UART_STATUS_TXINT		(1<<2)
#define UART_STATUS_TXRDY		(1<<1)
#define UART_STATUS_RXRDY		(1<<0)

#define FORMAT_MONO_8			0
#define FORMAT_STEREO_8			1
#define FORMAT_MONO_16			2
#define FORMAT_STEREO_16		3

const int32_t codec_attn[]= {
	25,32,41,51,65,82,103,130,164,206,260,327,412,519,653,
	822,1036,1304,1641,2067,2602,3276,4125,5192,6537,8230,10362,13044,
	16422,20674,26027,32767
};

static void es1371_fetch(es1371_t *es1371, int dac_nr);
static void update_legacy(es1371_t *es1371, uint32_t old_legacy_ctrl);

#ifdef ENABLE_AUDIOPCI_LOG
int audiopci_do_log = ENABLE_AUDIOPCI_LOG;


static void
audiopci_log(const char *fmt, ...)
{
    va_list ap;

    if (audiopci_do_log) {
	va_start(ap, fmt);
	pclog_ex(fmt, ap);
	va_end(ap);
    }
}
#else
#define audiopci_log(fmt, ...)
#endif


static void es1371_update_irqs(es1371_t *es1371)
{
	int irq = 0;
	
	if ((es1371->int_status & INT_STATUS_DAC1) && (es1371->si_cr & SI_P1_INTR_EN))
		irq = 1;
	if ((es1371->int_status & INT_STATUS_DAC2) && (es1371->si_cr & SI_P2_INTR_EN)) {
		irq = 1;
	}
	/*MIDI input is unsupported for now*/
	if ((es1371->int_status & INT_STATUS_UART) && (es1371->uart_status & UART_STATUS_TXINT)) {
		irq = 1;
	}

	if (irq)
		es1371->int_status |= INT_STATUS_INTR;
	else
		es1371->int_status &= ~INT_STATUS_INTR;

	if (es1371->legacy_ctrl & LEGACY_FORCE_IRQ)
		irq = 1;
	
	if (irq)
	{
		pci_set_irq(es1371->card, PCI_INTA);
//		audiopci_log("Raise IRQ\n");
	}
	else
	{
		pci_clear_irq(es1371->card, PCI_INTA);
//		audiopci_log("Drop IRQ\n");
	}
}

static uint8_t es1371_inb(uint16_t port, void *p)
{
	es1371_t *es1371 = (es1371_t *)p;
	uint8_t ret = 0;
	
	switch (port & 0x3f)
	{
		case 0x00:
		ret = es1371->int_ctrl & 0xff;
		break;
		case 0x01:
		ret = (es1371->int_ctrl >> 8) & 0xff;
		break;
		case 0x02:
		ret = (es1371->int_ctrl >> 16) & 0xff;
		break;
		case 0x03:
		ret = (es1371->int_ctrl >> 24) & 0xff;
		break;

		case 0x04:
		ret = es1371->int_status & 0xff;
		break;
		case 0x05:
		ret = (es1371->int_status >> 8) & 0xff;
		break;
		case 0x06:
		ret = (es1371->int_status >> 16) & 0xff;
		break;
		case 0x07:
		ret = (es1371->int_status >> 24) & 0xff;
		break;
		
		case 0x09:
		ret = es1371->uart_status & 0xc7;
		audiopci_log("ES1371 UART Status = %02x\n", es1371->uart_status);
		break;
		
		case 0x0c:
		ret = es1371->mem_page;
		break;
		
		case 0x1a:
		ret = es1371->legacy_ctrl >> 16;
		break;
		case 0x1b:
		ret = es1371->legacy_ctrl >> 24;
		break;
		
		case 0x20:
		ret = es1371->si_cr & 0xff;
		break;
		case 0x21:
		ret = es1371->si_cr >> 8;
		break;
		case 0x22:
		ret = (es1371->si_cr >> 16) | 0x80;
		break;
		case 0x23:		
		ret = 0xff;
		break;
		
		default:
		audiopci_log("Bad es1371_inb: port=%04x\n", port);
	}

	audiopci_log("es1371_inb: port=%04x ret=%02x\n", port, ret);
//	output = 3;
	return ret;
}
static uint16_t es1371_inw(uint16_t port, void *p)
{
	es1371_t *es1371 = (es1371_t *)p;
	uint16_t ret = 0;
	
	switch (port & 0x3e)
	{
		case 0x00:
		ret = es1371->int_ctrl & 0xffff;
		break;
		case 0x02:
		ret = (es1371->int_ctrl >> 16) & 0xffff;
		break;

		case 0x18:
		ret = es1371->legacy_ctrl & 0xffff;
//		audiopci_log("Read legacy ctrl %04x\n", ret);
		break;

		case 0x26:
		ret = es1371->dac[0].curr_samp_ct;
		break;

		case 0x2a:
		ret = es1371->dac[1].curr_samp_ct;
		break;
		
		case 0x36:
		switch (es1371->mem_page)
		{
			case 0xc:
			ret = es1371->dac[0].count;
			break;
			
			default:
			audiopci_log("Bad es1371_inw: mem_page=%x port=%04x\n", es1371->mem_page, port);
		}
		break;

		case 0x3e:
		switch (es1371->mem_page)
		{
			case 0xc:
			ret = es1371->dac[1].count;
			break;
			
			default:
			audiopci_log("Bad es1371_inw: mem_page=%x port=%04x\n", es1371->mem_page, port);
		}
		break;

		default:
		audiopci_log("Bad es1371_inw: port=%04x\n", port);
	}

//	audiopci_log("es1371_inw: port=%04x ret=%04x %04x:%08x\n", port, ret, CS,cpu_state.pc);
	return ret;
}
static uint32_t es1371_inl(uint16_t port, void *p)
{
	es1371_t *es1371 = (es1371_t *)p;
	uint32_t ret = 0;
	
	switch (port & 0x3c)
	{
		case 0x00:
		ret = es1371->int_ctrl;
		break;
		case 0x04:
		ret = es1371->int_status;
		break;
		
		case 0x10:
		ret = es1371->sr_cir & ~0xffff;
		ret |= es1371->sr_ram[es1371->sr_cir >> 25];
		break;
		
		case 0x14:
		ret = es1371->codec_ctrl & 0x00ff0000;
		ret |= es1371->codec_regs[(es1371->codec_ctrl >> 16) & 0x7f];
		if (((es1371->codec_ctrl >> 16) & 0x7f) == 0x26)
			ret |= 0x0f;
		ret |= CODEC_READY;
		break;

		case 0x30:
		switch (es1371->mem_page) {
			case 0xe: case 0xf:
			audiopci_log("ES1371 0x30 read UART FIFO: val = %02x\n", ret & 0xff);
			break;
		}
		break;

		case 0x34:
		switch (es1371->mem_page) {
			case 0xc:
			ret = es1371->dac[0].size | (es1371->dac[0].count << 16);
			break;
			
			case 0xd:
			ret = es1371->adc.size | (es1371->adc.count << 16);
			break;

			case 0xe: case 0xf:
			audiopci_log("ES1371 0x34 read UART FIFO: val = %02x\n", ret & 0xff);
			break;

			default:
			audiopci_log("Bad es1371_inl: mem_page=%x port=%04x\n", es1371->mem_page, port);
		}
		break;

		case 0x38:
		switch (es1371->mem_page) {
			case 0xe: case 0xf:
			audiopci_log("ES1371 0x38 read UART FIFO: val = %02x\n", ret & 0xff);
			break;
		}
		break;		

		case 0x3c:
		switch (es1371->mem_page) {
			case 0xc:
			ret = es1371->dac[1].size | (es1371->dac[1].count << 16);
			break;
			
			case 0xe: case 0xf:
			audiopci_log("ES1371 0x3c read UART FIFO: val = %02x\n", ret & 0xff);
			break;			

			default:
			audiopci_log("Bad es1371_inl: mem_page=%x port=%04x\n", es1371->mem_page, port);
		}
		break;
		
		default:
		audiopci_log("Bad es1371_inl: port=%04x\n", port);
	}

	audiopci_log("es1371_inl: port=%04x ret=%08x\n", port, ret);
	return ret;
}

static void es1371_outb(uint16_t port, uint8_t val, void *p)
{
	es1371_t *es1371 = (es1371_t *)p;
        uint32_t old_legacy_ctrl;

	audiopci_log("es1371_outb: port=%04x val=%02x\n", port, val);
	switch (port & 0x3f)
	{
		case 0x00:
		if (!(es1371->int_ctrl & INT_DAC1_EN) && (val & INT_DAC1_EN))
		{
			es1371->dac[0].addr = es1371->dac[0].addr_latch;
			es1371->dac[0].buffer_pos = 0;
			es1371->dac[0].buffer_pos_end = 0;
			es1371_fetch(es1371, 0);
		}
		if (!(es1371->int_ctrl & INT_DAC2_EN) && (val & INT_DAC2_EN))
		{
			es1371->dac[1].addr = es1371->dac[1].addr_latch;
			es1371->dac[1].buffer_pos = 0;
			es1371->dac[1].buffer_pos_end = 0;
			es1371_fetch(es1371, 1);
		}
		es1371->int_ctrl = (es1371->int_ctrl & 0xffffff00) | val;
		break;
		case 0x01:
		es1371->int_ctrl = (es1371->int_ctrl & 0xffff00ff) | (val << 8);
		break;
		case 0x02:
		es1371->int_ctrl = (es1371->int_ctrl & 0xff00ffff) | (val << 16);
		break;
		case 0x03:
		es1371->int_ctrl = (es1371->int_ctrl & 0x00ffffff) | (val << 24);
		break;
		
		case 0x08:
		midi_raw_out_byte(val);
		break;
		
		case 0x09:
		es1371->uart_ctrl = val & 0xe3;
		audiopci_log("ES1371 UART Cntrl = %02x\n", es1371->uart_ctrl);
		break;
		
		case 0x0c:
		es1371->mem_page = val & 0xf;
		break;

		case 0x18:
		es1371->legacy_ctrl |= LEGACY_INT;
		nmi = 0;
		break;
		case 0x1a:
                old_legacy_ctrl = es1371->legacy_ctrl;
		es1371->legacy_ctrl = (es1371->legacy_ctrl & 0xff00ffff) | (val << 16);
		update_legacy(es1371, old_legacy_ctrl);
		break;
		case 0x1b:
                old_legacy_ctrl = es1371->legacy_ctrl;
		es1371->legacy_ctrl = (es1371->legacy_ctrl & 0x00ffffff) | (val << 24);
		es1371_update_irqs(es1371);
//		output = 3;
		update_legacy(es1371, old_legacy_ctrl);
		break;
		
		case 0x20:
		es1371->si_cr = (es1371->si_cr & 0xffff00) | val;
		break;
		case 0x21:
		es1371->si_cr = (es1371->si_cr & 0xff00ff) | (val << 8);
		if (!(es1371->si_cr & SI_P1_INTR_EN))
			es1371->int_status &= ~INT_STATUS_DAC1;
		if (!(es1371->si_cr & SI_P2_INTR_EN))
			es1371->int_status &= ~INT_STATUS_DAC2;
		es1371_update_irqs(es1371);
		break;
		case 0x22:
		es1371->si_cr = (es1371->si_cr & 0x00ffff) | (val << 16);
		break;
		
		default:
		audiopci_log("Bad es1371_outb: port=%04x val=%02x\n", port, val);
	}
}
static void es1371_outw(uint16_t port, uint16_t val, void *p)
{
	es1371_t *es1371 = (es1371_t *)p;

//	audiopci_log("es1371_outw: port=%04x val=%04x\n", port, val);
	switch (port & 0x3f)
	{
		case 0x0c:
		es1371->mem_page = val & 0xf;
		break;

		case 0x24:
		es1371->dac[0].samp_ct = val;
		break;

		case 0x28:
		es1371->dac[1].samp_ct = val;
		break;
		
		default:
		audiopci_log("Bad es1371_outw: port=%04x val=%04x\n", port, val);
	}
}
static void es1371_outl(uint16_t port, uint32_t val, void *p)
{
	es1371_t *es1371 = (es1371_t *)p;

	audiopci_log("es1371_outl: port=%04x val=%08x\n", port, val);
	switch (port & 0x3f)
	{
		case 0x04:
		break;
		
		case 0x0c:
		es1371->mem_page = val & 0xf;
		break;

		case 0x10:
		es1371->sr_cir = val;
		if (es1371->sr_cir & SRC_RAM_WE)
		{
//			audiopci_log("Write SR RAM %02x %04x\n", es1371->sr_cir >> 25, val & 0xffff);
			es1371->sr_ram[es1371->sr_cir >> 25] = val & 0xffff;
			switch (es1371->sr_cir >> 25)
			{
				case 0x71:
				es1371->dac[0].vf = (es1371->dac[0].vf & ~0x1f8000) | ((val & 0xfc00) << 5);
				es1371->dac[0].ac = (es1371->dac[0].ac & ~0x7f8000) | ((val & 0x00ff) << 15);
                                es1371->dac[0].f_pos = 0;
				break;
				case 0x72:
				es1371->dac[0].ac = (es1371->dac[0].ac & ~0x7fff) | (val & 0x7fff);
				break;				
				case 0x73:
				es1371->dac[0].vf = (es1371->dac[0].vf & ~0x7fff) | (val & 0x7fff);
				break;

				case 0x75:
				es1371->dac[1].vf = (es1371->dac[1].vf & ~0x1f8000) | ((val & 0xfc00) << 5);
				es1371->dac[1].ac = (es1371->dac[1].ac & ~0x7f8000) | ((val & 0x00ff) << 15);
                                es1371->dac[1].f_pos = 0;
				break;
				case 0x76:
				es1371->dac[1].ac = (es1371->dac[1].ac & ~0x7fff) | (val & 0x7fff);
				break;				
				case 0x77:
				es1371->dac[1].vf = (es1371->dac[1].vf & ~0x7fff) | (val & 0x7fff);
				break;
				
				case 0x7c:
				es1371->dac[0].vol_l = (int32_t)(int16_t)(val & 0xffff);
				break;
				case 0x7d:
				es1371->dac[0].vol_r = (int32_t)(int16_t)(val & 0xffff);
				break;
				case 0x7e:
				es1371->dac[1].vol_l = (int32_t)(int16_t)(val & 0xffff);
				break;
				case 0x7f:
				es1371->dac[1].vol_r = (int32_t)(int16_t)(val & 0xffff);
				break;
			}
		}
		break;

		case 0x14:
		es1371->codec_ctrl = val;
		if (!(val & CODEC_READ))
		{
//			audiopci_log("Write codec %02x %04x\n", (val >> 16) & 0x7f, val & 0xffff);
			if ((((val >> 16) & 0x7f) != 0x7c) && (((val >> 16) & 0x7f) != 0x7e))
				es1371->codec_regs[(val >> 16) & 0x7f] = val & 0xffff;
			switch ((val >> 16) & 0x7f)
			{
				case 0x02: /*Master volume*/
				if (val & 0x8000)
					es1371->master_vol_l = es1371->master_vol_r = 0;
				else
				{
					if (val & 0x2000)
						es1371->master_vol_l = codec_attn[0];
					else
						es1371->master_vol_l = codec_attn[0x1f - ((val >> 8) & 0x1f)];
					if (val & 0x20)
						es1371->master_vol_r = codec_attn[0];
					else					
						es1371->master_vol_r = codec_attn[0x1f - (val & 0x1f)];
				}
				break;
				case 0x12: /*CD volume*/
				if (val & 0x8000)
					es1371->cd_vol_l = es1371->cd_vol_r = 0;
				else
				{
					es1371->cd_vol_l = codec_attn[0x1f - ((val >> 8) & 0x1f)];
					es1371->cd_vol_r = codec_attn[0x1f - (val & 0x1f)];
				}
				break;
			}       
		}
		break;
		
		case 0x24:
		es1371->dac[0].samp_ct = val & 0xffff;
		break;

		case 0x28:
		es1371->dac[1].samp_ct = val & 0xffff;
		break;

		case 0x30:
		switch (es1371->mem_page)
		{
			case 0x0: case 0x1: case 0x2: case 0x3:
			case 0x4: case 0x5: case 0x6: case 0x7:
			case 0x8: case 0x9: case 0xa: case 0xb:
			break;
			
			case 0xc:
			es1371->dac[0].addr_latch = val;
//			audiopci_log("DAC1 addr %08x\n", val);
			break;
			
			case 0xe: case 0xf:
			audiopci_log("ES1371 0x30 write UART FIFO: val = %02x\n", val & 0xff);
			break;
			
			default:
			audiopci_log("Bad es1371_outl: mem_page=%x port=%04x val=%08x\n", es1371->mem_page, port, val);
		}
		break;
		case 0x34:
		switch (es1371->mem_page)
		{
			case 0x0: case 0x1: case 0x2: case 0x3:
			case 0x4: case 0x5: case 0x6: case 0x7:
			case 0x8: case 0x9: case 0xa: case 0xb:
			break;

			case 0xc:
			es1371->dac[0].size = val & 0xffff;
			es1371->dac[0].count = val >> 16;
			break;
			
			case 0xd:
			es1371->adc.size = val & 0xffff;
			es1371->adc.count = val >> 16;
			break;

			case 0xe: case 0xf:
			audiopci_log("ES1371 0x34 write UART FIFO: val = %02x\n", val & 0xff);
			break;

			default:
			audiopci_log("Bad es1371_outl: mem_page=%x port=%04x val=%08x\n", es1371->mem_page, port, val);
		}
		break;
		case 0x38:
		switch (es1371->mem_page)
		{
			case 0x0: case 0x1: case 0x2: case 0x3:
			case 0x4: case 0x5: case 0x6: case 0x7:
			case 0x8: case 0x9: case 0xa: case 0xb:
			break;

			case 0xc:
			es1371->dac[1].addr_latch = val;
			break;
			
			case 0xd:
			break;
			
			case 0xe: case 0xf:
			audiopci_log("ES1371 0x38 write UART FIFO: val = %02x\n", val & 0xff);
			break;

			default:
			audiopci_log("Bad es1371_outl: mem_page=%x port=%04x val=%08x\n", es1371->mem_page, port, val);
		}
		break;
		case 0x3c:
		switch (es1371->mem_page)
		{
			case 0x0: case 0x1: case 0x2: case 0x3:
			case 0x4: case 0x5: case 0x6: case 0x7:
			case 0x8: case 0x9: case 0xa: case 0xb:
			break;

			case 0xc:
			es1371->dac[1].size = val & 0xffff;
			es1371->dac[1].count = val >> 16;
			break;		

			case 0xe: case 0xf:
			audiopci_log("ES1371 0x3c write UART FIFO: val = %02x\n", val & 0xff);
			break;

			default:
			audiopci_log("Bad es1371_outl: mem_page=%x port=%04x val=%08x\n", es1371->mem_page, port, val);
		}
		break;

		default:
		audiopci_log("Bad es1371_outl: port=%04x val=%08x\n", port, val);
	}
}

static void capture_event(es1371_t *es1371, int type, int rw, uint16_t port)
{
	es1371->legacy_ctrl &= ~(LEGACY_EVENT_MASK | LEGACY_EVENT_ADDR_MASK);
	es1371->legacy_ctrl |= type;
	if (rw)	
		es1371->legacy_ctrl |= LEGACY_EVENT_TYPE_RW;
	else
		es1371->legacy_ctrl &= ~LEGACY_EVENT_TYPE_RW;
	es1371->legacy_ctrl |= ((port << LEGACY_EVENT_ADDR_SHIFT) & LEGACY_EVENT_ADDR_MASK);
	es1371->legacy_ctrl &= ~LEGACY_INT;
	nmi = 1;
//	audiopci_log("Event! %s %04x\n", rw ? "write" : "read", port);
}

static void capture_write_sscape(uint16_t port, uint8_t val, void *p)
{
	capture_event(p, LEGACY_EVENT_SSCAPE, 1, port);
}
static void capture_write_codec(uint16_t port, uint8_t val, void *p)
{
	capture_event(p, LEGACY_EVENT_CODEC, 1, port);
}
static void capture_write_sb(uint16_t port, uint8_t val, void *p)
{
	capture_event(p, LEGACY_EVENT_SB, 1, port);
}
static void capture_write_adlib(uint16_t port, uint8_t val, void *p)
{
	capture_event(p, LEGACY_EVENT_ADLIB, 1, port);
}
static void capture_write_master_pic(uint16_t port, uint8_t val, void *p)
{
	capture_event(p, LEGACY_EVENT_MASTER_PIC, 1, port);
}
static void capture_write_master_dma(uint16_t port, uint8_t val, void *p)
{
	capture_event(p, LEGACY_EVENT_MASTER_DMA, 1, port);
}
static void capture_write_slave_pic(uint16_t port, uint8_t val, void *p)
{
	capture_event(p, LEGACY_EVENT_SLAVE_PIC, 1, port);
}
static void capture_write_slave_dma(uint16_t port, uint8_t val, void *p)
{
	capture_event(p, LEGACY_EVENT_SLAVE_DMA, 1, port);
}

static uint8_t capture_read_sscape(uint16_t port, void *p)
{
	capture_event(p, LEGACY_EVENT_SSCAPE, 0, port);
	return 0xff;
}
static uint8_t capture_read_codec(uint16_t port, void *p)
{
	capture_event(p, LEGACY_EVENT_CODEC, 0, port);
	return 0xff;
}
static uint8_t capture_read_sb(uint16_t port, void *p)
{
	capture_event(p, LEGACY_EVENT_SB, 0, port);
	return 0xff;
}
static uint8_t capture_read_adlib(uint16_t port, void *p)
{
	capture_event(p, LEGACY_EVENT_ADLIB, 0, port);
	return 0xff;
}
static uint8_t capture_read_master_pic(uint16_t port, void *p)
{
	capture_event(p, LEGACY_EVENT_MASTER_PIC, 0, port);
	return 0xff;
}
static uint8_t capture_read_master_dma(uint16_t port, void *p)
{
	capture_event(p, LEGACY_EVENT_MASTER_DMA, 0, port);
	return 0xff;
}
static uint8_t capture_read_slave_pic(uint16_t port, void *p)
{
	capture_event(p, LEGACY_EVENT_SLAVE_PIC, 0, port);
	return 0xff;
}
static uint8_t capture_read_slave_dma(uint16_t port, void *p)
{
	capture_event(p, LEGACY_EVENT_SLAVE_DMA, 0, port);
	return 0xff;
}

static void update_legacy(es1371_t *es1371, uint32_t old_legacy_ctrl)
{
        if (old_legacy_ctrl & LEGACY_CAPTURE_SSCAPE)
        {
                switch ((old_legacy_ctrl >> LEGACY_SSCAPE_ADDR_SHIFT) & 3)
                {
                        case 0: io_removehandler(0x0320, 0x0008, capture_read_sscape,NULL,NULL, capture_write_sscape,NULL,NULL, es1371); break;
                        case 1: io_removehandler(0x0330, 0x0008, capture_read_sscape,NULL,NULL, capture_write_sscape,NULL,NULL, es1371); break;
                        case 2: io_removehandler(0x0340, 0x0008, capture_read_sscape,NULL,NULL, capture_write_sscape,NULL,NULL, es1371); break;
                        case 3: io_removehandler(0x0350, 0x0008, capture_read_sscape,NULL,NULL, capture_write_sscape,NULL,NULL, es1371); break;
                }
        }
        if (old_legacy_ctrl & LEGACY_CAPTURE_CODEC)
        {
                switch ((old_legacy_ctrl >> LEGACY_CODEC_ADDR_SHIFT) & 3)
                {
                        case 0: io_removehandler(0x5300, 0x0080, capture_read_codec,NULL,NULL, capture_write_codec,NULL,NULL, es1371); break;
                        case 2: io_removehandler(0xe800, 0x0080, capture_read_codec,NULL,NULL, capture_write_codec,NULL,NULL, es1371); break;
                        case 3: io_removehandler(0xf400, 0x0080, capture_read_codec,NULL,NULL, capture_write_codec,NULL,NULL, es1371); break;
                }
        }
        if (old_legacy_ctrl & LEGACY_CAPTURE_SB)
        {
                if (!(old_legacy_ctrl & LEGACY_SB_ADDR))
                        io_removehandler(0x0220, 0x0010, capture_read_sb,NULL,NULL, capture_write_sb,NULL,NULL, es1371);
                else
                        io_removehandler(0x0240, 0x0010, capture_read_sb,NULL,NULL, capture_write_sb,NULL,NULL, es1371);
        }
        if (old_legacy_ctrl & LEGACY_CAPTURE_ADLIB)
                io_removehandler(0x0388, 0x0004, capture_read_adlib,NULL,NULL, capture_write_adlib,NULL,NULL, es1371);
        if (old_legacy_ctrl & LEGACY_CAPTURE_MASTER_PIC)
                io_removehandler(0x0020, 0x0002, capture_read_master_pic,NULL,NULL, capture_write_master_pic,NULL,NULL, es1371);
        if (old_legacy_ctrl & LEGACY_CAPTURE_MASTER_DMA)
                io_removehandler(0x0000, 0x0010, capture_read_master_dma,NULL,NULL, capture_write_master_dma,NULL,NULL, es1371);
        if (old_legacy_ctrl & LEGACY_CAPTURE_SLAVE_PIC)
                io_removehandler(0x00a0, 0x0002, capture_read_slave_pic,NULL,NULL, capture_write_slave_pic,NULL,NULL, es1371);
        if (old_legacy_ctrl & LEGACY_CAPTURE_SLAVE_DMA)
                io_removehandler(0x00c0, 0x0020, capture_read_slave_dma,NULL,NULL, capture_write_slave_dma,NULL,NULL, es1371);

        if (es1371->legacy_ctrl & LEGACY_CAPTURE_SSCAPE)
        {
                switch ((es1371->legacy_ctrl >> LEGACY_SSCAPE_ADDR_SHIFT) & 3)
                {
                        case 0: io_sethandler(0x0320, 0x0008, capture_read_sscape,NULL,NULL, capture_write_sscape,NULL,NULL, es1371); break;
                        case 1: io_sethandler(0x0330, 0x0008, capture_read_sscape,NULL,NULL, capture_write_sscape,NULL,NULL, es1371); break;
                        case 2: io_sethandler(0x0340, 0x0008, capture_read_sscape,NULL,NULL, capture_write_sscape,NULL,NULL, es1371); break;
                        case 3: io_sethandler(0x0350, 0x0008, capture_read_sscape,NULL,NULL, capture_write_sscape,NULL,NULL, es1371); break;
                }
        }
        if (es1371->legacy_ctrl & LEGACY_CAPTURE_CODEC)
        {
                switch ((es1371->legacy_ctrl >> LEGACY_CODEC_ADDR_SHIFT) & 3)
                {
                        case 0: io_sethandler(0x5300, 0x0080, capture_read_codec,NULL,NULL, capture_write_codec,NULL,NULL, es1371); break;
                        case 2: io_sethandler(0xe800, 0x0080, capture_read_codec,NULL,NULL, capture_write_codec,NULL,NULL, es1371); break;
                        case 3: io_sethandler(0xf400, 0x0080, capture_read_codec,NULL,NULL, capture_write_codec,NULL,NULL, es1371); break;
                }
        }
        if (es1371->legacy_ctrl & LEGACY_CAPTURE_SB)
        {
                if (!(es1371->legacy_ctrl & LEGACY_SB_ADDR))
                        io_sethandler(0x0220, 0x0010, capture_read_sb,NULL,NULL, capture_write_sb,NULL,NULL, es1371);
                else
                        io_sethandler(0x0240, 0x0010, capture_read_sb,NULL,NULL, capture_write_sb,NULL,NULL, es1371);
        }
        if (es1371->legacy_ctrl & LEGACY_CAPTURE_ADLIB)        
                io_sethandler(0x0388, 0x0004, capture_read_adlib,NULL,NULL, capture_write_adlib,NULL,NULL, es1371);
        if (es1371->legacy_ctrl & LEGACY_CAPTURE_MASTER_PIC)
                io_sethandler(0x0020, 0x0002, capture_read_master_pic,NULL,NULL, capture_write_master_pic,NULL,NULL, es1371);
        if (es1371->legacy_ctrl & LEGACY_CAPTURE_MASTER_DMA)
                io_sethandler(0x0000, 0x0010, capture_read_master_dma,NULL,NULL, capture_write_master_dma,NULL,NULL, es1371);
        if (es1371->legacy_ctrl & LEGACY_CAPTURE_SLAVE_PIC)
                io_sethandler(0x00a0, 0x0002, capture_read_slave_pic,NULL,NULL, capture_write_slave_pic,NULL,NULL, es1371);
        if (es1371->legacy_ctrl & LEGACY_CAPTURE_SLAVE_DMA)
                io_sethandler(0x00c0, 0x0020, capture_read_slave_dma,NULL,NULL, capture_write_slave_dma,NULL,NULL, es1371);
}


static uint8_t es1371_pci_read(int func, int addr, void *p)
{
	es1371_t *es1371 = (es1371_t *)p;

	if (func)
		return 0;

	//audiopci_log("ES1371 PCI read %08X PC=%08x\n", addr, cpu_state.pc);

	if (addr > 0x3f)
		return 0x00;

	switch (addr)
	{
		case 0x00: return 0x74; /*Ensoniq*/
		case 0x01: return 0x12;
		
		case 0x02: return 0x71; /* ES1371 */
		case 0x03: return 0x13;

		case 0x04: return es1371->pci_command;
		case 0x05: return es1371->pci_serr;
		
		case 0x06: return 0x10;	/* Supports support ACPI */
		case 0x07: return 0x00;

		case 0x08: return 0x02;	/* Revision ID */
		case 0x09: return 0x00;	/* Multimedia audio device */
		case 0x0a: return 0x01;
		case 0x0b: return 0x04;
		
		case 0x10: return 0x01 | (es1371->base_addr & 0xc0);	/* memBaseAddr */
		case 0x11: return es1371->base_addr >> 8;
		case 0x12: return es1371->base_addr >> 16;
		case 0x13: return es1371->base_addr >> 24;

		case 0x2c: return 0x74;	/* Subsystem vendor ID */
		case 0x2d: return 0x12;
		case 0x2e: return 0x71;
		case 0x2f: return 0x13;

		case 0x34: return 0xdc; /*Capabilites pointer*/

		case 0x3c: return es1371->int_line;
		case 0x3d: return 0x01; /*INTA*/

		case 0x3e: return 0xc; /*Minimum grant*/
		case 0x3f: return 0x80; /*Maximum latency*/
		
		case 0xdc: return 0x01; /*Capabilities identifier*/
		case 0xdd: return 0x00; /*Next item pointer*/
		case 0xde: return 0x31; /*Power management capabilities*/
		case 0xdf: return 0x6c;
		
		case 0xe0: return es1371->pmcsr & 0xff;
		case 0xe1: return es1371->pmcsr >> 8;
	}
	return 0;
}

static void es1371_pci_write(int func, int addr, uint8_t val, void *p)
{
	es1371_t *es1371 = (es1371_t *)p;
	
	if (func)
		return;

//	audiopci_log("ES1371 PCI write %04X %02X PC=%08x\n", addr, val, cpu_state.pc);

	switch (addr)
	{
		case 0x04:
		if (es1371->pci_command & PCI_COMMAND_IO)
			io_removehandler(es1371->base_addr, 0x0040, es1371_inb, es1371_inw, es1371_inl, es1371_outb, es1371_outw, es1371_outl, es1371);
		es1371->pci_command = val & 0x05;
		if (es1371->pci_command & PCI_COMMAND_IO)
			io_sethandler(es1371->base_addr, 0x0040, es1371_inb, es1371_inw, es1371_inl, es1371_outb, es1371_outw, es1371_outl, es1371);
		break;
		case 0x05:
		es1371->pci_serr = val & 1;
		break;
		
		case 0x10:
		if (es1371->pci_command & PCI_COMMAND_IO)
			io_removehandler(es1371->base_addr, 0x0040, es1371_inb, es1371_inw, es1371_inl, es1371_outb, es1371_outw, es1371_outl, es1371);
		es1371->base_addr = (es1371->base_addr & 0xffffff00) | (val & 0xc0);
		if (es1371->pci_command & PCI_COMMAND_IO)
			io_sethandler(es1371->base_addr, 0x0040, es1371_inb, es1371_inw, es1371_inl, es1371_outb, es1371_outw, es1371_outl, es1371);
		break;
		case 0x11:
		if (es1371->pci_command & PCI_COMMAND_IO)
			io_removehandler(es1371->base_addr, 0x0040, es1371_inb, es1371_inw, es1371_inl, es1371_outb, es1371_outw, es1371_outl, es1371);
		es1371->base_addr = (es1371->base_addr & 0xffff00c0) | (val << 8);
		if (es1371->pci_command & PCI_COMMAND_IO)
			io_sethandler(es1371->base_addr, 0x0040, es1371_inb, es1371_inw, es1371_inl, es1371_outb, es1371_outw, es1371_outl, es1371);
		break;
		case 0x12:
		es1371->base_addr = (es1371->base_addr & 0xff00ffc0) | (val << 16);
		break;
		case 0x13:
		es1371->base_addr = (es1371->base_addr & 0x00ffffc0) | (val << 24);
		break;

		case 0x3c:
		es1371->int_line = val;
		break;

		case 0xe0:
		es1371->pmcsr = (es1371->pmcsr & 0xff00) | (val & 0x03);
		break;
		case 0xe1:
		es1371->pmcsr = (es1371->pmcsr & 0x00ff) | ((val & 0x01) << 8);
		break;
	}
//	audiopci_log("es1371->base_addr %08x\n", es1371->base_addr);
}

static void es1371_fetch(es1371_t *es1371, int dac_nr)
{
	int format = dac_nr ? ((es1371->si_cr >> 2) & 3) : (es1371->si_cr & 3);
	int pos = es1371->dac[dac_nr].buffer_pos & 63;
	int c;

//audiopci_log("Fetch format=%i %08x %08x  %08x %08x  %08x\n", format, es1371->dac[dac_nr].count, es1371->dac[dac_nr].size,  es1371->dac[dac_nr].curr_samp_ct,es1371->dac[dac_nr].samp_ct, es1371->dac[dac_nr].addr);
	switch (format)
	{
		case FORMAT_MONO_8:
		for (c = 0; c < 32; c += 4)
		{
			es1371->dac[dac_nr].buffer_l[(pos+c)   & 63] = es1371->dac[dac_nr].buffer_r[(pos+c)   & 63] = (mem_readb_phys(es1371->dac[dac_nr].addr) ^ 0x80) << 8;
			es1371->dac[dac_nr].buffer_l[(pos+c+1) & 63] = es1371->dac[dac_nr].buffer_r[(pos+c+1) & 63] = (mem_readb_phys(es1371->dac[dac_nr].addr+1) ^ 0x80) << 8;
			es1371->dac[dac_nr].buffer_l[(pos+c+2) & 63] = es1371->dac[dac_nr].buffer_r[(pos+c+2) & 63] = (mem_readb_phys(es1371->dac[dac_nr].addr+2) ^ 0x80) << 8;
			es1371->dac[dac_nr].buffer_l[(pos+c+3) & 63] = es1371->dac[dac_nr].buffer_r[(pos+c+3) & 63] = (mem_readb_phys(es1371->dac[dac_nr].addr+3) ^ 0x80) << 8;
			es1371->dac[dac_nr].addr += 4;
	
			es1371->dac[dac_nr].buffer_pos_end += 4;
			es1371->dac[dac_nr].count++;
			if (es1371->dac[dac_nr].count > es1371->dac[dac_nr].size)
			{
				es1371->dac[dac_nr].count = 0;
				es1371->dac[dac_nr].addr = es1371->dac[dac_nr].addr_latch;
				break;
			}
		}
		break;
		case FORMAT_STEREO_8:
		for (c = 0; c < 16; c += 2)
		{
			es1371->dac[dac_nr].buffer_l[(pos+c)   & 63] = (mem_readb_phys(es1371->dac[dac_nr].addr) ^ 0x80) << 8;
			es1371->dac[dac_nr].buffer_r[(pos+c)   & 63] = (mem_readb_phys(es1371->dac[dac_nr].addr + 1) ^ 0x80) << 8;
			es1371->dac[dac_nr].buffer_l[(pos+c+1) & 63] = (mem_readb_phys(es1371->dac[dac_nr].addr + 2) ^ 0x80) << 8;
			es1371->dac[dac_nr].buffer_r[(pos+c+1) & 63] = (mem_readb_phys(es1371->dac[dac_nr].addr + 3) ^ 0x80) << 8;
			es1371->dac[dac_nr].addr += 4;
	
			es1371->dac[dac_nr].buffer_pos_end += 2;
			es1371->dac[dac_nr].count++;
			if (es1371->dac[dac_nr].count > es1371->dac[dac_nr].size)
			{
				es1371->dac[dac_nr].count = 0;
				es1371->dac[dac_nr].addr = es1371->dac[dac_nr].addr_latch;
				break;
			}
		}
		break;
		case FORMAT_MONO_16:
		for (c = 0; c < 16; c += 2)
		{
			es1371->dac[dac_nr].buffer_l[(pos+c)   & 63] = es1371->dac[dac_nr].buffer_r[(pos+c)   & 63] = mem_readw_phys(es1371->dac[dac_nr].addr);
			es1371->dac[dac_nr].buffer_l[(pos+c+1) & 63] = es1371->dac[dac_nr].buffer_r[(pos+c+1) & 63] = mem_readw_phys(es1371->dac[dac_nr].addr + 2);
			es1371->dac[dac_nr].addr += 4;

			es1371->dac[dac_nr].buffer_pos_end += 2;
			es1371->dac[dac_nr].count++;
			if (es1371->dac[dac_nr].count > es1371->dac[dac_nr].size)
			{
				es1371->dac[dac_nr].count = 0;
				es1371->dac[dac_nr].addr = es1371->dac[dac_nr].addr_latch;
				break;
			}
		}
		break;
		case FORMAT_STEREO_16:
		for (c = 0; c < 4; c++)
		{
			es1371->dac[dac_nr].buffer_l[(pos+c) & 63] = mem_readw_phys(es1371->dac[dac_nr].addr);
			es1371->dac[dac_nr].buffer_r[(pos+c) & 63] = mem_readw_phys(es1371->dac[dac_nr].addr + 2);
//			audiopci_log("Fetch %02x %08x  %04x %04x\n", (pos+c) & 63, es1371->dac[dac_nr].addr, es1371->dac[dac_nr].buffer_l[(pos+c) & 63], es1371->dac[dac_nr].buffer_r[(pos+c) & 63]);
			es1371->dac[dac_nr].addr += 4;
	
			es1371->dac[dac_nr].buffer_pos_end++;
			es1371->dac[dac_nr].count++;
			if (es1371->dac[dac_nr].count > es1371->dac[dac_nr].size)
			{
				es1371->dac[dac_nr].count = 0;
				es1371->dac[dac_nr].addr = es1371->dac[dac_nr].addr_latch;
				break;
			}
		}
		break;
	}
}

static inline float low_fir_es1371(int dac_nr, int i, float NewSample)
{
        static float x[2][2][128]; //input samples
        static int x_pos[2] = {0, 0};
        float out = 0.0;
	int read_pos;
	int n_coef;
	int pos = x_pos[dac_nr];

        x[dac_nr][i][pos] = NewSample;

        /*Since only 1/16th of input samples are non-zero, only filter those that
          are valid.*/
	read_pos = (pos + 15) & (127 & ~15);
	n_coef = (16 - pos) & 15;

	while (n_coef < ES1371_NCoef)
	{
		out += low_fir_es1371_coef[n_coef] * x[dac_nr][i][read_pos];
		read_pos = (read_pos + 16) & (127 & ~15);
		n_coef += 16;
	}

        if (i == 1)
        {
        	x_pos[dac_nr] = (x_pos[dac_nr] + 1) & 127;
        	if (x_pos[dac_nr] > 127)
        		x_pos[dac_nr] = 0;
        }

        return out;
}

static void es1371_next_sample_filtered(es1371_t *es1371, int dac_nr, int out_idx)
{
        int out_l, out_r;
        int c;
        
	if ((es1371->dac[dac_nr].buffer_pos - es1371->dac[dac_nr].buffer_pos_end) >= 0)
	{
		es1371_fetch(es1371, dac_nr);
	}

        out_l = es1371->dac[dac_nr].buffer_l[es1371->dac[dac_nr].buffer_pos & 63];
        out_r = es1371->dac[dac_nr].buffer_r[es1371->dac[dac_nr].buffer_pos & 63];
        
        es1371->dac[dac_nr].filtered_l[out_idx] = (int)low_fir_es1371(dac_nr, 0, (float)out_l);
        es1371->dac[dac_nr].filtered_r[out_idx] = (int)low_fir_es1371(dac_nr, 1, (float)out_r);
        for (c = 1; c < 16; c++)
        {
                es1371->dac[dac_nr].filtered_l[out_idx+c] = (int)low_fir_es1371(dac_nr, 0, 0);
                es1371->dac[dac_nr].filtered_r[out_idx+c] = (int)low_fir_es1371(dac_nr, 1, 0);
        }
        
//	audiopci_log("Use %02x %04x %04x\n", es1371->dac[dac_nr].buffer_pos & 63, es1371->dac[dac_nr].out_l, es1371->dac[dac_nr].out_r);
	
	es1371->dac[dac_nr].buffer_pos++;
//	audiopci_log("Next sample %08x %08x  %08x\n", es1371->dac[dac_nr].buffer_pos, es1371->dac[dac_nr].buffer_pos_end, es1371->dac[dac_nr].curr_samp_ct);
}

//static FILE *es1371_f;//,*es1371_f2;

static void es1371_update(es1371_t *es1371)
{
        int32_t l, r;
                                
        l = (es1371->dac[0].out_l * es1371->dac[0].vol_l) >> 12;
        l += ((es1371->dac[1].out_l * es1371->dac[1].vol_l) >> 12);
        r = (es1371->dac[0].out_r * es1371->dac[0].vol_r) >> 12;
        r += ((es1371->dac[1].out_r * es1371->dac[1].vol_r) >> 12);
                
        l >>= 1;
        r >>= 1;
                
        l = (l * es1371->master_vol_l) >> 15;
        r = (r * es1371->master_vol_r) >> 15;
                                
        if (l < -32768)
                l = -32768;
        else if (l > 32767)
                l = 32767;
        if (r < -32768)
                r = -32768;
        else if (r > 32767)
                r = 32767;

        for (; es1371->pos < sound_pos_global; es1371->pos++)
        {                                        
                es1371->buffer[es1371->pos*2]     = l;
                es1371->buffer[es1371->pos*2 + 1] = r;
        }
}

static void es1371_poll(void *p)
{
	es1371_t *es1371 = (es1371_t *)p;
	
	timer_advance_u64(&es1371->dac[1].timer, es1371->dac[1].latch);

	es1371_update(es1371);		

	if (es1371->int_ctrl & INT_UART_EN) {
		audiopci_log("UART INT Enabled\n");
		if (es1371->uart_ctrl & UART_CTRL_RXINTEN) { /*We currently don't implement MIDI Input.*/
			/*But if anything sets MIDI Input and Output together we'd have to take account
			of the MIDI Output case, and disable IRQ's and RX bits when MIDI Input is enabled as well but not in the MIDI Output portion*/
			if (es1371->uart_ctrl & UART_CTRL_TXINTEN) 
				es1371->int_status |= INT_STATUS_UART;
			else
				es1371->int_status &= ~INT_STATUS_UART;
		} else if (!(es1371->uart_ctrl & UART_CTRL_RXINTEN) && ((es1371->uart_ctrl & UART_CTRL_TXINTEN))) { /*Or enable the UART IRQ and the respective TX bits only when the MIDI Output is enabled*/
			es1371->int_status |= INT_STATUS_UART;
		}
		
		if (es1371->uart_ctrl & UART_CTRL_RXINTEN) {
			if (es1371->uart_ctrl & UART_CTRL_TXINTEN) 
				es1371->uart_status |= (UART_STATUS_TXINT | UART_STATUS_TXRDY);
			else
				es1371->uart_status &= ~(UART_STATUS_TXINT | UART_STATUS_TXRDY);
		} else
			es1371->uart_status |= (UART_STATUS_TXINT | UART_STATUS_TXRDY);
		
		es1371_update_irqs(es1371);
	}		
		
	if (es1371->int_ctrl & INT_DAC1_EN) {
                int frac = es1371->dac[0].ac & 0x7fff;
                int idx = es1371->dac[0].ac >> 15;
                int samp1_l = es1371->dac[0].filtered_l[idx];
                int samp1_r = es1371->dac[0].filtered_r[idx];
                int samp2_l = es1371->dac[0].filtered_l[(idx + 1) & 31];
                int samp2_r = es1371->dac[0].filtered_r[(idx + 1) & 31];
                
                es1371->dac[0].out_l = ((samp1_l * (0x8000 - frac)) + (samp2_l * frac)) >> 15;
                es1371->dac[0].out_r = ((samp1_r * (0x8000 - frac)) + (samp2_r * frac)) >> 15;
                es1371->dac[0].ac += es1371->dac[0].vf;
                es1371->dac[0].ac &= ((32 << 15) - 1);
                if ((es1371->dac[0].ac >> (15+4)) != es1371->dac[0].f_pos)
		{
                        es1371_next_sample_filtered(es1371, 0, es1371->dac[0].f_pos ? 16 : 0);
                        es1371->dac[0].f_pos = (es1371->dac[0].f_pos + 1) & 1;

                        es1371->dac[0].curr_samp_ct--;
                        if (es1371->dac[0].curr_samp_ct < 0)
			{
				es1371->int_status |= INT_STATUS_DAC1;
				es1371_update_irqs(es1371);
				es1371->dac[0].curr_samp_ct = es1371->dac[0].samp_ct;
			}
		}
	}

	if (es1371->int_ctrl & INT_DAC2_EN)
	{
                int frac = es1371->dac[1].ac & 0x7fff;
                int idx = es1371->dac[1].ac >> 15;
                int samp1_l = es1371->dac[1].filtered_l[idx];
                int samp1_r = es1371->dac[1].filtered_r[idx];
                int samp2_l = es1371->dac[1].filtered_l[(idx + 1) & 31];
                int samp2_r = es1371->dac[1].filtered_r[(idx + 1) & 31];
                
                es1371->dac[1].out_l = ((samp1_l * (0x8000 - frac)) + (samp2_l * frac)) >> 15;
                es1371->dac[1].out_r = ((samp1_r * (0x8000 - frac)) + (samp2_r * frac)) >> 15;
		es1371->dac[1].ac += es1371->dac[1].vf;
                es1371->dac[1].ac &= ((32 << 15) - 1);
                if ((es1371->dac[1].ac >> (15+4)) != es1371->dac[1].f_pos)
		{
                        es1371_next_sample_filtered(es1371, 1, es1371->dac[1].f_pos ? 16 : 0);
                        es1371->dac[1].f_pos = (es1371->dac[1].f_pos + 1) & 1;

                        es1371->dac[1].curr_samp_ct--;
                        if (es1371->dac[1].curr_samp_ct < 0)
			{
				es1371->int_status |= INT_STATUS_DAC2;
				es1371_update_irqs(es1371);
                                es1371->dac[1].curr_samp_ct = es1371->dac[1].samp_ct;
			}
		}
	}
}

static void es1371_get_buffer(int32_t *buffer, int len, void *p)
{
	es1371_t *es1371 = (es1371_t *)p;
	int c;

        es1371_update(es1371);

	for (c = 0; c < len * 2; c++)
		buffer[c] += (es1371->buffer[c] / 2);
	
	es1371->pos = 0;
}

static void es1371_filter_cd_audio(int channel, double *buffer, void *p)
{
	es1371_t *es1371 = (es1371_t *)p;
	int32_t c;
	int cd = channel ? es1371->cd_vol_r : es1371->cd_vol_l;
	int master = channel ? es1371->master_vol_r : es1371->master_vol_l;

        c = (((int32_t) *buffer) * cd) >> 15;
	c = (c * master) >> 15;

	*buffer     = (double) c;
}

static inline double sinc(double x)
{
	return sin(M_PI * x) / (M_PI * x);
}

static void generate_es1371_filter()
{
        /*Cutoff frequency = 1 / 32*/
        float fC = 1.0 / 32.0;
        float gain;
        int n;
        
        for (n = 0; n < ES1371_NCoef; n++)
        {
                /*Blackman window*/
                double w = 0.42 - (0.5 * cos((2.0*n*M_PI)/(double)(ES1371_NCoef-1))) + (0.08 * cos((4.0*n*M_PI)/(double)(ES1371_NCoef-1)));
                /*Sinc filter*/
                double h = sinc(2.0 * fC * ((double)n - ((double)(ES1371_NCoef-1) / 2.0)));
                
                /*Create windowed-sinc filter*/
                low_fir_es1371_coef[n] = w * h;
        }
        
        low_fir_es1371_coef[(ES1371_NCoef - 1) / 2] = 1.0;

        gain = 0.0;
        for (n = 0; n < ES1371_NCoef; n++)
                gain += low_fir_es1371_coef[n] / (float)N;

	gain /= 0.95;

        /*Normalise filter, to produce unity gain*/
        for (n = 0; n < ES1371_NCoef; n++)
                low_fir_es1371_coef[n] /= gain;
}        

static void *es1371_init(const device_t *info)
{
	es1371_t *es1371 = malloc(sizeof(es1371_t));
	memset(es1371, 0, sizeof(es1371_t));
		
	sound_add_handler(es1371_get_buffer, es1371);
	sound_set_cd_audio_filter(es1371_filter_cd_audio, es1371);

	es1371->card = pci_add_card(info->local ? PCI_ADD_SOUND : PCI_ADD_NORMAL, es1371_pci_read, es1371_pci_write, es1371);
	
	timer_add(&es1371->dac[1].timer, es1371_poll, es1371, 1); 
        
        generate_es1371_filter();

	/* Return a CS4297A like VMWare does. */
	es1371->codec_regs[0x7c] = 0x4352;
	es1371->codec_regs[0x7e] = 0x5910;

	return es1371;
}

static void es1371_close(void *p)
{
	es1371_t *es1371 = (es1371_t *)p;
	
	free(es1371);
}

static void es1371_speed_changed(void *p)
{
	es1371_t *es1371 = (es1371_t *)p;
	
	es1371->dac[1].latch = (uint64_t)((double)TIMER_USEC * (1000000.0 / 48000.0));
}
 
void es1371_add_status_info_dac(es1371_t *es1371, char *s, int max_len, int dac_nr)
{
        int ena = dac_nr ? INT_DAC2_EN : INT_DAC1_EN;
        char *dac_name = dac_nr ? "DAC2 (Wave)" : "DAC1 (MIDI)";
        char temps[128];

        if (es1371->int_ctrl & ena)
        {
                int format = dac_nr ? ((es1371->si_cr >> 2) & 3) : (es1371->si_cr & 3);
                double freq = 48000.0 * ((double)es1371->dac[dac_nr].vf / (32768.0 * 16.0));

                switch (format)
                {
                        case FORMAT_MONO_8:
                        snprintf(temps, 128, "%s format : 8-bit mono\n", dac_name);
                        break;
                        case FORMAT_STEREO_8:
                        snprintf(temps, 128, "%s format : 8-bit stereo\n", dac_name);
                        break;
                        case FORMAT_MONO_16:
                        snprintf(temps, 128, "%s format : 16-bit mono\n", dac_name);
                        break;
                        case FORMAT_STEREO_16:
                        snprintf(temps, 128, "%s format : 16-bit stereo\n", dac_name);
                        break;
                }
                
                strncat(s, temps, max_len);
                max_len -= strlen(temps);

                snprintf(temps, 128, "Playback frequency : %i Hz\n", (int)freq);
                strncat(s, temps, max_len);
        }
        else
        {
                snprintf(temps, max_len, "%s stopped\n", dac_name);
                strncat(s, temps, max_len);
        }
}

const device_t es1371_device =
{
    "Ensoniq AudioPCI (ES1371)",
    DEVICE_PCI,
    0,
    es1371_init,
    es1371_close,
    NULL,
    { NULL },
    es1371_speed_changed,
    NULL,
    NULL
};

const device_t es1371_onboard_device =
{
    "Ensoniq AudioPCI (ES1371) (On-Board)",
    DEVICE_PCI,
    1,
    es1371_init,
    es1371_close,
    NULL,
    { NULL },
    es1371_speed_changed,
    NULL,
    NULL
};
