aboutsummaryrefslogtreecommitdiff
path: root/Emu8000.cpp
diff options
context:
space:
mode:
authorJavier <dev.git@javispedro.com>2022-02-05 15:43:59 +0100
committerJavier <dev.git@javispedro.com>2022-02-05 15:43:59 +0100
commit774984e2f00b4ea81060adf7a0625706ddaa42a5 (patch)
treeb28bc676598432953ce1002b93b0d7b584500df2 /Emu8000.cpp
parent176ec23dd48c50c87e5394b702e2cf0fe72957db (diff)
downloadvmusic-774984e2f00b4ea81060adf7a0625706ddaa42a5.tar.gz
vmusic-774984e2f00b4ea81060adf7a0625706ddaa42a5.zip
increment the emu's sample count between audio callbacks as per the virtual clock, to aid programs that poll it
Diffstat (limited to 'Emu8000.cpp')
-rw-r--r--Emu8000.cpp30
1 files changed, 25 insertions, 5 deletions
diff --git a/Emu8000.cpp b/Emu8000.cpp
index 86dcb11..4e3fd01 100644
--- a/Emu8000.cpp
+++ b/Emu8000.cpp
@@ -132,9 +132,12 @@ typedef struct {
bool volatile fShutdown;
/** Flag from render thread indicated it has shutdown (e.g. due to error or timeout). */
bool volatile fStopped;
- /** (System clock) timestamp of last OPL chip access. */
+ /** (System clock) timestamp of last port write. */
uint64_t tmLastWrite;
+ /** (Virtual clock) timestamp of last frame rendered. */
+ uint64_t tmLastRender;
+
/** To protect access to opl3_chip from the render thread and main thread. */
RTCRITSECT critSect;
/** Handle to emu8k. */
@@ -148,18 +151,26 @@ typedef EMUSTATE *PEMUSTATE;
#ifndef VBOX_DEVICE_STRUCT_TESTCASE
-static inline uint64_t emuCalculateFramesFromMilli(PEMUSTATE pThis, uint64_t milli)
+DECLINLINE(uint64_t) emuCalculateFramesFromMilli(PEMUSTATE pThis, uint64_t milli)
{
uint64_t rate = pThis->uSampleRate;
return (rate * milli) / 1000;
}
-static inline size_t emuCalculateBytesFromFrames(PEMUSTATE pThis, uint64_t frames)
+DECLINLINE(uint64_t) emuCalculateFramesFromNano(PEMUSTATE pThis, uint64_t nano)
+{
+ uint64_t rate = pThis->uSampleRate;
+ return (rate * nano) / 1000000000;
+}
+
+DECLINLINE(size_t) emuCalculateBytesFromFrames(PEMUSTATE pThis, uint64_t frames)
{
NOREF(pThis);
return frames * sizeof(uint16_t) * EMU_NUM_CHANNELS;
}
+
+
/**
* The render thread calls into the emulator to render audio frames, and then pushes them
* on the PCM output device.
@@ -172,7 +183,8 @@ static inline size_t emuCalculateBytesFromFrames(PEMUSTATE pThis, uint64_t frame
static DECLCALLBACK(int) emuRenderThread(RTTHREAD ThreadSelf, void *pvUser)
{
RT_NOREF(ThreadSelf);
- PEMUSTATE pThis = (PEMUSTATE)pvUser;
+ PPDMDEVINS pDevIns = (PPDMDEVINS)pvUser;
+ PEMUSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PEMUSTATE);
PCMOutBackend *pPcmOut = &pThis->pcmOut;
// Compute the max number of frames we can store on our temporary buffer.
@@ -190,6 +202,7 @@ static DECLCALLBACK(int) emuRenderThread(RTTHREAD ThreadSelf, void *pvUser)
RTCritSectEnter(&pThis->critSect);
emu8k_render(pThis->emu, buf, buf_frames);
+ pThis->tmLastRender = PDMDevHlpTMTimeVirtGetNano(pDevIns);
RTCritSectLeave(&pThis->critSect);
Log9(("writing %lld frames\n", buf_frames));
@@ -275,7 +288,7 @@ static void emuWakeRenderThread(PPDMDEVINS pDevIns)
Log3(("Creating render thread\n"));
- int rc = RTThreadCreateF(&pThis->hRenderThread, emuRenderThread, pThis, 0,
+ int rc = RTThreadCreateF(&pThis->hRenderThread, emuRenderThread, pDevIns, 0,
RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE,
"emu%u_render", pDevIns->iInstance);
AssertLogRelRCReturnVoid(rc);
@@ -291,6 +304,10 @@ static DECLCALLBACK(VBOXSTRICTRC) emuIoPortRead(PPDMDEVINS pDevIns, void *pvUser
PEMUSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PEMUSTATE);
+ RTCritSectEnter(&pThis->critSect);
+ uint64_t frames_since_last_render = emuCalculateFramesFromNano(pThis, PDMDevHlpTMTimeVirtGetNano(pDevIns) - pThis->tmLastRender);
+ emu8k_update_virtual_sample_count(pThis->emu, frames_since_last_render);
+
switch (cb) {
case sizeof(uint8_t):
*pu32 = emu8k_inb(pThis->emu, port);
@@ -307,6 +324,8 @@ static DECLCALLBACK(VBOXSTRICTRC) emuIoPortRead(PPDMDEVINS pDevIns, void *pvUser
break;
}
+ RTCritSectLeave(&pThis->critSect);
+
Log9Func(("read port 0x%X (%u): %#04x\n", port, cb, *pu32));
return VINF_SUCCESS;
@@ -397,6 +416,7 @@ static DECLCALLBACK(void) emuR3Reset(PPDMDEVINS pDevIns)
RTCritSectEnter(&pThis->critSect);
emu8k_reset(pThis->emu);
+ pThis->tmLastRender = PDMDevHlpTMTimeVirtGetNano(pDevIns);
RTCritSectLeave(&pThis->critSect);
}