public bool FrameAdvance(IController controller, bool render, bool rendersound) { FrameAdvancePrep(controller); if (_syncSettings.EqualLengthFrames) { while (true) { // target number of samples to emit: length of 1 frame minus whatever overflow uint samplesEmitted = TICKSINFRAME - frameOverflow; Debug.Assert(samplesEmitted * 2 <= _soundbuff.Length); if (LibGambatte.gambatte_runfor(GambatteState, _soundbuff, ref samplesEmitted) > 0) { LibGambatte.gambatte_blitto(GambatteState, VideoBuffer, 160); } // account for actual number of samples emitted _cycleCount += samplesEmitted; frameOverflow += samplesEmitted; if (rendersound && !Muted) { ProcessSound((int)samplesEmitted); } if (frameOverflow >= TICKSINFRAME) { frameOverflow -= TICKSINFRAME; break; } } } else { // target number of samples to emit: always 59.7fps // runfor() always ends after creating a video frame, so sync-up is guaranteed // when the display has been off, some frames can be markedly shorter than expected uint samplesEmitted = TICKSINFRAME; if (LibGambatte.gambatte_runfor(GambatteState, _soundbuff, ref samplesEmitted) > 0) { LibGambatte.gambatte_blitto(GambatteState, VideoBuffer, 160); } _cycleCount += samplesEmitted; frameOverflow = 0; if (rendersound && !Muted) { ProcessSound((int)samplesEmitted); } } if (rendersound && !Muted) { ProcessSoundEnd(); } FrameAdvancePost(); return(true); }
public void FrameAdvance(bool render, bool rendersound = true) { LCont.Clear(); RCont.Clear(); foreach (var s in DualGbController.BoolButtons) { if (Controller.IsPressed(s)) { if (s.Contains("P1 ")) { LCont.Set(s.Replace("P1 ", "")); } else if (s.Contains("P2 ")) { RCont.Set(s.Replace("P2 ", "")); } } } bool cablediscosignal_new = Controller.IsPressed("Toggle Cable"); if (cablediscosignal_new && !cablediscosignal) { cableconnected ^= true; Console.WriteLine("Cable connect status to {0}", cableconnected); LinkConnected = cableconnected; } cablediscosignal = cablediscosignal_new; Frame++; L.FrameAdvancePrep(); R.FrameAdvancePrep(); unsafe { fixed(int *leftvbuff = &VideoBuffer[0]) { // use pitch to have both cores write to the same video buffer, interleaved int * rightvbuff = leftvbuff + 160; const int pitch = 160 * 2; fixed(short *leftsbuff = LeftBuffer, rightsbuff = RightBuffer) { const int step = 32; // could be 1024 for GB int nL = overflowL; int nR = overflowR; // slowly step our way through the frame, while continually checking and resolving link cable status for (int target = 0; target < SampPerFrame;) { target += step; if (target > SampPerFrame) { target = SampPerFrame; // don't run for slightly too long depending on step } // gambatte_runfor() aborts early when a frame is produced, but we don't want that, hence the while() while (nL < target) { uint nsamp = (uint)(target - nL); if (LibGambatte.gambatte_runfor(L.GambatteState, leftsbuff + nL * 2, ref nsamp) > 0) { LibGambatte.gambatte_blitto(L.GambatteState, leftvbuff, pitch); } nL += (int)nsamp; } while (nR < target) { uint nsamp = (uint)(target - nR); if (LibGambatte.gambatte_runfor(R.GambatteState, rightsbuff + nR * 2, ref nsamp) > 0) { LibGambatte.gambatte_blitto(R.GambatteState, rightvbuff, pitch); } nR += (int)nsamp; } // poll link cable statuses, but not when the cable is disconnected if (!cableconnected) { continue; } if (LibGambatte.gambatte_linkstatus(L.GambatteState, 256) != 0) // ClockTrigger { LibGambatte.gambatte_linkstatus(L.GambatteState, 257); // ack int lo = LibGambatte.gambatte_linkstatus(L.GambatteState, 258); // GetOut int ro = LibGambatte.gambatte_linkstatus(R.GambatteState, 258); LibGambatte.gambatte_linkstatus(L.GambatteState, ro & 0xff); // ShiftIn LibGambatte.gambatte_linkstatus(R.GambatteState, lo & 0xff); // ShiftIn } if (LibGambatte.gambatte_linkstatus(R.GambatteState, 256) != 0) // ClockTrigger { LibGambatte.gambatte_linkstatus(R.GambatteState, 257); // ack int lo = LibGambatte.gambatte_linkstatus(L.GambatteState, 258); // GetOut int ro = LibGambatte.gambatte_linkstatus(R.GambatteState, 258); LibGambatte.gambatte_linkstatus(L.GambatteState, ro & 0xff); // ShiftIn LibGambatte.gambatte_linkstatus(R.GambatteState, lo & 0xff); // ShiftIn } } overflowL = nL - SampPerFrame; overflowR = nR - SampPerFrame; if (overflowL < 0 || overflowR < 0) { throw new Exception("Timing problem?"); } if (rendersound) { PrepSound(); } // copy extra samples back to beginning for (int i = 0; i < overflowL * 2; i++) { LeftBuffer[i] = LeftBuffer[i + SampPerFrame * 2]; } for (int i = 0; i < overflowR * 2; i++) { RightBuffer[i] = RightBuffer[i + SampPerFrame * 2]; } } } } L.FrameAdvancePost(); R.FrameAdvancePost(); IsLagFrame = L.IsLagFrame && R.IsLagFrame; if (IsLagFrame) { LagCount++; } }
public bool FrameAdvance(IController controller, bool render, bool rendersound) { FrameAdvancePrep(controller); uint samplesEmitted; switch (_syncSettings.FrameLength) { case GambatteSyncSettings.FrameLengthType.VBlankDrivenFrames: // target number of samples to emit: always 59.7fps // runfor() always ends after creating a video frame, so sync-up is guaranteed // when the display has been off, some frames can be markedly shorter than expected samplesEmitted = TICKSINFRAME; if (LibGambatte.gambatte_runfor(GambatteState, _soundbuff, ref samplesEmitted) > 0) { LibGambatte.gambatte_blitto(GambatteState, VideoBuffer, 160); } _cycleCount += samplesEmitted; frameOverflow = 0; if (rendersound && !Muted) { ProcessSound((int)samplesEmitted); } break; case GambatteSyncSettings.FrameLengthType.EqualLengthFrames: while (true) { // target number of samples to emit: length of 1 frame minus whatever overflow samplesEmitted = TICKSINFRAME - frameOverflow; Debug.Assert(samplesEmitted * 2 <= _soundbuff.Length); if (LibGambatte.gambatte_runfor(GambatteState, _soundbuff, ref samplesEmitted) > 0) { LibGambatte.gambatte_blitto(GambatteState, VideoBuffer, 160); } // account for actual number of samples emitted _cycleCount += samplesEmitted; frameOverflow += samplesEmitted; if (rendersound && !Muted) { ProcessSound((int)samplesEmitted); } if (frameOverflow >= TICKSINFRAME) { frameOverflow -= TICKSINFRAME; break; } } break; case GambatteSyncSettings.FrameLengthType.UserDefinedFrames: while (true) { // target number of samples to emit: input length minus whatever overflow float inputFrameLength = controller.AxisValue("Input Length"); uint inputFrameLengthInt = (uint)Math.Floor(inputFrameLength); if (inputFrameLengthInt == 0) { inputFrameLengthInt = TICKSINFRAME; } samplesEmitted = inputFrameLengthInt - frameOverflow; Debug.Assert(samplesEmitted * 2 <= _soundbuff.Length); if (LibGambatte.gambatte_runfor(GambatteState, _soundbuff, ref samplesEmitted) > 0) { LibGambatte.gambatte_blitto(GambatteState, VideoBuffer, 160); } // account for actual number of samples emitted _cycleCount += samplesEmitted; frameOverflow += samplesEmitted; if (rendersound && !Muted) { ProcessSound((int)samplesEmitted); } if (frameOverflow >= inputFrameLengthInt) { frameOverflow -= inputFrameLengthInt; break; } } break; } if (rendersound && !Muted) { ProcessSoundEnd(); } FrameAdvancePost(); return(true); }