diff --git a/AppleWin/source/Mockingboard.cpp b/AppleWin/source/Mockingboard.cpp index 6911454c..73c0badf 100644 --- a/AppleWin/source/Mockingboard.cpp +++ b/AppleWin/source/Mockingboard.cpp @@ -149,6 +149,7 @@ static USHORT g_nMBTimerDevice = 0; // SY6522 device# which is generating timer // SSI263 vars: static USHORT g_nSSI263Device = 0; // SSI263 device# which is generating phoneme-complete IRQ static int g_nCurrentActivePhoneme = -1; +static bool g_bStopPhoneme = false; static bool g_bVotraxPhoneme = false; static const DWORD SAMPLE_RATE = 44100; // Use a base freq so that DirectX (or sound h/w) doesn't have to up/down-sample @@ -303,16 +304,20 @@ static void UpdateIFR(SY6522_AY8910* pMB) for(UINT i=0; inAY8910Number & 1) - CpuNmiAssert(IS_6522); - else - CpuIrqAssert(IS_6522); + { + CpuIrqAssert(IS_6522); + } else - if (pMB->nAY8910Number & 1) - CpuNmiDeassert(IS_6522); - else - CpuIrqDeassert(IS_6522); + { + CpuIrqDeassert(IS_6522); + } } static void SY6522_Write(BYTE nDevice, BYTE nReg, BYTE nValue) @@ -574,16 +579,20 @@ static void SSI263_Write(BYTE nDevice, BYTE nReg, BYTE nValue) // Datasheet is not clear, but a write to DURPHON must clear the IRQ if(g_bPhasorEnable) - if (pMB->nAY8910Number & 1) - CpuNmiDeassert(IS_SPEECH); - else - CpuIrqDeassert(IS_SPEECH); - pMB->sy6522.IFR &= ~IxR_PERIPHERAL; - UpdateIFR(pMB); + { + CpuIrqDeassert(IS_SPEECH); + } + else + { + pMB->sy6522.IFR &= ~IxR_PERIPHERAL; + UpdateIFR(pMB); + } pMB->SpeechChip.CurrentMode &= ~1; // Clear SSI263's D7 pin pMB->SpeechChip.DurationPhonome = nValue; + g_nSSI263Device = nDevice; + // Phoneme output not dependent on CONTROL bit if(g_bPhasorEnable) { @@ -594,7 +603,6 @@ static void SSI263_Write(BYTE nDevice, BYTE nReg, BYTE nValue) { SSI263_Play(nValue & PHONEME_MASK); } - g_nSSI263Device = nDevice; break; case SSI_INFLECT: #if LOG_SSI263 @@ -709,6 +717,8 @@ static void Votrax_Write(BYTE nDevice, BYTE nValue) pMB->sy6522.IFR &= ~IxR_VOTRAX; UpdateIFR(pMB); + g_nSSI263Device = nDevice; + SSI263_Play(Votrax2SSI263[nValue & PHONEME_MASK]); } @@ -891,6 +901,16 @@ static DWORD WINAPI SSI263Thread(LPVOID lpParameter) // Phoneme completed playing + if (g_bStopPhoneme) + { + g_bStopPhoneme = false; + continue; + } + +#if LOG_SSI263 + //if(g_fh) fprintf(g_fh, "IRQ: Phoneme complete (0x%02X)\n\n", g_nCurrentActivePhoneme); +#endif + SSI263Voice[g_nCurrentActivePhoneme].bActive = false; g_nCurrentActivePhoneme = -1; @@ -903,11 +923,8 @@ static DWORD WINAPI SSI263Thread(LPVOID lpParameter) { pMB->SpeechChip.CurrentMode |= 1; // Set SSI263's D7 pin - // Is Phasor's SSI263.IRQ wired directly to IRQ? (Bypassing the 6522) - if (pMB->nAY8910Number & 1) - CpuNmiAssert(IS_SPEECH); - else - CpuIrqAssert(IS_SPEECH); + // Phasor's SSI263.IRQ line appears to be wired directly to IRQ (Bypassing the 6522) + CpuIrqAssert(IS_SPEECH); } } else @@ -944,7 +961,11 @@ static void SSI263_Play(unsigned int nPhoneme) HRESULT hr; if(g_nCurrentActivePhoneme >= 0) + { + // A write to DURPHON before previous phoneme has completed + g_bStopPhoneme = true; hr = SSI263Voice[g_nCurrentActivePhoneme].lpDSBvoice->Stop(); + } g_nCurrentActivePhoneme = nPhoneme; @@ -1106,7 +1127,8 @@ static bool MB_DSInit() unsigned int nPhonemeByteLength = g_nPhonemeInfo[nPhoneme].nLength * sizeof(SHORT); - hr = DSGetSoundBuffer(&SSI263Voice[i], DSBCAPS_CTRLVOLUME+DSBCAPS_CTRLPOSITIONNOTIFY, nPhonemeByteLength, 22050, 1); + // NB. DSBCAPS_LOCSOFTWARE required for Phoneme+2==0x28 - sample too short (see KB327698) + hr = DSGetSoundBuffer(&SSI263Voice[i], DSBCAPS_CTRLVOLUME+DSBCAPS_CTRLPOSITIONNOTIFY+DSBCAPS_LOCSOFTWARE, nPhonemeByteLength, 22050, 1); if(FAILED(hr)) { if(g_fh) fprintf(g_fh, "SSI263: DSGetSoundBuffer failed (%08X)\n",hr);