mirror of
https://github.com/InvisibleUp/uvmac.git
synced 2024-12-22 07:31:39 +00:00
Split out sound and timing funcs from OSGLUWIN.c
This commit is contained in:
parent
a9c7900546
commit
1b31b614d2
2
Makefile
2
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/"
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
292
src/UI/WIN32/SOUND.c
Normal file
292
src/UI/WIN32/SOUND.c
Normal file
@ -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
|
56
src/UI/WIN32/SOUND.h
Normal file
56
src/UI/WIN32/SOUND.h
Normal file
@ -0,0 +1,56 @@
|
||||
#ifndef WIN32_SOUND_H
|
||||
#define WIN32_SOUND_H
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#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
|
137
src/UI/WIN32/TIMEDATE.c
Normal file
137
src/UI/WIN32/TIMEDATE.c
Normal file
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user