121 lines
5.0 KiB
C#
121 lines
5.0 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
|
|
namespace BizHawk.Client.Common
|
|
{
|
|
public class PlatformFrameRates
|
|
{
|
|
// these are political numbers, designed to be in accord with tasvideos.org tradition. theyre not necessarily mathematical factualities (although they may be in some cases)
|
|
// it would be nice if we could turn this into a rational expression natively, and also, to write some comments about the derivation and ideal valees (since this seems to be where theyre all collected)
|
|
// are we collecting them anywhere else? for avi-writing code perhaps?
|
|
|
|
// just some constants, according to specs
|
|
private static readonly double PALCarrier = (15625 * 283.75) + 25; // 4.43361875 MHz
|
|
private static readonly double NTSCCarrier = 4500000 * 227.5 / 286; // 3.579545454... MHz
|
|
private static readonly double PALNCarrier = (15625 * 229.25) + 25; // 3.58205625 MHz
|
|
|
|
private static readonly Dictionary<string, double> Rates = new Dictionary<string, double>
|
|
{
|
|
["NES"] = 60.098813897440515532, // discussion here: http://forums.nesdev.com/viewtopic.php?t=492 ; a rational expression would be (19687500 / 11) / ((341*262-0.529780.5)/3) -> (118125000 / 1965513) -> 60.098813897440515529533511098629 (so our chosen number is very close)
|
|
["NES_PAL"] = 50.006977968268290849,
|
|
["FDS"] = 60.098813897440515532,
|
|
["FDS_PAL"] = 50.006977968268290849,
|
|
["SNES"] = (double)21477272 / (4 * 341 * 262), // 60.098475521
|
|
["SNES_PAL"] = (double)21281370 / (4 * 341 * 312), // 50.0069789082
|
|
["SGB"] = (double)21477272 / (4 * 341 * 262), // 60.098475521
|
|
["SGB_PAL"] = (double)21281370 / (4 * 341 * 312), // 50.0069789082
|
|
["PCE"] = (7159090.90909090 / 455 / 263), // 59.8261054535
|
|
["PCECD"] = (7159090.90909090 / 455 / 263), // 59.8261054535
|
|
["SMS"] = (3579545 / 262.0 / 228.0), // 59.9227434043
|
|
["SMS_PAL"] = (3546893 / 313.0 / 228.0), // 49.7014320946
|
|
["GG"] = (3579545 / 262.0 / 228.0), // 59.9227434043
|
|
["GG_PAL"] = (3546893 / 313.0 / 228.0), // 49.7014320946
|
|
["SG"] = (3579545 / 262.0 / 228.0), // 59.9227434043
|
|
["SG_PAL"] = (3546893 / 313.0 / 228.0), // 49.7014320946
|
|
["NGP"] = (6144000.0 / (515 * 198)), // 60.2530155928
|
|
["VB"] = (20000000.0 / (259 * 384 * 4)), // 50.2734877735
|
|
["Lynx"] = 16000000.0 / (16 * 105 * 159), // 59.89817310572028
|
|
["WSWAN"] = (3072000.0 / (159 * 256)), // 75.4716981132
|
|
["GB"] = 262144.0 / 4389.0, // 59.7275005696
|
|
["GBC"] = 262144.0 / 4389.0, // 59.7275005696
|
|
["GBA"] = 262144.0 / 4389.0, // 59.7275005696
|
|
["GEN"] = 53693175 / (3420.0 * 262),
|
|
["GEN_PAL"] = 53203424 / (3420.0 * 313),
|
|
|
|
// while the number of scanlines per frame is software controlled and variable, we
|
|
// enforce exactly 262 (NTSC) 312 (PAL) per reference time frame
|
|
["A26"] = 315000000.0 / 88.0 / 262.0 / 228.0, // 59.922751013550531429197560173856
|
|
// this pal clock ref is exact
|
|
["A26_PAL"] = 3546895.0 / 312.0 / 228.0, // 49.860759671614934772829509671615
|
|
|
|
["A78"] = 59.9227510135505,
|
|
["Coleco"] = 59.9227510135505,
|
|
|
|
// according to http://problemkaputt.de/psx-spx.htm
|
|
["PSX"] = 44100.0 * 768 * 11 / 7 / 263 / 3413, // 59.292862562
|
|
["PSX_PAL"] = 44100.0 * 768 * 11 / 7 / 314 / 3406, // 49.7645593576
|
|
|
|
["C64_PAL"] = PALCarrier * 2 / 9 / 312 / 63,
|
|
["C64_NTSC"] = NTSCCarrier * 2 / 7 / 263 / 65,
|
|
["C64_NTSC_OLD"] = NTSCCarrier * 2 / 7 / 262 / 64,
|
|
["C64_DREAN"] = PALNCarrier * 2 / 7 / 312 / 65,
|
|
["INTV"] = 59.92
|
|
|
|
// according to ryphecha, using
|
|
// clocks[2] = { 53.693182e06, 53.203425e06 }; //ntsc console, pal console
|
|
// lpf[2][2] = { { 263, 262.5 }, { 314, 312.5 } }; //ntsc,pal; noninterlaced, interlaced
|
|
// cpl[2] = { 3412.5, 3405 }; //ntsc mode, pal mode
|
|
// PAL PS1: 0, PAL Mode: 0, Interlaced: 0 --- 59.826106 (53.693182e06/(263*3412.5))
|
|
// PAL PS1: 0, PAL Mode: 0, Interlaced: 1 --- 59.940060 (53.693182e06/(262.5*3412.5))
|
|
// PAL PS1: 1, PAL Mode: 1, Interlaced: 0 --- 49.761427 (53.203425e06/(314*3405))
|
|
// PAL PS1: 1, PAL Mode: 1, Interlaced: 1 --- 50.000282(53.203425e06/(312.5*3405))
|
|
};
|
|
|
|
public double this[string systemId, bool pal]
|
|
{
|
|
get
|
|
{
|
|
var key = systemId + (pal ? "_PAL" : "");
|
|
if (Rates.ContainsKey(key))
|
|
{
|
|
return Rates[key];
|
|
}
|
|
|
|
return 60.0;
|
|
}
|
|
}
|
|
|
|
public TimeSpan MovieTime(IMovie movie)
|
|
{
|
|
var dblseconds = GetSeconds(movie);
|
|
var seconds = (int)(dblseconds % 60);
|
|
var days = seconds / 86400;
|
|
var hours = seconds / 3600;
|
|
var minutes = (seconds / 60) % 60;
|
|
var milliseconds = (int)((dblseconds - seconds) * 1000);
|
|
return new TimeSpan(days, hours, minutes, seconds, milliseconds);
|
|
}
|
|
|
|
private double Fps(IMovie movie)
|
|
{
|
|
var system = movie.HeaderEntries[HeaderKeys.PLATFORM];
|
|
var pal = movie.HeaderEntries.ContainsKey(HeaderKeys.PAL) &&
|
|
movie.HeaderEntries[HeaderKeys.PAL] == "1";
|
|
|
|
return this[system, pal];
|
|
}
|
|
|
|
private double GetSeconds(IMovie movie)
|
|
{
|
|
double frames = movie.InputLogLength;
|
|
|
|
if (frames < 1)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
return frames / Fps(movie);
|
|
}
|
|
}
|
|
}
|