2014-06-29 00:57:33 +00:00
using System ;
using System.Collections.Generic ;
2013-11-30 02:20:34 +00:00
namespace BizHawk.Client.Common
{
public class PlatformFrameRates
{
2014-02-04 03:08:20 +00:00
// 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?
private static readonly Dictionary < string , double > _rates = new Dictionary < string , double >
2013-11-30 02:20:34 +00:00
{
2014-02-04 03:08:20 +00:00
{ "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)
2013-11-30 02:20:34 +00:00
{ "NES_PAL" , 50.006977968268290849 } ,
{ "FDS" , 60.098813897440515532 } ,
{ "FDS_PAL" , 50.006977968268290849 } ,
2014-02-18 04:02:35 +00:00
{ "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
2014-11-23 19:25:47 +00:00
{ "VBOY" , ( 20000000.0 / ( 259 * 384 * 4 ) ) } , //50.2734877735
2014-11-23 19:31:22 +00:00
{ "Lynx" , 16000000.0 / ( 16 * 105 * 159 ) } , // 59.89817310572028
2014-02-18 04:02:35 +00:00
{ "WSWAN" , ( 3072000.0 / ( 159 * 256 ) ) } , //75.4716981132
{ "GB" , 262144.0 / 4389.0 } , //59.7275005696
{ "GBC" , 262144.0 / 4389.0 } , //59.7275005696
2014-05-31 16:28:31 +00:00
{ "GBA" , 262144.0 / 4389.0 } , //59.7275005696
2014-08-21 17:41:59 +00:00
{ "GEN" , 53693175 / ( 3420.0 * 262 ) } ,
{ "GEN_PAL" , 53203424 / ( 3420.0 * 313 ) } ,
2014-05-31 16:28:31 +00:00
// 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
2013-11-30 02:20:34 +00:00
{ "A78" , 59.9227510135505 } ,
2014-12-17 01:22:25 +00:00
{ "Coleco" , 59.9227510135505 } ,
2014-12-18 03:36:40 +00:00
//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
//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))
2013-11-30 02:20:34 +00:00
} ;
2014-02-04 03:08:20 +00:00
public double this [ string systemId , bool pal ]
{
get
{
var key = systemId + ( pal ? "_PAL" : string . Empty ) ;
if ( _rates . ContainsKey ( key ) )
{
return _rates [ key ] ;
}
return 60.0 ;
}
}
2014-06-29 00:57:33 +00:00
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 ) ;
}
2013-11-30 02:20:34 +00:00
}
}