Skip to content

Commit

Permalink
use soundcard interrupt instead of timer, music plays more stable.
Browse files Browse the repository at this point in the history
  • Loading branch information
crazii committed Jan 25, 2023
1 parent ace364b commit de7c8bb
Show file tree
Hide file tree
Showing 7 changed files with 103 additions and 40 deletions.
84 changes: 55 additions & 29 deletions MAIN.C
Expand Up @@ -22,13 +22,21 @@ extern int16_t* TEST_Sample;
extern unsigned long TEST_SampleLen;

mpxplay_audioout_info_s aui = {0};

#define MAIN_USE_INT70 0
#define MAIN_USE_TIMER 0
#if MAIN_USE_TIMER
#define MAIN_USE_INT70 1
#define MAIN_INT70_FREQ 1024 //1024 max
#define MAIN_PCM_SAMPLESIZE 32768
#define MAIN_FREQ (MAIN_USE_INT70 ? MAIN_INT70_FREQ : 18) //because some programs will assume default frequency on running/uninstalling its own timer, so we don't change the default
#define MAIN_SAMPLES (SBEMU_SAMPLERATE / MAIN_FREQ)
#define MAIN_PCM_SAMPLESIZE 32768
static const int MAIN_PCM_COUNT = (MAIN_PCM_SAMPLESIZE / (MAIN_SAMPLES*SBEMU_CHANNELS) * MAIN_SAMPLES*SBEMU_CHANNELS);
static int16_t MAIN_OPLPCM[MAIN_SAMPLES*8+256];
static int MAIN_PCMEndTag = MAIN_PCM_COUNT;
#else
#define MAIN_USE_INT70 0
#define MAIN_PCM_SAMPLESIZE 8192
static int16_t MAIN_OPLPCM[MAIN_PCM_SAMPLESIZE+256];
#endif

static DPMI_ISR_HANDLE MAIN_TimerIntHandlePM;
static DPMI_REG MAIN_TimerPMReg = {0};
Expand All @@ -39,14 +47,13 @@ static uint32_t MAIN_DMA_Size = 0;
static uint32_t MAIN_DMA_MappedAddr = 0;
static uint32_t MAIN_SBBytes = 0;
static int16_t MAIN_PCM[MAIN_PCM_SAMPLESIZE+256];
static int16_t MAIN_OPLPCM[MAIN_SAMPLES*8+256];

static int MAIN_PCMStart;
static int MAIN_PCMEnd;
static int MAIN_PCMEndTag = MAIN_PCM_COUNT;
static void MAIN_TimerInterrupt();
static void MAIN_Interrupt();
//need capture both RM & PM context to issue virq
static void MAIN_TimerInterruptPM();
static void MAIN_TimerInterruptRM();
static void MAIN_InterruptPM();
static void MAIN_InterruptRM();
static void MAIN_EnableInt70();

static uint32_t MAIN_OPL3_388(uint32_t port, uint32_t val, uint32_t out)
Expand Down Expand Up @@ -322,13 +329,14 @@ int main(int argc, char* argv[])
//TestSound(FALSE);
}

SBEMU_Init(MAIN_Options[OPT_IRQ].value, MAIN_Options[OPT_DMA].value);
SBEMU_Init(MAIN_Options[OPT_IRQ].value, MAIN_Options[OPT_DMA].value, &MAIN_Interrupt);
for(int i = 0; i < countof(MAIN_SB_IODT); ++i)
MAIN_SB_IODT[i].port += MAIN_Options[OPT_ADDR].value;
QEMM_IODT* SB_Iodt = MAIN_Options[OPT_OPL].value ? MAIN_SB_IODT : MAIN_SB_IODT+4;
int SB_IodtCount = MAIN_Options[OPT_OPL].value ? countof(MAIN_SB_IODT) : countof(MAIN_SB_IODT)-4;
//MAIN_SB_IODT[countof(MAIN_SB_IODT)-1].port = DPMI_LoadW(DPMI_SEGOFF2L(0x40,0x63)) + 6;


/*
BOOL QEMMInstalledVDMA = QEMM_Install_IOPortTrap(MAIN_VDMA_IODT, countof(MAIN_VDMA_IODT), &MAIN_VDMA_IOPT);
#if MAIN_USE_INT70 //will crash with VIRQ installed, do it temporarily. TODO: figure out why
BOOL QEMMInstalledVIRQ = TRUE;
Expand All @@ -343,24 +351,29 @@ int main(int argc, char* argv[])
BOOL HDPMIInstalledVIRQ1 = HDPMIPT_Install_IOPortTrap(0x20, 0x21, MAIN_VIRQ_IODT, 2, &MAIN_VIRQ_IOPT_PM1);
BOOL HDPMIInstalledVIRQ2 = HDPMIPT_Install_IOPortTrap(0xA0, 0xA1, MAIN_VIRQ_IODT+2, 2, &MAIN_VIRQ_IOPT_PM2);
BOOL HDPMIInstalledSB = HDPMIPT_Install_IOPortTrap(MAIN_Options[OPT_ADDR].value, MAIN_Options[OPT_ADDR].value+0x0F, SB_Iodt, SB_IodtCount, &MAIN_SB_IOPT_PM);

BOOL PM_ISR = DPMI_InstallISR(MAIN_USE_INT70 ? 0x70 : 0x08, MAIN_TimerInterruptPM, &MAIN_TimerIntHandlePM) == 0;
*/
#if MAIN_USE_TIMER
BOOL PM_ISR = DPMI_InstallISR(MAIN_USE_INT70 ? 0x70 : 0x08, MAIN_InterruptPM, &MAIN_TimerIntHandlePM) == 0;
#if MAIN_USE_INT70
MAIN_EnableInt70();
#endif
#else
BOOL PM_ISR = DPMI_InstallISR(PIC_IRQ2VEC(aui.card_irq), MAIN_InterruptPM, &MAIN_TimerIntHandlePM) == 0;
PIC_UnmaskIRQ(aui.card_irq);
#endif

BOOL TSR = TRUE;
if(!PM_ISR
|| !QEMMInstalledVDMA || !QEMMInstalledVIRQ || !QEMMInstalledSB
|| !HDPMIInstalledVDMA1 || !HDPMIInstalledVDMA2 || !HDPMIInstalledVDMA3 || !HDPMIInstalledVIRQ1 || !HDPMIInstalledVIRQ2 || !HDPMIInstalledSB
//|| !QEMMInstalledVDMA || !QEMMInstalledVIRQ || !QEMMInstalledSB
//|| !HDPMIInstalledVDMA1 || !HDPMIInstalledVDMA2 || !HDPMIInstalledVDMA3 || !HDPMIInstalledVIRQ1 || !HDPMIInstalledVIRQ2 || !HDPMIInstalledSB
|| !(TSR=DPMI_TSR()))
{
if(MAIN_Options[OPT_OPL].value)
{
QEMM_Uninstall_IOPortTrap(&OPL3IOPT);
HDPMIPT_Uninstall_IOPortTrap(&OPL3IOPT_PM);
}

/*
if(!QEMMInstalledVDMA || !QEMMInstalledVIRQ || !QEMMInstalledSB)
printf("Error: Failed installing IO port trap for QEMM.\n");
if(QEMMInstalledVDMA) QEMM_Uninstall_IOPortTrap(&MAIN_VDMA_IOPT);
Expand All @@ -377,7 +390,7 @@ int main(int argc, char* argv[])
if(HDPMIInstalledVIRQ1) HDPMIPT_Uninstall_IOPortTrap(&MAIN_VIRQ_IOPT_PM1);
if(HDPMIInstalledVIRQ2) HDPMIPT_Uninstall_IOPortTrap(&MAIN_VIRQ_IOPT_PM2);
if(HDPMIInstalledSB) HDPMIPT_Uninstall_IOPortTrap(&MAIN_SB_IOPT_PM);

*/
if(!PM_ISR)
printf("Error: Failed installing timer.\n");
if(PM_ISR) DPMI_UninstallISR(&MAIN_TimerIntHandlePM);
Expand All @@ -388,9 +401,8 @@ int main(int argc, char* argv[])
return 1;
}

static void MAIN_TimerInterruptPM()
static void MAIN_InterruptPM()
{
CLIS();
#if MAIN_USE_INT70
if(++MAIN_Int70Counter >= (1024/MAIN_INT70_FREQ))
#endif
Expand Down Expand Up @@ -418,17 +430,20 @@ static void MAIN_TimerInterruptPM()
DBG_DumpREG(&MAIN_TimerPMReg);//while(1);
#endif

MAIN_TimerInterrupt();
MAIN_Interrupt();
}

DPMI_CallOldISR(&MAIN_TimerIntHandlePM);
//DPMI_CallRealModeOldISR(&MAIN_TimerIntHandlePM);
#if MAIN_USE_INT70
MAIN_EnableInt70();
#endif
#if !MAIN_USE_TIMER
PIC_UnmaskIRQ(aui.card_irq);
#endif
}

static void MAIN_TimerInterrupt()
static void MAIN_Interrupt()
{
#if 0
const int samples = MAIN_SAMPLES*2;
Expand All @@ -439,7 +454,17 @@ static void MAIN_TimerInterrupt()
cur += aui.samplenum;
AU_writedata(&aui);
#else
#if MAIN_USE_TIMER
int samples = MAIN_SAMPLES;
#else
if(aui.card_handler->irq_routine) aui.card_handler->irq_routine(&aui);
aui.card_outbytes = aui.card_dmasize;
int samples = AU_cardbuf_space(&aui) / sizeof(int16_t) / 2; //16 bit, 2 channels
if(samples == 0)
return;
#endif

#if MAIN_USE_TIMER
if((MAIN_PCMEnd - MAIN_PCMStart + MAIN_PCMEndTag)%MAIN_PCMEndTag >= MAIN_PCMEndTag-MAIN_SAMPLES*4) //buffer full
{
aui.samplenum = MAIN_PCMEnd >= MAIN_PCMStart ? MAIN_PCMEnd - MAIN_PCMStart : MAIN_PCMEndTag - MAIN_PCMStart;
Expand All @@ -454,6 +479,7 @@ static void MAIN_TimerInterrupt()
}
return;
}
#endif
/*if(MAIN_PCMEnd >= MAIN_PCMStart && MAIN_PCMEnd - MAIN_PCMStart < MAIN_SAMPLES*4) //(almost) empty
samples += samples/2; //extra samples to avoid underrun due to timer interrupt precision
//_LOG("PTR: %d, %d, %d\n", MAIN_PCMEnd, MAIN_PCMStart, MAIN_PCMEnd - MAIN_PCMStart);*/
Expand Down Expand Up @@ -529,12 +555,6 @@ static void MAIN_TimerInterrupt()
}
} while(DMA_GetAuto() && (pos < samples) && SBEMU_HasStarted());
samples = pos;
/*while(pos < samples)
{
MAIN_PCM[MAIN_PCMEnd+pos*2] = 0;
MAIN_PCM[MAIN_PCMEnd+pos*2+1] = 0;
++pos;
}*/
//_LOG("digital end\n");
}
else if(!MAIN_Options[OPT_OPL].value)
Expand Down Expand Up @@ -562,14 +582,14 @@ static void MAIN_TimerInterrupt()
}
}
samples *= 2; //to stereo
MAIN_PCMEnd += samples;

#if MAIN_USE_TIMER
MAIN_PCMEnd += samples;
if(MAIN_PCMEnd >= MAIN_PCM_COUNT - MAIN_SAMPLES*4)
{
MAIN_PCMEndTag = MAIN_PCMEnd;
MAIN_PCMEnd = 0;
}

aui.samplenum = MAIN_PCMEnd >= MAIN_PCMStart ? MAIN_PCMEnd - MAIN_PCMStart : MAIN_PCMEndTag - MAIN_PCMStart;
aui.pcm_sample = MAIN_PCM + MAIN_PCMStart;
MAIN_PCMStart += aui.samplenum - AU_writedata(&aui);
Expand All @@ -580,15 +600,21 @@ static void MAIN_TimerInterrupt()
aui.pcm_sample = MAIN_PCM + MAIN_PCMStart;
MAIN_PCMStart += aui.samplenum - AU_writedata(&aui);
}
#else
aui.samplenum = samples;
aui.pcm_sample = MAIN_PCM + MAIN_PCMStart;
AU_writedata(&aui);
#endif

//_LOG("TIMEREND\n");
#endif
}


static void MAIN_EnableInt70()
{
CLIS();
PIC_UnmaskIRQ(8);

outp(0x70, 0x0A);
int freq = inp(0x71);
if(freq != 0x26) //1024
Expand Down
9 changes: 7 additions & 2 deletions MPXPLAY/AU_CARDS/AU_CARDS.C
Expand Up @@ -33,7 +33,9 @@ typedef int (*aucards_writedata_t)(struct mpxplay_audioout_info_s *aui,unsigned
static unsigned int cardinit(struct mpxplay_audioout_info_s *aui);
static unsigned int carddetect(struct mpxplay_audioout_info_s *aui, unsigned int retry);

#ifndef SBEMU
static unsigned int AU_cardbuf_space(struct mpxplay_audioout_info_s *aui);
#endif
static int aucards_writedata_normal(struct mpxplay_audioout_info_s *aui,unsigned long outbytes_left);
static int aucards_writedata_intsound(struct mpxplay_audioout_info_s *aui,unsigned long outbytes_left);
#ifdef SBEMU
Expand Down Expand Up @@ -878,7 +880,10 @@ void AU_setmixer_all(struct mpxplay_audioout_info_s *aui)
//-------------------------------------------------------------------------
#define SOUNDCARD_BUFFER_PROTECTION 32 // in bytes (requried for PCI cards)

static unsigned int AU_cardbuf_space(struct mpxplay_audioout_info_s *aui)
#ifndef SBEMU
static
#endif
unsigned int AU_cardbuf_space(struct mpxplay_audioout_info_s *aui)
{
unsigned long buffer_protection;

Expand Down Expand Up @@ -910,7 +915,7 @@ static unsigned int AU_cardbuf_space(struct mpxplay_audioout_info_s *aui)
if(bufpos>=aui->card_outbytes)
aui->card_dmalastput=bufpos-aui->card_outbytes;
else
aui->card_dmalastput=aui->card_dmasize+bufpos-aui->card_outbytes;
aui->card_dmalastput=aui->card_dmasize+bufpos-aui->card_outbytes+aui->card_bytespersign;
funcbit_smp_disable(aui->card_infobits,AUINFOS_CARDINFOBIT_DMAUNDERRUN);
}
}else{
Expand Down
3 changes: 3 additions & 0 deletions MPXPLAY/AU_CARDS/AU_CARDS.H
Expand Up @@ -281,6 +281,9 @@ extern void AU_setmixer_outs(struct mpxplay_audioout_info_s *aui,unsigned int se
extern void AU_setmixer_all(struct mpxplay_audioout_info_s *);
extern void AU_clearbuffs(struct mpxplay_audioout_info_s *);
extern void AU_pause_process(struct mpxplay_audioout_info_s *);
#ifdef SBEMU
extern unsigned int AU_cardbuf_space(struct mpxplay_audioout_info_s *aui);
#endif
extern int AU_writedata(struct mpxplay_audioout_info_s *);

#ifdef __cplusplus
Expand Down
4 changes: 2 additions & 2 deletions MPXPLAY/AU_CARDS/PCIBIOS.H
Expand Up @@ -80,8 +80,8 @@ typedef unsigned long uint32_t;
#define PCIR_RID 0x08 // chiprev
#define PCIR_CCODE 0x0A
#define PCIR_HEADT 0x0E // head type
#define PCIR_NAMBAR 0x10 // io baseport
#define PCIR_NABMBAR 0x14 // busmaster io baseport
#define PCIR_NAMBAR 0x10 // Native Audio Mixer Base Address
#define PCIR_NABMBAR 0x14 // Native Audio Bus Mastering Base Address
#define PCIR_SSVID 0x2C // subsystem id + vendor id (serial)
#define PCIR_SSID 0x2E // subsystem id (model)
#define PCIR_INTR_LN 0x3C // irq number
Expand Down
29 changes: 26 additions & 3 deletions MPXPLAY/AU_CARDS/SC_ICH.C
Expand Up @@ -31,9 +31,13 @@
#define ICH_PO_CR_REG 0x1b // PCM out Control Register
#define ICH_PO_CR_START 0x01 // start codec
#define ICH_PO_CR_RESET 0x02 // reset codec
#define ICH_PO_CR_LVBIE 0x04 // last valid buffer interrupt enable
#define ICH_PO_CR_IOCE 0x10 // IOC enable

#define ICH_PO_SR_REG 0x16 // PCM out Status register
#define ICH_PO_SR_DCH 0x01 // DMA controller halted
#define ICH_PO_SR_LVBCI 0x04 // last valid buffer completion interrupt
#define ICH_PO_SR_BCIS 0x08 // buffer completion interrupt status (IOC)

#define ICH_GLOB_CNT_REG 0x2c // Global control register
#define ICH_GLOB_CNT_ACLINKOFF 0x00000008 // turn off ac97 link
Expand Down Expand Up @@ -64,6 +68,8 @@

#define ICH_DEFAULT_RETRY 1000

#define ICH_BD_IOC 0x8000

typedef struct intel_card_s
{
unsigned long baseport_bm; // busmaster baseport
Expand Down Expand Up @@ -208,6 +214,7 @@ static void snd_intel_chip_init(struct intel_card_s *card)
snd_intel_write_8(card,ICH_PO_CR_REG,ICH_PO_CR_RESET); // reset channels
#ifdef SBEMU
pds_mdelay(50);
snd_intel_write_8(card,ICH_PO_CR_REG,/*ICH_PO_CR_LVBIE*/ICH_PO_CR_IOCE);
#endif

mpxplay_debugf(ICH_DEBUG_OUTPUT,"chip init end");
Expand Down Expand Up @@ -293,7 +300,7 @@ static void snd_intel_prepare_playback(struct intel_card_s *card,struct mpxplay_
period_size_samples=card->period_size_bytes/(aui->bits_card>>3);
for(i=0; i<ICH_DMABUF_PERIODS; i++){
table_base[i*2]=(uint32_t)pds_cardmem_physicalptr(card->dm,(char *)card->pcmout_buffer+(i*card->period_size_bytes));
table_base[i*2+1]=period_size_samples;
table_base[i*2+1]=period_size_samples | (ICH_BD_IOC<<16);
}
snd_intel_write_32(card,ICH_PO_BDBAR_REG,(uint32_t)pds_cardmem_physicalptr(card->dm,table_base));

Expand Down Expand Up @@ -367,8 +374,8 @@ static int INTELICH_adetect(struct mpxplay_audioout_info_s *aui)
card->baseport_codec = pcibios_ReadConfig_Dword(card->pci_dev, PCIR_NAMBAR)&0xfff0;
if(!card->baseport_codec)
goto err_adetect;
card->irq = pcibios_ReadConfig_Byte(card->pci_dev, PCIR_INTR_LN);

aui->card_irq = card->irq = pcibios_ReadConfig_Byte(card->pci_dev, PCIR_INTR_LN);
card->device_type=card->pci_dev->device_type;

mpxplay_debugf(ICH_DEBUG_OUTPUT,"vend_id:%4.4X dev_id:%4.4X devtype:%s bmport:%4.4X mixport:%4.4X irq:%d",
Expand Down Expand Up @@ -572,6 +579,18 @@ static unsigned long INTELICH_readMIXER(struct mpxplay_audioout_info_s *aui,unsi
return snd_intel_codec_read(card,reg);
}

#ifdef SBEMU
static void INTELICH_IRQRoutine(mpxplay_audioout_info_s* aui)
{
intel_card_s *card=aui->card_private_data;
if(snd_intel_read_8(card,ICH_PO_SR_REG)&ICH_PO_SR_LVBCI)
snd_intel_write_8(card, ICH_PO_SR_REG, ICH_PO_SR_LVBCI);

if(snd_intel_read_8(card,ICH_PO_SR_REG)&ICH_PO_SR_BCIS)
snd_intel_write_8(card, ICH_PO_SR_REG, ICH_PO_SR_BCIS);
}
#endif

one_sndcard_info ICH_sndcard_info={
"ICH AC97",
SNDCARD_LOWLEVELHAND|SNDCARD_INT08_ALLOWED,
Expand All @@ -589,7 +608,11 @@ one_sndcard_info ICH_sndcard_info={
&INTELICH_getbufpos,
&MDma_clearbuf,
NULL, // ICH doesn't need dma-monitor (LVI handles it)
#ifdef SBEMU
&INTELICH_IRQRoutine,
#else
NULL,
#endif

&INTELICH_writeMIXER,
&INTELICH_readMIXER,
Expand Down

0 comments on commit de7c8bb

Please sign in to comment.