From 1b31b614d2a608b3dcc3e9fb416c28a23d026a76 Mon Sep 17 00:00:00 2001 From: InvisibleUp Date: Thu, 30 Apr 2020 20:13:16 -0400 Subject: [PATCH] Split out sound and timing funcs from OSGLUWIN.c --- Makefile | 2 + src/UI/WIN32/OSGLUWIN.c | 502 +--------------------------------------- src/UI/WIN32/OSGLUWIN.h | 32 +++ src/UI/WIN32/SOUND.c | 292 +++++++++++++++++++++++ src/UI/WIN32/SOUND.h | 56 +++++ src/UI/WIN32/TIMEDATE.c | 137 +++++++++++ 6 files changed, 520 insertions(+), 501 deletions(-) create mode 100644 src/UI/WIN32/SOUND.c create mode 100644 src/UI/WIN32/SOUND.h create mode 100644 src/UI/WIN32/TIMEDATE.c diff --git a/Makefile b/Makefile index 5609c6e..9c0a306 100644 --- a/Makefile +++ b/Makefile @@ -31,6 +31,8 @@ Win32Files := \ src/UI/WIN32/INTLKBRD.c \ src/UI/WIN32/DBGLOG.c \ src/UI/WIN32/KEYBOARD.c \ + src/UI/WIN32/SOUND.c \ + src/UI/WIN32/TIMEDATE.c \ windows : mkdir -p "bld/" diff --git a/src/UI/WIN32/OSGLUWIN.c b/src/UI/WIN32/OSGLUWIN.c index 3da6c50..4de7e50 100644 --- a/src/UI/WIN32/OSGLUWIN.c +++ b/src/UI/WIN32/OSGLUWIN.c @@ -36,6 +36,7 @@ #include "CNFGGLOB.h" #include "SYSDEPNS.h" #include "UTIL/ENDIANAC.h" +#include "UTIL/DATE2SEC.h" #include "UI/COMOSGLU.h" #include "UI/MYOSGLUE.h" @@ -380,507 +381,6 @@ LOCALPROC LowerPriority(void) #endif -/* --- time, date, location --- */ - -#define dbglog_TimeStuff (0 && dbglog_HAVE) - -LOCALVAR uint32_t TrueEmulatedTime = 0; - -#define InvTimeDivPow 16 -#define InvTimeDiv (1 << InvTimeDivPow) -#define InvTimeDivMask (InvTimeDiv - 1) -#define InvTimeStep 1089590 /* 1000 / 60.14742 * InvTimeDiv */ - -LOCALVAR DWORD LastTime; - -LOCALVAR DWORD NextIntTime; -LOCALVAR uint32_t NextFracTime; - -LOCALPROC IncrNextTime(void) -{ - NextFracTime += InvTimeStep; - NextIntTime += (NextFracTime >> InvTimeDivPow); - NextFracTime &= InvTimeDivMask; -} - -LOCALPROC InitNextTime(void) -{ - NextIntTime = LastTime; - NextFracTime = 0; - IncrNextTime(); -} - -LOCALFUNC bool UpdateTrueEmulatedTime(void) -{ - DWORD LatestTime; - int32_t TimeDiff; - - LatestTime = timeGetTime(); - if (LatestTime != LastTime) { - LastTime = LatestTime; - TimeDiff = (LatestTime - NextIntTime); - /* this should work even when time wraps */ - if (TimeDiff >= 0) { - if (TimeDiff > 256) { - /* emulation interrupted, forget it */ - ++TrueEmulatedTime; - InitNextTime(); - -#if dbglog_TimeStuff - dbglog_writelnNum("emulation interrupted", - TrueEmulatedTime); -#endif - } else { - do { - ++TrueEmulatedTime; - IncrNextTime(); - TimeDiff = (LatestTime - NextIntTime); - } while (TimeDiff >= 0); - } - return true; - } else if (TimeDiff < -256) { - /* clock goofed if ever get here, reset */ -#if dbglog_TimeStuff - dbglog_writeln("clock set back"); -#endif - - InitNextTime(); - } - } - return false; -} - -LOCALVAR uint32_t TimeSecBase; -LOCALVAR DWORD TimeMilliBase; - -#include "UTIL/DATE2SEC.h" - -LOCALFUNC bool CheckDateTime(void) -{ - uint32_t NewMacDateInSecond; - - NewMacDateInSecond = - ((uint32_t)(LastTime - TimeMilliBase)) / 1000 + TimeSecBase; - if (CurMacDateInSeconds != NewMacDateInSecond) { - CurMacDateInSeconds = NewMacDateInSecond; - - return true; - } else { - return false; - } -} - -LOCALFUNC bool Init60thCheck(void) -{ - SYSTEMTIME s; -#if AutoTimeZone - TIME_ZONE_INFORMATION r; - DWORD v; -#endif - DWORD t; - - GetLocalTime(&s); - t = timeGetTime(); - TimeSecBase = Date2MacSeconds(s.wSecond, s.wMinute, s.wHour, - s.wDay, s.wMonth, s.wYear); - TimeMilliBase = t - s.wMilliseconds; - -#if AutoTimeZone - v = GetTimeZoneInformation(&r); - if ((v != 0xFFFFFFFF) && (v != TIME_ZONE_ID_UNKNOWN)) { - int32_t dlsBias = (v != TIME_ZONE_ID_DAYLIGHT) - ? r.StandardBias : r.DaylightBias; - CurMacDelta = (((uint32_t)(- (r.Bias + dlsBias) * 60)) - & 0x00FFFFFF) - | (((v != TIME_ZONE_ID_DAYLIGHT) ? 0 : 0x80) - << 24); - } -#endif - - LastTime = timeGetTime(); - InitNextTime(); - - OnTrueTime = TrueEmulatedTime; - - (void) CheckDateTime(); - - return true; -} - -#ifndef TimeResolution -#define TimeResolution 3 -#endif - /* - Setting TimeResolution to 1 seems to drastically slow down - the clock in Virtual PC 7.0.2 for Mac. Using 3 is more polite - anyway, and should not cause much observable difference. - */ - -#if (TimeResolution != 0) -LOCALVAR bool HaveSetTimeResolution = false; -#endif - -#if (TimeResolution != 0) -LOCALPROC Timer_Suspend(void) -{ - if (HaveSetTimeResolution) { - (void) timeEndPeriod(TimeResolution); - HaveSetTimeResolution = false; - } -} -#endif - -#if (TimeResolution != 0) -LOCALPROC Timer_Resume(void) -{ - TIMECAPS tc; - - if (timeGetDevCaps(&tc, sizeof(TIMECAPS)) - == TIMERR_NOERROR) - { - if ((TimeResolution >= tc.wPeriodMin) - && (TimeResolution <= tc.wPeriodMax)) - { - if (timeBeginPeriod(TimeResolution) - == TIMERR_NOERROR) - { - HaveSetTimeResolution = true; - } - } - } -} -#endif - -/* --- sound --- */ - -#if SoundEnabled - - -#define kLn2SoundBuffers 4 /* kSoundBuffers must be a power of two */ -#define kSoundBuffers (1 << kLn2SoundBuffers) -#define kSoundBuffMask (kSoundBuffers - 1) - -#define DesiredMinFilledSoundBuffs 3 - /* - if too big then sound lags behind emulation. - if too small then sound will have pauses. - */ - -#define kLnOneBuffLen 9 -#define kLnAllBuffLen (kLn2SoundBuffers + kLnOneBuffLen) -#define kOneBuffLen (1UL << kLnOneBuffLen) -#define kAllBuffLen (1UL << kLnAllBuffLen) -#define kLnOneBuffSz (kLnOneBuffLen + kLn2SoundSampSz - 3) -#define kLnAllBuffSz (kLnAllBuffLen + kLn2SoundSampSz - 3) -#define kOneBuffSz (1UL << kLnOneBuffSz) -#define kAllBuffSz (1UL << kLnAllBuffSz) -#define kOneBuffMask (kOneBuffLen - 1) -#define kAllBuffMask (kAllBuffLen - 1) -#define dbhBufferSize (kAllBuffSz + kOneBuffSz) - -#define dbglog_SoundStuff (0 && dbglog_HAVE) -#define dbglog_SoundBuffStats (0 && dbglog_HAVE) - -LOCALVAR tpSoundSamp TheSoundBuffer = nullpr; -LOCALVAR uint16_t ThePlayOffset; -LOCALVAR uint16_t TheFillOffset; -LOCALVAR bool wantplaying; -LOCALVAR uint16_t MinFilledSoundBuffs; -LOCALVAR uint16_t TheWriteOffset; - -#define SOUND_SAMPLERATE /* 22050 */ 22255 - /* = round(7833600 * 2 / 704) */ - - -LOCALPROC FillWithSilence(tpSoundSamp p, int n, trSoundSamp v) -{ - int i; - - for (i = n; --i >= 0; ) { - *p++ = v; - } -} - - -LOCALVAR HWAVEOUT hWaveOut = NULL; -LOCALVAR WAVEHDR whdr[kSoundBuffers]; - - -LOCALPROC Sound_BeginPlaying(void) -{ -#if dbglog_SoundStuff - fprintf(stderr, "Sound_BeginPlaying\n"); -#endif -} - -LOCALPROC Sound_Start(void) -{ - if (hWaveOut == NULL) { - WAVEFORMATEX wfex; - MMRESULT mmr; - int i; - tpSoundSamp p; - WAVEHDR *pwh; - - wfex.wFormatTag = WAVE_FORMAT_PCM; - wfex.nChannels = 1; - wfex.nSamplesPerSec = SOUND_SAMPLERATE; - wfex.nAvgBytesPerSec = SOUND_SAMPLERATE; -#if 3 == kLn2SoundSampSz - wfex.nBlockAlign = 1; - wfex.wBitsPerSample = 8; -#elif 4 == kLn2SoundSampSz - wfex.nBlockAlign = 2; - wfex.wBitsPerSample = 16; -#else -#error "unsupported audio format" -#endif - wfex.cbSize = 0; - mmr = waveOutOpen(&hWaveOut, WAVE_MAPPER, &wfex, 0, - 0 /* (DWORD) AppInstance */, CALLBACK_NULL); - if (mmr != MMSYSERR_NOERROR) { - /* - not recursive: - MacMsg("waveOutOpen failed", - "Sorry, Mini vMac encountered errors" - " and cannot continue.", true); - */ - } else { - p = TheSoundBuffer; - pwh = whdr; - for (i = 0; i < kSoundBuffers; ++i) { - pwh->lpData = (LPSTR)p; - pwh->dwBufferLength = kOneBuffSz; - pwh->dwBytesRecorded = 0; - pwh->dwUser = 0; - pwh->dwFlags = 0; - pwh->dwLoops = 0; - mmr = waveOutPrepareHeader(hWaveOut, pwh, - sizeof(WAVEHDR)); - if (mmr != MMSYSERR_NOERROR) { - /* - not recursive: - MacMsg("waveOutPrepareHeader failed", - "Sorry, Mini vMac encountered errors" - " and cannot continue.", true); - */ - } else { - pwh->dwFlags |= WHDR_DONE; - } - p += kOneBuffLen; - ++pwh; - } - - TheFillOffset = 0; - ThePlayOffset = 0; - TheWriteOffset = 0; - MinFilledSoundBuffs = kSoundBuffers; - wantplaying = false; - } - } -} - -LOCALPROC Sound_Stop(void) -{ - MMRESULT mmr; - int i; - - wantplaying = false; - if (hWaveOut != NULL) { - DWORD StartTime = GetTickCount(); - for (i = 0; i < kSoundBuffers; ++i) { - while (((whdr[i].dwFlags & WHDR_DONE) == 0) - && ((uint32_t)(GetTickCount() - StartTime) < 1000)) - { - Sleep(1); - } - - mmr = waveOutUnprepareHeader(hWaveOut, &whdr[i], - sizeof(WAVEHDR)); - if (mmr != MMSYSERR_NOERROR) { - /* - not recursive: - MacMsg("waveOutUnprepareHeader failed", - "Sorry, Mini vMac encountered errors" - " and cannot continue.", true); - */ - } - } - - mmr = waveOutClose(hWaveOut); - if (mmr != MMSYSERR_NOERROR) { - /* - MacMsg("waveOutClose failed", - "Sorry, Mini vMac encountered errors" - " and cannot continue.", true); - */ - } - hWaveOut = NULL; - } -} - -LOCALPROC SoundCheckVeryOften(void) -{ - if ((hWaveOut != NULL) && (wantplaying)) { -label_retry: - { - uint16_t FilledSoundBuffs; - uint16_t ToPlaySize = TheFillOffset - ThePlayOffset; - uint16_t CurPlayBuffer = - (ThePlayOffset >> kLnOneBuffLen) & kSoundBuffMask; - - if ((ToPlaySize > kOneBuffLen) - && ((whdr[CurPlayBuffer].dwFlags & WHDR_DONE) != 0)) - { - ThePlayOffset += kOneBuffLen; - goto label_retry; - } - FilledSoundBuffs = ToPlaySize >> kLnOneBuffLen; - - if (FilledSoundBuffs < MinFilledSoundBuffs) { - MinFilledSoundBuffs = FilledSoundBuffs; - } - - if (FilledSoundBuffs < 2) { - MMRESULT mmr; - uint16_t PrevPlayOffset = ThePlayOffset - kOneBuffLen; - uint16_t PrevPlayBuffer = - (PrevPlayOffset >> kLnOneBuffLen) & kSoundBuffMask; - uint16_t LastPlayedOffset = - ((TheFillOffset >> kLnOneBuffLen) << kLnOneBuffLen) - - 1; - - FillWithSilence( - TheSoundBuffer + (PrevPlayOffset & kAllBuffMask), - kOneBuffLen, - *(TheSoundBuffer - + (LastPlayedOffset & kAllBuffMask))); - mmr = waveOutWrite( - hWaveOut, &whdr[PrevPlayBuffer], sizeof(WAVEHDR)); - if (mmr != MMSYSERR_NOERROR) { - whdr[PrevPlayBuffer].dwFlags |= WHDR_DONE; - /* - not recursive: - MacMsg("waveOutWrite failed", - "Sorry, Mini vMac encountered errors" - " and cannot continue.", true); - */ - } - ThePlayOffset = PrevPlayOffset; - goto label_retry; - } - } - } -} - -#if 4 == kLn2SoundSampSz -LOCALPROC ConvertSoundBlockToNative(tpSoundSamp p) -{ - int i; - - for (i = kOneBuffLen; --i >= 0; ) { - *p++ -= 0x8000; - } -} -#else -#define ConvertSoundBlockToNative(p) -#endif - -LOCALPROC Sound_FilledBlocks(void) -{ - while (0 != ((TheWriteOffset - TheFillOffset) >> kLnOneBuffLen)) { - uint16_t CurFillBuffer = - (TheFillOffset >> kLnOneBuffLen) & kSoundBuffMask; - bool IsOk = false; - - ConvertSoundBlockToNative((tpSoundSamp) - whdr[CurFillBuffer].lpData); - - if (hWaveOut != NULL) { - MMRESULT mmr = waveOutWrite(hWaveOut, - &whdr[CurFillBuffer], sizeof(WAVEHDR)); - if (mmr == MMSYSERR_NOERROR) { - IsOk = true; - } - } - - if (! IsOk) { - /* - not recursive: - MacMsg("waveOutWrite failed", - "Sorry, Mini vMac encountered errors" - " and cannot continue.", true); - */ - whdr[CurFillBuffer].dwFlags |= WHDR_DONE; - } - - TheFillOffset += kOneBuffLen; - } -} - -LOCALPROC Sound_WroteABlock(void) -{ - if (wantplaying) { - Sound_FilledBlocks(); - } else if (((TheWriteOffset - ThePlayOffset) >> kLnOneBuffLen) < 12) - { - /* just wait */ - } else { - Sound_FilledBlocks(); - wantplaying = true; - Sound_BeginPlaying(); - } -} - -GLOBALOSGLUPROC Sound_EndWrite(uint16_t actL) -{ - TheWriteOffset += actL; - - if (0 == (TheWriteOffset & kOneBuffMask)) { - /* just finished a block */ - - Sound_WroteABlock(); - } -} - -GLOBALOSGLUFUNC tpSoundSamp Sound_BeginWrite(uint16_t n, uint16_t *actL) -{ - uint16_t ToFillLen = kAllBuffLen - (TheWriteOffset - ThePlayOffset); - uint16_t WriteBuffContig = - kOneBuffLen - (TheWriteOffset & kOneBuffMask); - - if (WriteBuffContig < n) { - n = WriteBuffContig; - } - if (ToFillLen < n) { - /* overwrite previous buffer */ - TheWriteOffset -= kOneBuffLen; - } - - *actL = n; - return TheSoundBuffer + (TheWriteOffset & kAllBuffMask); -} - -LOCALPROC Sound_SecondNotify(void) -{ - if (hWaveOut != NULL) { - if (MinFilledSoundBuffs > DesiredMinFilledSoundBuffs) { -#if dbglog_SoundStuff - dbglog_writeln("MinFilledSoundBuffs too high"); -#endif - IncrNextTime(); - } else if (MinFilledSoundBuffs < DesiredMinFilledSoundBuffs) { -#if dbglog_SoundStuff - dbglog_writeln("MinFilledSoundBuffs too low"); -#endif - ++TrueEmulatedTime; - } - MinFilledSoundBuffs = kSoundBuffers; - } -} - -#endif - /* --- overall grab --- */ #if MayFullScreen diff --git a/src/UI/WIN32/OSGLUWIN.h b/src/UI/WIN32/OSGLUWIN.h index a733c84..1a9be7c 100644 --- a/src/UI/WIN32/OSGLUWIN.h +++ b/src/UI/WIN32/OSGLUWIN.h @@ -6,6 +6,7 @@ #include "CNFGGLOB.h" #include "UI/COMOSGLU.h" #include "UI/CONTROLM.h" +#include "UI/WIN32/SOUND.h" /* Define the undefined */ @@ -27,6 +28,15 @@ #define EnableGrabSpecialKeys (MayFullScreen && GrabKeysFullScreen) #endif /* EnableGrabSpecialKeys */ +/* + Setting TimeResolution to 1 seems to drastically slow down + the clock in Virtual PC 7.0.2 for Mac. Using 3 is more polite + anyway, and should not cause much observable difference. +*/ +#ifndef TimeResolution +#define TimeResolution 3 +#endif + /* Resource Ids */ #define IDI_VMAC 256 @@ -124,4 +134,26 @@ void UnGrabSpecialKeys(void); void CheckForLostKeyUps(void); #endif +/* --- time, date, location --- */ + +#define dbglog_TimeStuff (0 && dbglog_HAVE) + +extern uint32_t TrueEmulatedTime; + +#define InvTimeDivPow 16 +#define InvTimeDiv (1 << InvTimeDivPow) +#define InvTimeDivMask (InvTimeDiv - 1) +#define InvTimeStep 1089590 /* 1000 / 60.14742 * InvTimeDiv */ + +DWORD LastTime; +DWORD NextIntTime; + +void IncrNextTime(void); +void InitNextTime(void); +bool UpdateTrueEmulatedTime(void); +bool CheckDateTime(void); +bool Init60thCheck(void); +void Timer_Suspend(void); +void Timer_Resume(void); + #endif // OSGLUWIN_H diff --git a/src/UI/WIN32/SOUND.c b/src/UI/WIN32/SOUND.c new file mode 100644 index 0000000..464174c --- /dev/null +++ b/src/UI/WIN32/SOUND.c @@ -0,0 +1,292 @@ +/* --- sound --- */ + +#include "OSGLUWIN.h" + +#if SoundEnabled +#include "UI/WIN32/SOUND.h" +tpSoundSamp TheSoundBuffer = nullpr; +HWAVEOUT hWaveOut = NULL; + +void FillWithSilence(tpSoundSamp p, int n, trSoundSamp v) +{ + int i; + + for (i = n; --i >= 0; ) { + *p++ = v; + } +} + +void Sound_BeginPlaying(void) +{ +#if dbglog_SoundStuff + fprintf(stderr, "Sound_BeginPlaying\n"); +#endif +} + +void Sound_Start(void) +{ + if (hWaveOut == NULL) { + WAVEFORMATEX wfex; + MMRESULT mmr; + int i; + tpSoundSamp p; + WAVEHDR *pwh; + + wfex.wFormatTag = WAVE_FORMAT_PCM; + wfex.nChannels = 1; + wfex.nSamplesPerSec = SOUND_SAMPLERATE; + wfex.nAvgBytesPerSec = SOUND_SAMPLERATE; +#if 3 == kLn2SoundSampSz + wfex.nBlockAlign = 1; + wfex.wBitsPerSample = 8; +#elif 4 == kLn2SoundSampSz + wfex.nBlockAlign = 2; + wfex.wBitsPerSample = 16; +#else +#error "unsupported audio format" +#endif + wfex.cbSize = 0; + mmr = waveOutOpen(&hWaveOut, WAVE_MAPPER, &wfex, 0, + 0 /* (DWORD) AppInstance */, CALLBACK_NULL); + if (mmr != MMSYSERR_NOERROR) { + /* + not recursive: + MacMsg("waveOutOpen failed", + "Sorry, Mini vMac encountered errors" + " and cannot continue.", true); + */ + } else { + p = TheSoundBuffer; + pwh = whdr; + for (i = 0; i < kSoundBuffers; ++i) { + pwh->lpData = (LPSTR)p; + pwh->dwBufferLength = kOneBuffSz; + pwh->dwBytesRecorded = 0; + pwh->dwUser = 0; + pwh->dwFlags = 0; + pwh->dwLoops = 0; + mmr = waveOutPrepareHeader(hWaveOut, pwh, + sizeof(WAVEHDR)); + if (mmr != MMSYSERR_NOERROR) { + /* + not recursive: + MacMsg("waveOutPrepareHeader failed", + "Sorry, Mini vMac encountered errors" + " and cannot continue.", true); + */ + } else { + pwh->dwFlags |= WHDR_DONE; + } + p += kOneBuffLen; + ++pwh; + } + + TheFillOffset = 0; + ThePlayOffset = 0; + TheWriteOffset = 0; + MinFilledSoundBuffs = kSoundBuffers; + wantplaying = false; + } + } +} + +void Sound_Stop(void) +{ + MMRESULT mmr; + int i; + + wantplaying = false; + if (hWaveOut != NULL) { + DWORD StartTime = GetTickCount(); + for (i = 0; i < kSoundBuffers; ++i) { + while (((whdr[i].dwFlags & WHDR_DONE) == 0) + && ((uint32_t)(GetTickCount() - StartTime) < 1000)) + { + Sleep(1); + } + + mmr = waveOutUnprepareHeader(hWaveOut, &whdr[i], + sizeof(WAVEHDR)); + if (mmr != MMSYSERR_NOERROR) { + /* + not recursive: + MacMsg("waveOutUnprepareHeader failed", + "Sorry, Mini vMac encountered errors" + " and cannot continue.", true); + */ + } + } + + mmr = waveOutClose(hWaveOut); + if (mmr != MMSYSERR_NOERROR) { + /* + MacMsg("waveOutClose failed", + "Sorry, Mini vMac encountered errors" + " and cannot continue.", true); + */ + } + hWaveOut = NULL; + } +} + +void SoundCheckVeryOften(void) +{ + if ((hWaveOut != NULL) && (wantplaying)) { +label_retry: + { + uint16_t FilledSoundBuffs; + uint16_t ToPlaySize = TheFillOffset - ThePlayOffset; + uint16_t CurPlayBuffer = + (ThePlayOffset >> kLnOneBuffLen) & kSoundBuffMask; + + if ((ToPlaySize > kOneBuffLen) + && ((whdr[CurPlayBuffer].dwFlags & WHDR_DONE) != 0)) + { + ThePlayOffset += kOneBuffLen; + goto label_retry; + } + FilledSoundBuffs = ToPlaySize >> kLnOneBuffLen; + + if (FilledSoundBuffs < MinFilledSoundBuffs) { + MinFilledSoundBuffs = FilledSoundBuffs; + } + + if (FilledSoundBuffs < 2) { + MMRESULT mmr; + uint16_t PrevPlayOffset = ThePlayOffset - kOneBuffLen; + uint16_t PrevPlayBuffer = + (PrevPlayOffset >> kLnOneBuffLen) & kSoundBuffMask; + uint16_t LastPlayedOffset = + ((TheFillOffset >> kLnOneBuffLen) << kLnOneBuffLen) + - 1; + + FillWithSilence( + TheSoundBuffer + (PrevPlayOffset & kAllBuffMask), + kOneBuffLen, + *(TheSoundBuffer + + (LastPlayedOffset & kAllBuffMask))); + mmr = waveOutWrite( + hWaveOut, &whdr[PrevPlayBuffer], sizeof(WAVEHDR)); + if (mmr != MMSYSERR_NOERROR) { + whdr[PrevPlayBuffer].dwFlags |= WHDR_DONE; + /* + not recursive: + MacMsg("waveOutWrite failed", + "Sorry, Mini vMac encountered errors" + " and cannot continue.", true); + */ + } + ThePlayOffset = PrevPlayOffset; + goto label_retry; + } + } + } +} + +#if 4 == kLn2SoundSampSz +void ConvertSoundBlockToNative(tpSoundSamp p) +{ + int i; + + for (i = kOneBuffLen; --i >= 0; ) { + *p++ -= 0x8000; + } +} +#else +#define ConvertSoundBlockToNative(p) +#endif + +void Sound_FilledBlocks(void) +{ + while (0 != ((TheWriteOffset - TheFillOffset) >> kLnOneBuffLen)) { + uint16_t CurFillBuffer = + (TheFillOffset >> kLnOneBuffLen) & kSoundBuffMask; + bool IsOk = false; + + ConvertSoundBlockToNative((tpSoundSamp) + whdr[CurFillBuffer].lpData); + + if (hWaveOut != NULL) { + MMRESULT mmr = waveOutWrite(hWaveOut, + &whdr[CurFillBuffer], sizeof(WAVEHDR)); + if (mmr == MMSYSERR_NOERROR) { + IsOk = true; + } + } + + if (! IsOk) { + /* + not recursive: + MacMsg("waveOutWrite failed", + "Sorry, Mini vMac encountered errors" + " and cannot continue.", true); + */ + whdr[CurFillBuffer].dwFlags |= WHDR_DONE; + } + + TheFillOffset += kOneBuffLen; + } +} + +void Sound_WroteABlock(void) +{ + if (wantplaying) { + Sound_FilledBlocks(); + } else if (((TheWriteOffset - ThePlayOffset) >> kLnOneBuffLen) < 12) + { + /* just wait */ + } else { + Sound_FilledBlocks(); + wantplaying = true; + Sound_BeginPlaying(); + } +} + +void Sound_EndWrite(uint16_t actL) +{ + TheWriteOffset += actL; + + if (0 == (TheWriteOffset & kOneBuffMask)) { + /* just finished a block */ + + Sound_WroteABlock(); + } +} + +tpSoundSamp Sound_BeginWrite(uint16_t n, uint16_t *actL) +{ + uint16_t ToFillLen = kAllBuffLen - (TheWriteOffset - ThePlayOffset); + uint16_t WriteBuffContig = + kOneBuffLen - (TheWriteOffset & kOneBuffMask); + + if (WriteBuffContig < n) { + n = WriteBuffContig; + } + if (ToFillLen < n) { + /* overwrite previous buffer */ + TheWriteOffset -= kOneBuffLen; + } + + *actL = n; + return TheSoundBuffer + (TheWriteOffset & kAllBuffMask); +} + +void Sound_SecondNotify(void) +{ + if (hWaveOut != NULL) { + if (MinFilledSoundBuffs > DesiredMinFilledSoundBuffs) { +#if dbglog_SoundStuff + dbglog_writeln("MinFilledSoundBuffs too high"); +#endif + IncrNextTime(); + } else if (MinFilledSoundBuffs < DesiredMinFilledSoundBuffs) { +#if dbglog_SoundStuff + dbglog_writeln("MinFilledSoundBuffs too low"); +#endif + ++TrueEmulatedTime; + } + MinFilledSoundBuffs = kSoundBuffers; + } +} + +#endif diff --git a/src/UI/WIN32/SOUND.h b/src/UI/WIN32/SOUND.h new file mode 100644 index 0000000..501308b --- /dev/null +++ b/src/UI/WIN32/SOUND.h @@ -0,0 +1,56 @@ +#ifndef WIN32_SOUND_H +#define WIN32_SOUND_H + +#include + +#define kLn2SoundBuffers 4 /* kSoundBuffers must be a power of two */ +#define kSoundBuffers (1 << kLn2SoundBuffers) +#define kSoundBuffMask (kSoundBuffers - 1) + +#define DesiredMinFilledSoundBuffs 3 + /* + if too big then sound lags behind emulation. + if too small then sound will have pauses. + */ + +#define kLnOneBuffLen 9 +#define kLnAllBuffLen (kLn2SoundBuffers + kLnOneBuffLen) +#define kOneBuffLen (1UL << kLnOneBuffLen) +#define kAllBuffLen (1UL << kLnAllBuffLen) +#define kLnOneBuffSz (kLnOneBuffLen + kLn2SoundSampSz - 3) +#define kLnAllBuffSz (kLnAllBuffLen + kLn2SoundSampSz - 3) +#define kOneBuffSz (1UL << kLnOneBuffSz) +#define kAllBuffSz (1UL << kLnAllBuffSz) +#define kOneBuffMask (kOneBuffLen - 1) +#define kAllBuffMask (kAllBuffLen - 1) +#define dbhBufferSize (kAllBuffSz + kOneBuffSz) + +#define dbglog_SoundStuff (0 && dbglog_HAVE) +#define dbglog_SoundBuffStats (0 && dbglog_HAVE) + +extern tpSoundSamp TheSoundBuffer; +uint16_t ThePlayOffset; +uint16_t TheFillOffset; +bool wantplaying; +uint16_t MinFilledSoundBuffs; +uint16_t TheWriteOffset; + +extern HWAVEOUT hWaveOut; +WAVEHDR whdr[kSoundBuffers]; + +#define SOUND_SAMPLERATE /* 22050 */ 22255 + /* = round(7833600 * 2 / 704) */ + +void FillWithSilence(tpSoundSamp p, int n, trSoundSamp v); +void Sound_BeginPlaying(void); +void Sound_Start(void); +void Sound_Stop(void); +void SoundCheckVeryOften(void); +void ConvertSoundBlockToNative(tpSoundSamp p); +void Sound_FilledBlocks(void); +void Sound_WroteABlock(void); +void Sound_EndWrite(uint16_t actL); +tpSoundSamp Sound_BeginWrite(uint16_t n, uint16_t *actL); +void Sound_SecondNotify(void); + +#endif diff --git a/src/UI/WIN32/TIMEDATE.c b/src/UI/WIN32/TIMEDATE.c new file mode 100644 index 0000000..a7e808e --- /dev/null +++ b/src/UI/WIN32/TIMEDATE.c @@ -0,0 +1,137 @@ +#include "OSGLUWIN.h" + +/* --- time, date, location --- */ + +uint32_t TrueEmulatedTime = 0; +LOCALVAR uint32_t TimeSecBase; +LOCALVAR DWORD TimeMilliBase; +LOCALVAR uint32_t NextFracTime; +bool HaveSetTimeResolution = false; + +void IncrNextTime(void) +{ + NextFracTime += InvTimeStep; + NextIntTime += (NextFracTime >> InvTimeDivPow); + NextFracTime &= InvTimeDivMask; +} + +void InitNextTime(void) +{ + NextIntTime = LastTime; + NextFracTime = 0; + IncrNextTime(); +} + +bool UpdateTrueEmulatedTime(void) +{ + DWORD LatestTime; + int32_t TimeDiff; + + LatestTime = timeGetTime(); + if (LatestTime != LastTime) { + LastTime = LatestTime; + TimeDiff = (LatestTime - NextIntTime); + /* this should work even when time wraps */ + if (TimeDiff >= 0) { + if (TimeDiff > 256) { + /* emulation interrupted, forget it */ + ++TrueEmulatedTime; + InitNextTime(); + +#if dbglog_TimeStuff + dbglog_writelnNum("emulation interrupted", + TrueEmulatedTime); +#endif + } else { + do { + ++TrueEmulatedTime; + IncrNextTime(); + TimeDiff = (LatestTime - NextIntTime); + } while (TimeDiff >= 0); + } + return true; + } else if (TimeDiff < -256) { + /* clock goofed if ever get here, reset */ +#if dbglog_TimeStuff + dbglog_writeln("clock set back"); +#endif + + InitNextTime(); + } + } + return false; +} + +bool CheckDateTime(void) +{ + uint32_t NewMacDateInSecond; + + NewMacDateInSecond = + ((uint32_t)(LastTime - TimeMilliBase)) / 1000 + TimeSecBase; + if (CurMacDateInSeconds != NewMacDateInSecond) { + CurMacDateInSeconds = NewMacDateInSecond; + return true; + } else { + return false; + } +} + +bool Init60thCheck(void) +{ + SYSTEMTIME s; + TIME_ZONE_INFORMATION r; + DWORD v; + DWORD t; + + GetLocalTime(&s); + t = timeGetTime(); + TimeSecBase = Date2MacSeconds(s.wSecond, s.wMinute, s.wHour, + s.wDay, s.wMonth, s.wYear); + TimeMilliBase = t - s.wMilliseconds; + + if (AutoTimeZone) { + v = GetTimeZoneInformation(&r); + if ((v != 0xFFFFFFFF) && (v != TIME_ZONE_ID_UNKNOWN)) { + int32_t dlsBias = \ + (v != TIME_ZONE_ID_DAYLIGHT) ? r.StandardBias : r.DaylightBias; + CurMacDelta = \ + (((uint32_t)(- (r.Bias + dlsBias) * 60)) & 0x00FFFFFF) + | (((v != TIME_ZONE_ID_DAYLIGHT) ? 0 : 0x80) << 24 ); + } + } + + LastTime = timeGetTime(); + InitNextTime(); + + OnTrueTime = TrueEmulatedTime; + + (void) CheckDateTime(); + + return true; +} + +void Timer_Suspend(void) +{ + if (HaveSetTimeResolution) { + (void) timeEndPeriod(TimeResolution); + HaveSetTimeResolution = false; + } +} + +void Timer_Resume(void) +{ + TIMECAPS tc; + + if (timeGetDevCaps(&tc, sizeof(TIMECAPS)) == TIMERR_NOERROR) + { + if ((TimeResolution >= tc.wPeriodMin) + && (TimeResolution <= tc.wPeriodMax)) + { + if (timeBeginPeriod(TimeResolution) + == TIMERR_NOERROR) + { + HaveSetTimeResolution = true; + } + } + } +}