mirror of
https://github.com/ppeccin/javatari.js.git
synced 2024-06-16 03:27:24 -04:00
VideoClock uses divider in order to avoid too high host frequencies, so to avoid overloading the network
This commit is contained in:
parent
fc43514870
commit
016bab1043
|
@ -8,9 +8,12 @@ jt.AtariConsole = function(mainVideoClock) {
|
|||
function init() {
|
||||
mainComponentsCreate();
|
||||
socketsCreate();
|
||||
setDefaults();
|
||||
}
|
||||
|
||||
this.socketsConnected = function() {
|
||||
setDefaults();
|
||||
};
|
||||
|
||||
this.powerOn = function() {
|
||||
if (this.powerIsOn) this.powerOff();
|
||||
bus.powerOn();
|
||||
|
@ -66,28 +69,6 @@ jt.AtariConsole = function(mainVideoClock) {
|
|||
return systemPaused;
|
||||
};
|
||||
|
||||
this.videoClockPulseOLD = function(ignoreSystemPause) {
|
||||
if (systemPaused && !ignoreSystemPause) return;
|
||||
|
||||
if (!self.powerIsOn) return;
|
||||
|
||||
if (videoPulldown.steps === 1) {
|
||||
// Simple pulldown with 1:1 cadence
|
||||
videoFrame();
|
||||
} else {
|
||||
// Complex pulldown
|
||||
var pulls = videoPulldown.cadence[--videoPulldownStep];
|
||||
if (videoPulldownStep === 0) videoPulldownStep = videoPulldown.steps;
|
||||
while(pulls > 0) {
|
||||
pulls--;
|
||||
videoFrame();
|
||||
}
|
||||
}
|
||||
|
||||
// Finish audio signal (generate any missing samples to adjust to sample rate)
|
||||
if (!systemPaused && !userPaused) audioSocket.audioFinishFrame();
|
||||
};
|
||||
|
||||
this.videoClockPulse = function() {
|
||||
// Video clock will be the Tia Frame video clock (60Hz/50Hz)
|
||||
// CPU and other clocks (Pia, Audio) will be sent by the Tia
|
||||
|
@ -139,6 +120,10 @@ jt.AtariConsole = function(mainVideoClock) {
|
|||
return saveStateSocket;
|
||||
};
|
||||
|
||||
this.getVideoClockSocket = function() {
|
||||
return videoClockSocket;
|
||||
};
|
||||
|
||||
this.getAudioSocket = function() {
|
||||
return audioSocket;
|
||||
};
|
||||
|
@ -242,14 +227,14 @@ jt.AtariConsole = function(mainVideoClock) {
|
|||
// According to the native video frequency detected, target Video Standard and vSynchMode, use a specific pulldown configuration
|
||||
if (vSynchMode === 1) { // ON
|
||||
// Will V-synch to host freq if detected and supported, or use optimal timer configuration)
|
||||
videoPulldown = videoStandard.pulldowns[jt.Clock.HOST_NATIVE_FPS] || videoStandard.pulldowns.TIMER;
|
||||
videoPulldown = videoStandard.pulldowns[videoClockSocket.getVSynchNativeFrequency()] || videoStandard.pulldowns.TIMER;
|
||||
} else { // OFF, DISABLED
|
||||
// No V-synch. Always use the optimal timer configuration)
|
||||
videoPulldown = videoStandard.pulldowns.TIMER;
|
||||
}
|
||||
|
||||
videoPulldownStep = 0;
|
||||
mainVideoClockUpdateSpeed();
|
||||
videoClockUpdateSpeed();
|
||||
|
||||
//console.error("Update Synchronization: " + videoPulldown.frequency);
|
||||
}
|
||||
|
@ -289,7 +274,7 @@ jt.AtariConsole = function(mainVideoClock) {
|
|||
if (s.upf !== undefined) userPauseMoreFrames = s.upf;
|
||||
|
||||
// Normal
|
||||
mainVideoClockUpdateSpeed();
|
||||
videoClockUpdateSpeed();
|
||||
tia.loadState(s.t);
|
||||
pia.loadState(s.p);
|
||||
ram.loadState(s.r);
|
||||
|
@ -307,16 +292,16 @@ jt.AtariConsole = function(mainVideoClock) {
|
|||
setVideoStandardAuto(true);
|
||||
speedControl = 1;
|
||||
alternateSpeed = null;
|
||||
mainVideoClockUpdateSpeed();
|
||||
videoClockUpdateSpeed();
|
||||
tia.debug(0);
|
||||
tia.debugNoCollisions(false);
|
||||
}
|
||||
|
||||
function mainVideoClockUpdateSpeed() {
|
||||
var freq = videoPulldown.frequency;
|
||||
mainVideoClock.setVSynch(vSynchMode === 1);
|
||||
mainVideoClock.setFrequency((freq * (alternateSpeed || speedControl)) | 0);
|
||||
audioSocket.setFps(freq);
|
||||
function videoClockUpdateSpeed() {
|
||||
videoClockSocket.setVSynch(vSynchMode === 1);
|
||||
var hostFreq = (videoPulldown.frequency * (alternateSpeed || speedControl)) | 0;
|
||||
videoClockSocket.setFrequency(hostFreq, videoPulldown.divider);
|
||||
audioSocket.setFps(hostFreq / videoPulldown.divider);
|
||||
}
|
||||
|
||||
var mainComponentsCreate = function() {
|
||||
|
@ -329,6 +314,7 @@ jt.AtariConsole = function(mainVideoClock) {
|
|||
};
|
||||
|
||||
var socketsCreate = function() {
|
||||
videoClockSocket = new VideoClockSocket();
|
||||
consoleControlsSocket = new ConsoleControlsSocket();
|
||||
cartridgeSocket = new CartridgeSocket();
|
||||
saveStateSocket = new SaveStateSocket();
|
||||
|
@ -356,6 +342,7 @@ jt.AtariConsole = function(mainVideoClock) {
|
|||
var videoStandard;
|
||||
var videoPulldown, videoPulldownStep;
|
||||
|
||||
var videoClockSocket;
|
||||
var consoleControlsSocket;
|
||||
var cartridgeSocket;
|
||||
var saveStateSocket;
|
||||
|
@ -382,11 +369,11 @@ jt.AtariConsole = function(mainVideoClock) {
|
|||
if (control === controls.FAST_SPEED) {
|
||||
if (state && alternateSpeed !== SPEED_FAST) {
|
||||
alternateSpeed = SPEED_FAST;
|
||||
mainVideoClockUpdateSpeed();
|
||||
videoClockUpdateSpeed();
|
||||
self.showOSD("FAST FORWARD", true);
|
||||
} else if (!state && alternateSpeed === SPEED_FAST) {
|
||||
alternateSpeed = null;
|
||||
mainVideoClockUpdateSpeed();
|
||||
videoClockUpdateSpeed();
|
||||
self.showOSD(null, true);
|
||||
}
|
||||
return;
|
||||
|
@ -394,11 +381,11 @@ jt.AtariConsole = function(mainVideoClock) {
|
|||
if (control === controls.SLOW_SPEED) {
|
||||
if (state && alternateSpeed !== SPEED_SLOW) {
|
||||
alternateSpeed = SPEED_SLOW;
|
||||
mainVideoClockUpdateSpeed();
|
||||
videoClockUpdateSpeed();
|
||||
self.showOSD("SLOW MOTION", true);
|
||||
} else if (!state && alternateSpeed === SPEED_SLOW) {
|
||||
alternateSpeed = null;
|
||||
mainVideoClockUpdateSpeed();
|
||||
videoClockUpdateSpeed();
|
||||
self.showOSD(null, true);
|
||||
}
|
||||
return;
|
||||
|
@ -435,7 +422,7 @@ jt.AtariConsole = function(mainVideoClock) {
|
|||
else if (control === controls.NORMAL_SPEED) speedIndex = SPEEDS.indexOf(1);
|
||||
speedControl = SPEEDS[speedIndex];
|
||||
self.showOSD("Speed: " + ((speedControl * 100) | 0) + "%", true);
|
||||
mainVideoClockUpdateSpeed();
|
||||
videoClockUpdateSpeed();
|
||||
break;
|
||||
case controls.SAVE_STATE_0: case controls.SAVE_STATE_1: case controls.SAVE_STATE_2: case controls.SAVE_STATE_3: case controls.SAVE_STATE_4: case controls.SAVE_STATE_5:
|
||||
case controls.SAVE_STATE_6: case controls.SAVE_STATE_7: case controls.SAVE_STATE_8: case controls.SAVE_STATE_9: case controls.SAVE_STATE_10: case controls.SAVE_STATE_11: case controls.SAVE_STATE_12:
|
||||
|
@ -479,6 +466,25 @@ jt.AtariConsole = function(mainVideoClock) {
|
|||
};
|
||||
|
||||
|
||||
// Video Clock Socket -----------------------------------------
|
||||
|
||||
function VideoClockSocket() {
|
||||
this.connectClock = function(clock) {
|
||||
videoClock = clock;
|
||||
};
|
||||
this.getVSynchNativeFrequency = function() {
|
||||
return videoClock.getVSynchNativeFrequency();
|
||||
};
|
||||
this.setVSynch = function(state) {
|
||||
videoClock.setVSynch(state);
|
||||
};
|
||||
this.setFrequency = function(freq, div) {
|
||||
videoClock.setFrequency(freq, div);
|
||||
};
|
||||
var videoClock;
|
||||
}
|
||||
|
||||
|
||||
// CartridgeSocket -----------------------------------------
|
||||
|
||||
function CartridgeSocket() {
|
||||
|
@ -712,20 +718,6 @@ jt.AtariConsole = function(mainVideoClock) {
|
|||
|
||||
// Debug methods ------------------------------------------------------
|
||||
|
||||
this.runFramesAtTopSpeed = function(frames) {
|
||||
mainVideoClock.pause();
|
||||
var start = jt.Util.performanceNow();
|
||||
for (var i = 0; i < frames; i++) {
|
||||
//var pulseTime = jt.Util.performanceNow();
|
||||
self.videoClockPulseApplyPulldowns(1);
|
||||
//console.log(jt.Util.performanceNow() - pulseTime);
|
||||
}
|
||||
var duration = jt.Util.performanceNow() - start;
|
||||
jt.Util.log("Done running " + frames + " frames in " + (duration | 0) + " ms");
|
||||
jt.Util.log((frames / (duration/1000)).toFixed(2) + " frames/sec");
|
||||
mainVideoClock.go();
|
||||
};
|
||||
|
||||
this.eval = function(str) {
|
||||
return eval(str);
|
||||
};
|
||||
|
|
|
@ -1,160 +0,0 @@
|
|||
// Copyright 2015 by Paulo Augusto Peccin. See license.txt distributed with this file.
|
||||
|
||||
// Clock Pulse generator. Intended to be synchronized with Host machine Video Frequency whenever possible
|
||||
|
||||
jt.Clock = function(clockPulse) {
|
||||
"use strict";
|
||||
|
||||
this.go = function() {
|
||||
if (!running) {
|
||||
//lastPulseTime = jt.Util.performanceNow();
|
||||
//timeMeasures = [];
|
||||
|
||||
useRequestAnimationFrame = vSynch && (cyclesPerSecond === jt.Clock.HOST_NATIVE_FPS);
|
||||
|
||||
running = true;
|
||||
if (useRequestAnimationFrame)
|
||||
animationFrame = requestAnimationFrame(pulse);
|
||||
else
|
||||
interval = setInterval(pulse, cycleTimeMs);
|
||||
}
|
||||
};
|
||||
|
||||
this.pause = function() {
|
||||
running = false;
|
||||
if (animationFrame) {
|
||||
cancelAnimationFrame(animationFrame);
|
||||
animationFrame = null;
|
||||
}
|
||||
if (interval) {
|
||||
clearInterval(interval);
|
||||
interval = null;
|
||||
}
|
||||
};
|
||||
|
||||
this.isRunning = function() {
|
||||
return running;
|
||||
};
|
||||
|
||||
this.getFrequency = function() {
|
||||
return cyclesPerSecond;
|
||||
};
|
||||
|
||||
this.setFrequency = function(freq) {
|
||||
if (running) {
|
||||
this.pause();
|
||||
internalSetFrequency(freq);
|
||||
this.go();
|
||||
} else {
|
||||
internalSetFrequency(freq);
|
||||
}
|
||||
};
|
||||
|
||||
this.setVSynch = function(boo) {
|
||||
if (running) {
|
||||
this.pause();
|
||||
vSynch = boo;
|
||||
this.go();
|
||||
} else {
|
||||
vSynch = boo;
|
||||
}
|
||||
};
|
||||
|
||||
var internalSetFrequency = function(freq) {
|
||||
cyclesPerSecond = freq;
|
||||
cycleTimeMs = 1000 / freq;
|
||||
};
|
||||
|
||||
var pulse = function() {
|
||||
// var pulseTime = jt.Util.performanceNow();
|
||||
// timeMeasures[timeMeasures.length] = pulseTime - lastPulseTime;
|
||||
// var lastPulseTime = pulseTime;
|
||||
|
||||
animationFrame = null;
|
||||
clockPulse();
|
||||
if (useRequestAnimationFrame && !animationFrame)
|
||||
animationFrame = requestAnimationFrame(pulse);
|
||||
|
||||
// console.log(jt.Util.performanceNow() - pulseTime);
|
||||
};
|
||||
|
||||
//this.getMeasures = function() {
|
||||
// return timeMeasures;
|
||||
//};
|
||||
|
||||
this.eval = function(str) {
|
||||
return eval(str);
|
||||
};
|
||||
|
||||
|
||||
var running = false;
|
||||
|
||||
var cyclesPerSecond = 1;
|
||||
var cycleTimeMs = 1000;
|
||||
var useRequestAnimationFrame;
|
||||
var animationFrame = null;
|
||||
var interval = null;
|
||||
var vSynch = true;
|
||||
|
||||
//var timeMeasures = [];
|
||||
//var lastPulseTime = 0;
|
||||
|
||||
};
|
||||
|
||||
jt.Clock.HOST_NATIVE_FPS = Javatari.SCREEN_VSYNCH_MODE === -1 ? -1 : Javatari.SCREEN_FORCE_HOST_NATIVE_FPS; // -1 = Unknown or not detected
|
||||
|
||||
jt.Clock.detectHostNativeFPSAndCallback = function(callback) {
|
||||
|
||||
if (Javatari.SCREEN_VSYNCH_MODE === -1) {
|
||||
jt.Util.warning("Video native V-Synch disabled in configuration");
|
||||
if (callback) callback(jt.Clock.HOST_NATIVE_FPS);
|
||||
return;
|
||||
}
|
||||
|
||||
if (jt.Clock.HOST_NATIVE_FPS !== -1) {
|
||||
jt.Util.warning("Host video frequency forced in configuration: " + jt.Clock.HOST_NATIVE_FPS);
|
||||
if (callback) callback(jt.Clock.HOST_NATIVE_FPS);
|
||||
return;
|
||||
}
|
||||
|
||||
// Start detection
|
||||
|
||||
var tries = 0;
|
||||
var samples = [];
|
||||
var lastTime = 0;
|
||||
var good60 = 0, good50 = 0, good120 = 0, good100 = 0;
|
||||
var tolerance = 0.06;
|
||||
|
||||
var sampler = function() {
|
||||
|
||||
// Detected?
|
||||
if (good60 >= 10 || good50 >= 10 || good120 >= 10 || good100 >= 10) {
|
||||
jt.Clock.HOST_NATIVE_FPS = good60 >= 10 ? 60 : good50 >= 10 ? 50 : good120 >= 10 ? 120 : 100;
|
||||
jt.Util.log("Video native frequency detected: " + jt.Clock.HOST_NATIVE_FPS + "Hz");
|
||||
if (callback) callback(jt.Clock.HOST_NATIVE_FPS);
|
||||
return;
|
||||
}
|
||||
|
||||
tries++;
|
||||
if (tries <= 50) {
|
||||
var currentTime = jt.Util.performanceNow();
|
||||
var sample = currentTime - lastTime;
|
||||
samples[samples.length] = sample;
|
||||
lastTime = currentTime;
|
||||
|
||||
if ((sample >= (1000 / 60) * (1 - tolerance)) && (sample <= (1000 / 60) * (1 + tolerance))) good60++;
|
||||
if ((sample >= (1000 / 50) * (1 - tolerance)) && (sample <= (1000 / 50) * (1 + tolerance))) good50++;
|
||||
if ((sample >= (1000 / 120) * (1 - tolerance)) && (sample <= (1000 / 120) * (1 + tolerance))) good120++;
|
||||
if ((sample >= (1000 / 100) * (1 - tolerance)) && (sample <= (1000 / 100) * (1 + tolerance))) good100++;
|
||||
|
||||
requestAnimationFrame(sampler);
|
||||
} else {
|
||||
jt.Clock.HOST_NATIVE_FPS = -1;
|
||||
jt.Util.warning("Could not detect video native frequency. V-Synch DISABLED!");
|
||||
if (callback) callback(jt.Clock.HOST_NATIVE_FPS);
|
||||
}
|
||||
};
|
||||
|
||||
sampler();
|
||||
|
||||
};
|
|
@ -13,40 +13,49 @@ jt.VideoStandard = {
|
|||
60: { // Host at 60Hz
|
||||
standard: "NTSC",
|
||||
frequency: 60,
|
||||
linesPerCycle: 262, // Normal 1:1 cadence. Exact V-synch to 60 Hz
|
||||
firstStepCycleLinesAdjust: 0,
|
||||
divider: 1,
|
||||
cadence: [ 1 ],
|
||||
steps: 1
|
||||
},
|
||||
120: { // Host at 120Hz
|
||||
120: { // Host at 120Hz, clock / 2
|
||||
standard: "NTSC",
|
||||
frequency: 120,
|
||||
linesPerCycle: 131, // 0:1 pulldown. 1 frame generated each 2 frames shown
|
||||
firstStepCycleLinesAdjust: 0,
|
||||
divider: 2,
|
||||
cadence: [ 1 ],
|
||||
steps: 1
|
||||
},
|
||||
"120s": { // Host at 120Hz
|
||||
standard: "NTSC",
|
||||
frequency: 120,
|
||||
divider: 1,
|
||||
cadence: [ 0, 1 ],
|
||||
steps: 2
|
||||
},
|
||||
50: { // Host at 50Hz
|
||||
standard: "NTSC",
|
||||
frequency: 50,
|
||||
linesPerCycle: 314, // 1:1:1:1:2 pulldown. 6 frames generated each 5 frames shown
|
||||
firstStepCycleLinesAdjust: +2,
|
||||
divider: 1,
|
||||
cadence: [ 1, 1, 1, 1, 2 ],
|
||||
steps: 5
|
||||
},
|
||||
100: { // Host at 100Hz
|
||||
100: { // Host at 100Hz, clock / 2
|
||||
standard: "NTSC",
|
||||
frequency: 100,
|
||||
linesPerCycle: 157, // 0:1:0:1:1:0:1:0:1:1 pulldown. 6 frames generated each 10 frames shown
|
||||
firstStepCycleLinesAdjust: +2,
|
||||
divider: 2,
|
||||
cadence: [ 1, 1, 1, 1, 2 ],
|
||||
steps: 5
|
||||
},
|
||||
"100s": { // Host at 100Hz
|
||||
standard: "NTSC",
|
||||
frequency: 100,
|
||||
divider: 1,
|
||||
cadence: [ 0, 1, 0, 1, 1, 0, 1, 0, 1, 1 ],
|
||||
steps: 10
|
||||
},
|
||||
TIMER: { // Host frequency not detected or V-synch disabled, use a normal interval timer
|
||||
standard: "NTSC",
|
||||
frequency: 62.5,
|
||||
linesPerCycle: 262, // Normal 1:1 cadence
|
||||
firstStepCycleLinesAdjust: 0,
|
||||
divider: 1,
|
||||
cadence: [ 1 ],
|
||||
steps: 1
|
||||
}
|
||||
|
@ -64,40 +73,49 @@ jt.VideoStandard = {
|
|||
50: { // Host at 50Hz
|
||||
standard: "PAL",
|
||||
frequency: 50,
|
||||
linesPerCycle: 313, // Normal 1:1 cadence. Exact V-synch to 50 Hz
|
||||
firstStepCycleLinesAdjust: 0,
|
||||
divider: 1,
|
||||
cadence: [ 1 ],
|
||||
steps: 1
|
||||
},
|
||||
100: { // Host at 100Hz
|
||||
100: { // Host at 100Hz, clock / 2
|
||||
standard: "PAL",
|
||||
frequency: 100,
|
||||
linesPerCycle: 156, // 0:1 pulldown. 1 frame generated each 2 frames shown
|
||||
firstStepCycleLinesAdjust: +1,
|
||||
divider: 2,
|
||||
cadence: [ 1 ],
|
||||
steps: 1
|
||||
},
|
||||
"100s": { // Host at 100Hz
|
||||
standard: "PAL",
|
||||
frequency: 100,
|
||||
divider: 1,
|
||||
cadence: [ 0, 1 ],
|
||||
steps: 2
|
||||
},
|
||||
60: { // Host at 60Hz
|
||||
standard: "PAL",
|
||||
frequency: 60,
|
||||
linesPerCycle: 261, // 0:1:1:1:1:1 pulldown. 5 frames generated each 6 frames shown
|
||||
firstStepCycleLinesAdjust: -1,
|
||||
divider: 1,
|
||||
cadence: [ 0, 1, 1, 1, 1, 1 ],
|
||||
steps: 6
|
||||
},
|
||||
120: { // Host at 120Hz
|
||||
120: { // Host at 120Hz, clock / 2
|
||||
standard: "PAL",
|
||||
frequency: 120,
|
||||
linesPerCycle: 130, // 0:0:1:0:1:0:0:1:0:1:0:1 pulldown. 5 frames generated each 12 frames shown
|
||||
firstStepCycleLinesAdjust: +5,
|
||||
divider: 2,
|
||||
cadence: [ 0, 1, 1, 1, 1, 1 ],
|
||||
steps: 6
|
||||
},
|
||||
"120s": { // Host at 120Hz
|
||||
standard: "PAL",
|
||||
frequency: 120,
|
||||
divider: 1,
|
||||
cadence: [ 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1 ],
|
||||
steps: 12
|
||||
},
|
||||
TIMER: { // Host frequency not detected or V-synch disabled, use a normal interval timer
|
||||
standard: "PAL",
|
||||
frequency: 50,
|
||||
linesPerCycle: 313, // Normal 1:1 cadence
|
||||
firstStepCycleLinesAdjust: 0,
|
||||
divider: 1,
|
||||
cadence: [ 1 ],
|
||||
steps: 1
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ jt.Room = function(screenElement, consoleStartPowerOn) {
|
|||
};
|
||||
|
||||
this.start = function(startAction) {
|
||||
jt.Clock.detectHostNativeFPSAndCallback(function(nativeFPS) {
|
||||
this.mainVideoClock.detectHostNativeFPSAndCallback(function(nativeFPS) {
|
||||
self.console.vSynchSetSupported(nativeFPS > 0);
|
||||
afterPowerONDelay(function () {
|
||||
self.setLoading(false);
|
||||
|
@ -154,14 +154,15 @@ jt.Room = function(screenElement, consoleStartPowerOn) {
|
|||
}
|
||||
|
||||
function buildAndPlugConsole() {
|
||||
self.console = new jt.AtariConsole(self.mainVideoClock);
|
||||
self.console = new jt.AtariConsole();
|
||||
self.mainVideoClock.connect(self.console.getVideoClockSocket());
|
||||
self.stateMedia.connect(self.console.getSavestateSocket());
|
||||
self.fileLoader.connect(self.console);
|
||||
self.screen.connect(self.console);
|
||||
self.speaker.connect(self.console.getAudioSocket());
|
||||
self.consoleControls.connect(self.console.getConsoleControlsSocket());
|
||||
self.peripheralControls.connect(self.console.getCartridgeSocket());
|
||||
// Cartridge Data operations unavailable self.console.getCartridgeSocket().connectFileDownloader(self.fileDownloader);
|
||||
self.console.socketsConnected();
|
||||
}
|
||||
|
||||
|
||||
|
@ -188,6 +189,23 @@ jt.Room = function(screenElement, consoleStartPowerOn) {
|
|||
var roomPowerOnTime;
|
||||
|
||||
|
||||
// Debug methods ------------------------------------------------------
|
||||
|
||||
this.runFramesAtTopSpeed = function(frames) {
|
||||
this.mainVideoClock.pause();
|
||||
var start = jt.Util.performanceNow();
|
||||
for (var i = 0; i < frames; i++) {
|
||||
//var pulseTime = jt.Util.performanceNow();
|
||||
self.mainVideoClockPulse();
|
||||
//console.log(jt.Util.performanceNow() - pulseTime);
|
||||
}
|
||||
var duration = jt.Util.performanceNow() - start;
|
||||
jt.Util.log("Done running " + frames + " frames in " + (duration | 0) + " ms");
|
||||
jt.Util.log((frames / (duration/1000)).toFixed(2) + " frames/sec");
|
||||
this.mainVideoClock.go();
|
||||
};
|
||||
|
||||
|
||||
init();
|
||||
|
||||
};
|
||||
|
|
175
src/main/room/clock/Clock.js
Normal file
175
src/main/room/clock/Clock.js
Normal file
|
@ -0,0 +1,175 @@
|
|||
// Copyright 2015 by Paulo Augusto Peccin. See license.txt distributed with this file.
|
||||
|
||||
// Clock Pulse generator. Intended to be synchronized with Host machine Video Frequency whenever possible
|
||||
|
||||
jt.Clock = function(clockPulse) {
|
||||
"use strict";
|
||||
|
||||
this.connect = function(clockSocket) {
|
||||
clockSocket.connectClock(this);
|
||||
};
|
||||
|
||||
this.go = function() {
|
||||
if (!running) {
|
||||
//lastPulseTime = jt.Util.performanceNow();
|
||||
//timeMeasures = [];
|
||||
|
||||
useRequestAnimationFrame = vSynch && (cyclesPerSecond === this.getVSynchNativeFrequency());
|
||||
|
||||
// console.log("Clock at " + cyclesPerSecond + " / " + divider + " using RequestAnimationFrame: " + useRequestAnimationFrame);
|
||||
|
||||
running = true;
|
||||
if (useRequestAnimationFrame)
|
||||
animationFrame = requestAnimationFrame(pulse);
|
||||
else
|
||||
interval = setInterval(pulse, cycleTimeMs);
|
||||
}
|
||||
};
|
||||
|
||||
this.pause = function() {
|
||||
running = false;
|
||||
if (animationFrame) {
|
||||
cancelAnimationFrame(animationFrame);
|
||||
animationFrame = null;
|
||||
}
|
||||
if (interval) {
|
||||
clearInterval(interval);
|
||||
interval = null;
|
||||
}
|
||||
};
|
||||
|
||||
this.setFrequency = function(freq, div) {
|
||||
if (running) {
|
||||
this.pause();
|
||||
internalSetFrequency(freq, div);
|
||||
this.go();
|
||||
} else {
|
||||
internalSetFrequency(freq, div);
|
||||
}
|
||||
};
|
||||
|
||||
this.setVSynch = function(state) {
|
||||
if (running) {
|
||||
this.pause();
|
||||
vSynch = state;
|
||||
this.go();
|
||||
} else {
|
||||
vSynch = state;
|
||||
}
|
||||
};
|
||||
|
||||
this.getVSynchNativeFrequency = function() {
|
||||
return vSynchAltNativeFrequency || vSynchNativeFrequency;
|
||||
};
|
||||
|
||||
this.setVSynchAltNativeFrequency = function(freq) {
|
||||
vSynchAltNativeFrequency = freq;
|
||||
};
|
||||
|
||||
var internalSetFrequency = function(freq, div) {
|
||||
cyclesPerSecond = freq;
|
||||
cycleTimeMs = 1000 / freq;
|
||||
divider = div >= 1 ? div : 1;
|
||||
if (dividerCounter > divider) dividerCounter = divider;
|
||||
};
|
||||
|
||||
var pulse = function() {
|
||||
//var pulseTime = jt.Util.performanceNow();
|
||||
//timeMeasures[timeMeasures.length] = pulseTime - lastPulseTime;
|
||||
//lastPulseTime = pulseTime;
|
||||
|
||||
animationFrame = null;
|
||||
|
||||
if (divider > 1) {
|
||||
if (--dividerCounter <= 0) {
|
||||
dividerCounter = divider;
|
||||
clockPulse();
|
||||
}
|
||||
} else
|
||||
clockPulse();
|
||||
|
||||
if (useRequestAnimationFrame && !animationFrame)
|
||||
animationFrame = requestAnimationFrame(pulse);
|
||||
|
||||
//console.log(jt.Util.performanceNow() - pulseTime);
|
||||
};
|
||||
|
||||
//this.getMeasures = function() {
|
||||
// return timeMeasures;
|
||||
//};
|
||||
|
||||
this.detectHostNativeFPSAndCallback = function(callback) {
|
||||
|
||||
if (Javatari.SCREEN_VSYNCH_MODE === -1) {
|
||||
jt.Util.warning("Video native V-Synch disabled in configuration");
|
||||
if (callback) callback(vSynchNativeFrequency);
|
||||
return;
|
||||
}
|
||||
if (Javatari.SCREEN_FORCE_HOST_NATIVE_FPS !== -1) {
|
||||
jt.Util.warning("Host video frequency forced in configuration: " + Javatari.SCREEN_FORCE_HOST_NATIVE_FPS);
|
||||
if (callback) callback(vSynchNativeFrequency);
|
||||
return;
|
||||
}
|
||||
|
||||
// Start detection
|
||||
|
||||
var tries = 0;
|
||||
var samples = [];
|
||||
var lastTime = 0;
|
||||
var good60 = 0, good50 = 0, good120 = 0, good100 = 0;
|
||||
var tolerance = 0.06;
|
||||
|
||||
var nativeFPSSampler = function() {
|
||||
// Detected?
|
||||
if (good60 >= 10 || good50 >= 10 || good120 >= 10 || good100 >= 10) {
|
||||
vSynchNativeFrequency = good60 >= 10 ? 60 : good50 >= 10 ? 50 : good120 >= 10 ? 120 : 100;
|
||||
jt.Util.log("Video native frequency detected: " + vSynchNativeFrequency + "Hz");
|
||||
if (callback) callback(vSynchNativeFrequency);
|
||||
return;
|
||||
}
|
||||
|
||||
tries++;
|
||||
if (tries <= 50) {
|
||||
var currentTime = jt.Util.performanceNow();
|
||||
var sample = currentTime - lastTime;
|
||||
samples[samples.length] = sample;
|
||||
lastTime = currentTime;
|
||||
if ((sample >= (1000 / 60) * (1 - tolerance)) && (sample <= (1000 / 60) * (1 + tolerance))) good60++;
|
||||
if ((sample >= (1000 / 50) * (1 - tolerance)) && (sample <= (1000 / 50) * (1 + tolerance))) good50++;
|
||||
if ((sample >= (1000 / 120) * (1 - tolerance)) && (sample <= (1000 / 120) * (1 + tolerance))) good120++;
|
||||
if ((sample >= (1000 / 100) * (1 - tolerance)) && (sample <= (1000 / 100) * (1 + tolerance))) good100++;
|
||||
requestAnimationFrame(nativeFPSSampler);
|
||||
} else {
|
||||
vSynchNativeFrequency = -1;
|
||||
jt.Util.error("Could not detect video native frequency. V-Synch DISABLED!");
|
||||
if (callback) callback(vSynchNativeFrequency);
|
||||
}
|
||||
};
|
||||
|
||||
nativeFPSSampler();
|
||||
};
|
||||
|
||||
this.eval = function(str) {
|
||||
return eval(str);
|
||||
};
|
||||
|
||||
|
||||
var running = false;
|
||||
|
||||
var cyclesPerSecond = 1;
|
||||
var cycleTimeMs = 1000;
|
||||
var divider = 1;
|
||||
var dividerCounter = 1;
|
||||
var useRequestAnimationFrame;
|
||||
var animationFrame = null;
|
||||
var interval = null;
|
||||
var vSynch = true;
|
||||
|
||||
var vSynchNativeFrequency = Javatari.SCREEN_VSYNCH_MODE === -1 ? -1 : Javatari.SCREEN_FORCE_HOST_NATIVE_FPS; // -1 = Unknown or not detected
|
||||
var vSynchAltNativeFrequency = undefined; // undefined = deactivated. Used by NetPlay to force the same frequency as the Server
|
||||
|
||||
//var timeMeasures = [];
|
||||
//var lastPulseTime = 0;
|
||||
|
||||
};
|
||||
|
|
@ -61,7 +61,6 @@
|
|||
<script src="../src/main/atari/tia/TiaAudio.js"></script>
|
||||
<script src="../src/main/atari/tia/TiaAudioChannel.js"></script>
|
||||
<script src="../src/main/atari/tia/Tia.js"></script>
|
||||
<script src="../src/main/atari/console/Clock.js"></script>
|
||||
<script src="../src/main/atari/console/Bus.js"></script>
|
||||
<script src="../src/main/atari/console/AtariConsole.js"></script>
|
||||
<script src="../src/main/atari/controls/JoystickButtons.js"></script>
|
||||
|
@ -89,6 +88,7 @@
|
|||
<script src="../src/main/atari/cartridge/CartridgeFormats.js"></script>
|
||||
<script src="../src/main/atari/cartridge/CartridgeCreator.js"></script>
|
||||
<script src="../src/main/images/Images.js"></script>
|
||||
<script src="../src/main/room/clock/Clock.js"></script>
|
||||
<script src="../src/main/room/files/RecentStoredROMs.js"></script>
|
||||
<script src="../src/main/room/files/FileLoader.js"></script>
|
||||
<script src="../src/main/room/files/FileDownloader.js"></script>
|
||||
|
|
Loading…
Reference in a new issue