/* * external.c * * This file is part of Emu48 * * Copyright (C) 1995 Sebastien Carlier * Copyright (C) 2005 Christoph Gießelink * */ #include "pch.h" #include "Emu48.h" #include "ops.h" #define MUSIC_FREQ 11025 // this can be adjusted for quality //| 38G | 39G | 40G | 48SX | 48GX | 49G | Name //#F0E4F #80F0F #80F0F #706D2 #80850 #80F0F =SFLAG53_56 // memory address for flags -53 to -56 #define SFLAG53_56 ( (cCurrentRomType=='6') \ ? 0xE0E4F \ : ( (cCurrentRomType=='A') \ ? 0xF0E4F \ : ( (cCurrentRomType!='E' && cCurrentRomType!='X') \ ? ( (cCurrentRomType=='S') \ ? 0x706D2 \ : 0x80850 \ ) \ : 0x80F0F \ ) \ ) \ ) BOOL bWaveBeep = FALSE; // PC speaker DWORD dwWaveVol = 64; // wave sound volume static __inline VOID BeepWave(DWORD dwFrequency,DWORD dwDuration) { HWAVEOUT hSoundDevice; WAVEFORMATEX wf; WAVEHDR wh; HANDLE hEventSound; DWORD i; if (dwFrequency == 0) // this is just a delay { Sleep(dwDuration); return; } hEventSound = CreateEvent(NULL,FALSE,FALSE,NULL); wf.wFormatTag = WAVE_FORMAT_PCM; wf.nChannels = 1; wf.nSamplesPerSec = MUSIC_FREQ; wf.nAvgBytesPerSec = MUSIC_FREQ; wf.nBlockAlign = 1; wf.wBitsPerSample = 8; wf.cbSize = 0; if (waveOutOpen(&hSoundDevice,WAVE_MAPPER,&wf,(DWORD_PTR)hEventSound,0,CALLBACK_EVENT) != 0) { CloseHandle(hEventSound); // no sound available return; } // (samp/sec) * msecs * (secs/msec) = samps wh.dwBufferLength = (DWORD) ((QWORD) MUSIC_FREQ * dwDuration / 1000); VERIFY(wh.lpData = HeapAlloc(hHeap,0,wh.dwBufferLength)); wh.dwBytesRecorded = 0; wh.dwUser = 0; wh.dwFlags = 0; wh.dwLoops = 0; for (i = 0; i < wh.dwBufferLength; ++i) // generate square wave { wh.lpData[i] = (BYTE) ((((QWORD) 2 * dwFrequency * i / MUSIC_FREQ) & 1) * dwWaveVol); } VERIFY(waveOutPrepareHeader(hSoundDevice,&wh,sizeof(wh)) == MMSYSERR_NOERROR); ResetEvent(hEventSound); // prepare event for finishing VERIFY(waveOutWrite(hSoundDevice,&wh,sizeof(wh)) == MMSYSERR_NOERROR); WaitForSingleObject(hEventSound,INFINITE); // wait for finishing VERIFY(waveOutUnprepareHeader(hSoundDevice,&wh,sizeof(wh)) == MMSYSERR_NOERROR); VERIFY(waveOutClose(hSoundDevice) == MMSYSERR_NOERROR); HeapFree(hHeap,0,wh.lpData); CloseHandle(hEventSound); return; } static __inline VOID BeepWin9x(DWORD dwFrequency,DWORD dwDuration) { #if !defined _WIN64 #define PIT8254_CNT2 0x42 #define PIT8254_MCR 0x43 #define PPI8255_PBO 0x61 BYTE bySpk = _inp(PPI8255_PBO); // get current status if (dwFrequency != 0) { WORD wCount; // limit low frequency if (lFreq.QuadPart / 65535 >= dwFrequency) dwFrequency = (DWORD) (lFreq.QuadPart / 65535) + 1; // determine the timer frequency wCount = (WORD) (lFreq.QuadPart / dwFrequency); _outp(PIT8254_MCR,0xB6); // set up the timer _outp(PIT8254_CNT2,wCount&0xff); _outp(PIT8254_CNT2,wCount>>8); _outp(PPI8255_PBO,bySpk | 0x03); // turn on the speaker } Sleep(dwDuration); _outp(PPI8255_PBO,bySpk & 0xFC); // turn off the speaker return; #undef PIT8254_CNT2 #undef PIT8254_MCR #undef PPI8255_PBO #endif } static VOID Beeper(DWORD freq,DWORD dur) { if (bWaveBeep) { BeepWave(freq,dur); // wave output over sound card } else { OSVERSIONINFO version; version.dwOSVersionInfoSize = sizeof(version); GetVersionEx(&version); if (version.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) { BeepWin9x(freq,dur); // do it the hard way on '9x / Me } else // VER_PLATFORM_WIN32_NT { if (freq < 37) freq = 37; // low limit of freqency (NT) _ASSERT(freq >= 0x25 && freq <= 0x7FFF); Beep(freq,dur); // NT: ok, Windows 95: default sound or standard system beep } } return; } VOID External(CHIPSET* w) // Beep patch { BYTE fbeep; DWORD freq,dur; freq = Npack(w->D,5); // frequency in Hz dur = Npack(w->C,5); // duration in ms Nread(&fbeep,SFLAG53_56,1); // fetch system flags -53 to -56 w->carry = TRUE; // setting of no beep if (!(fbeep & 0x8) && freq) // bit -56 clear and frequency > 0 Hz { if (freq > 4400) freq = 4400; // high limit of HP (SX) Beeper(freq,dur); // beeping // estimate cpu cycles for beeping time (2MHz / 4MHz) w->cycles += dur * ((cCurrentRomType=='S') ? 2000 : 4000); // original routine return with... w->P = 0; // P=0 w->intk = TRUE; // INTON w->carry = FALSE; // RTNCC } w->pc = rstkpop(); return; } VOID RCKBp(CHIPSET* w) // ROM Check Beep patch { DWORD dw2F,dwCpuFreq; DWORD freq,dur; BYTE f,d; f = w->C[1]; // f = freq ctl d = w->C[0]; // d = duration ctl if (cCurrentRomType == 'S') // Clarke chip with 48S ROM { // CPU strobe frequency @ RATE 14 = 1.97MHz dwCpuFreq = ((14 + 1) * 524288) >> 2; dw2F = f * 126 + 262; // F=f*63+131 } else // York chip with 48G and later ROM { // CPU strobe frequency @ RATE 27 = 3.67MHz // CPU strobe frequency @ RATE 29 = 3.93MHz dwCpuFreq = ((27 + 1) * 524288) >> 2; dw2F = f * 180 + 367; // F=f*90+183.5 } freq = dwCpuFreq / dw2F; dur = (dw2F * (256 - 16 * d)) * 1000 / 2 / dwCpuFreq; if (freq > 4400) freq = 4400; // high limit of HP Beeper(freq,dur); // beeping // estimate cpu cycles for beeping time (2MHz / 4MHz) w->cycles += dur * ((cCurrentRomType=='S') ? 2000 : 4000); w->P = 0; // P=0 w->carry = FALSE; // RTNCC w->pc = rstkpop(); return; }