DebugConfig ( {
//all: true,
calcMain : 0 ,
submitVar : 0 ,
input _ok : 0 ,
updateDisplay : 0 ,
getTiming : 0 ,
marginsUIChange : 0 ,
timingUIChange : 0 ,
generate _table : 0 ,
SI : 0 ,
SI _include _exclude : 0 ,
SI _set _options : 0 ,
SI _set _precision : 0 ,
CTA : 0 ,
DMT : 0 ,
CVT : 0 ,
CVT _R : 0 ,
GTF : 0 ,
} ) ;
CTA861 = { } ;
DMT _List = { } ;
// The intepreted current state of all input fields is stored here
Global _InputVars = {
'HRES' : '' , // Int
'VRES' : '' , // Int
'FREQ' : '' , // Float
'COLOR_DEPTH' : '' ,
'PIXEL_FORMAT' : '' ,
'COMP' : '' ,
'SCAN' : '' ,
'MARGINS' : '' ,
'TIMING_STD' : '' ,
'V_FP' : '' ,
'V_BP' : '' ,
'V_SW' : '' ,
'H_FP' : '' ,
'H_BP' : '' ,
'H_SW' : '' ,
'V_FP_INT' : '' ,
'V_BP_INT' : '' ,
'V_SW_INT' : '' ,
}
Detailed _Results = {
}
Encoding _Overhead = {
'8b/10b' : 1.25 ,
'16b/18b' : 1.125 ,
} ;
Interface = [
{
name : "DisplayPort 1.3–1.4" ,
encoding : "8b/10b" ,
datarate : 25.92 * ( 10 * * 9 ) ,
} , {
name : "DisplayPort 1.2" ,
encoding : "8b/10b" ,
datarate : 17.28 * ( 10 * * 9 ) ,
} , {
name : "DisplayPort 1.0–1.1" ,
encoding : "8b/10b" ,
datarate : 8.64 * ( 10 * * 9 ) ,
} , {
name : "HDMI 2.1" ,
encoding : "16b/18b" ,
datarate : 48 * ( 10 * * 9 ) * ( 16 / 18 ) ,
} , {
name : "HDMI 2.0" ,
encoding : "8b/10b" ,
datarate : 14.4 * ( 10 * * 9 ) ,
} , {
name : "HDMI 1.3–1.4" ,
encoding : "8b/10b" ,
datarate : 8.16 * ( 10 * * 9 ) ,
} , {
name : "HDMI 1.0–1.2" ,
encoding : "8b/10b" ,
datarate : 3.96 * ( 10 * * 9 ) ,
} , {
name : "Dual-Link DVI" ,
encoding : "8b/10b" ,
datarate : 7.92 * ( 10 * * 9 ) ,
} , {
name : "Single-Link DVI" ,
encoding : "8b/10b" ,
datarate : 3.96 * ( 10 * * 9 ) ,
} , {
name : "Thunderbolt 3 (Gen 2)" ,
encoding : "unknown" ,
datarate : 40 * ( 10 * * 9 ) ,
} , {
name : "Thunderbolt 3 (Gen 1)" ,
encoding : "unknown" ,
datarate : 34.56 * ( 10 * * 9 ) ,
} , {
name : "Thunderbolt 2" ,
encoding : "unknown" ,
datarate : 17.28 * ( 10 * * 9 ) ,
} , {
name : "Thunderbolt" ,
encoding : "unknown" ,
datarate : 8.64 * ( 10 * * 9 ) ,
} ,
] ;
function submitVar ( id , val ) {
DEBUG ( id , val ) ;
var len = 0 ;
var GlobalVars _Key = '' ;
if ( typeof ( val ) === 'number' ) { val = val . toString ( ) ; }
if ( id == 'INPUT_HRES' || id == 'INPUT_VRES' ) {
if ( id == 'INPUT_HRES' ) GlobalVars _Key = 'HRES' ;
else if ( id == 'INPUT_VRES' ) GlobalVars _Key = 'VRES' ;
val = parseNum ( val ) ;
if ( isNum ( val ) == true ) {
val = Math . abs ( parseInt ( val ) ) ;
Global _InputVars [ GlobalVars _Key ] = val ;
}
else {
DEBUG ( id + ' input is not a number:' , val ) ;
Global _InputVars [ GlobalVars _Key ] = '' ;
}
DEBUG ( "Global_InputVars['" + GlobalVars _Key + "'] was set to" , Global _InputVars [ GlobalVars _Key ] ) ;
}
else if ( id == 'INPUT_F' ) {
GlobalVars _Key = 'FREQ' ;
val = parseNum ( val ) ;
if ( isNum ( val ) == true ) {
Global _InputVars [ GlobalVars _Key ] = Math . abs ( val ) ;
}
else {
DEBUG ( id + ' input is not a number:' , val ) ;
Global _InputVars [ GlobalVars _Key ] = '' ;
}
DEBUG ( "Global_InputVars['" + GlobalVars _Key + "'] was set to" , Global _InputVars [ GlobalVars _Key ] ) ;
}
else if ( id == 'COLOR_DEPTH_FORM' ) {
// Value is either the color depth number (in bits per pixel), or the string 'Custom'
GlobalVars _Key = 'COLOR_DEPTH' ;
colordepthUIChange ( ) ;
if ( val != 'Custom' ) { Global _InputVars [ GlobalVars _Key ] = val ; }
else if ( val == 'Custom' ) { // Custom color depth
// If Custom, grab the number from the custom color depth input field
val = parseInt ( parseNum ( $ ( '#CUSTOM_COLOR_DEPTH' ) . val ( ) ) ) ;
if ( isNum ( val ) == true ) {
if ( $ ( 'input[name=CD_UNIT_SLCT]:checked' ) . val ( ) == 'bpc' ) {
val = val * 3 ; // If user enters values in units of bpc, then multiply by 3 to convert to bit/px (bpp)
}
Global _InputVars [ GlobalVars _Key ] = Math . abs ( val ) ;
}
else {
DEBUG ( id + ' input is not a number:' , val ) ;
Global _InputVars [ GlobalVars _Key ] = '' ;
}
}
DEBUG ( "Global_InputVars['" + GlobalVars _Key + "'] was set to" , Global _InputVars [ GlobalVars _Key ] ) ;
}
else if ( id == 'PIXEL_FORMAT_FORM' ) {
GlobalVars _Key = 'PIXEL_FORMAT' ;
if ( val == 'RGB' || val == 'YCBCR 4:4:4' ) { val = 1.0 ; }
else if ( val == 'YCBCR 4:2:2' ) { val = 1.5 ; }
else if ( val == 'YCBCR 4:2:0' ) { val = 2.0 ; }
Global _InputVars [ GlobalVars _Key ] = val ;
DEBUG ( "Global_InputVars['" + GlobalVars _Key + "'] was set to" , Global _InputVars [ GlobalVars _Key ] ) ;
}
else if ( id == 'COMPRESSION_FORM' ) {
GlobalVars _Key = 'COMP' ;
if ( val == 'Uncompressed' ) { val = 1.0 ; }
else if ( val == 'DSC 2.0x' ) { val = 2.0 ; }
else if ( val == 'DSC 2.5x' ) { val = 2.5 ; }
else if ( val == 'DSC 3.0x' ) { val = 3.0 ; }
Global _InputVars [ GlobalVars _Key ] = val ;
DEBUG ( "Global_InputVars['" + GlobalVars _Key + "'] was set to" , Global _InputVars [ GlobalVars _Key ] ) ;
}
else if ( id == 'SCAN_FORM' ) {
GlobalVars _Key = 'SCAN' ;
if ( val == 'p' ) { val = 1 ; }
else if ( val == 'i' ) { val = 2 ; }
Global _InputVars [ GlobalVars _Key ] = val ;
DEBUG ( "Global_InputVars['" + GlobalVars _Key + "'] was set to" , Global _InputVars [ GlobalVars _Key ] ) ;
timingUIChange ( ) ;
DEBUG ( 'Set interlaced timing row display to:' , $ ( '#Interlaced_Timing_Row' ) . css ( 'display' ) ) ;
}
else if ( id == 'MARGINS_FORM' ) {
// val is either 'y' or 'n'
GlobalVars _Key = 'MARGINS' ;
marginsUIChange ( ) ;
if ( val == 'n' ) {
Global _InputVars [ GlobalVars _Key ] = 0 ;
}
else if ( val == 'y' ) {
val = parseFloat ( parseNum ( $ ( '#CUSTOM_MARGINS' ) . val ( ) ) ) ;
if ( isNum ( val ) == true ) {
Global _InputVars [ GlobalVars _Key ] = Math . abs ( val ) ;
}
else {
DEBUG ( id + ' input is not a number:' , val ) ;
Global _InputVars [ GlobalVars _Key ] = '' ;
}
}
else { DEBUG ( 'invalid input combination. id/val = ' , id , val ) } // If val is not 'y' or 'n', then something somewhere has gone terribly wrong
DEBUG ( "Global_InputVars['" + GlobalVars _Key + "'] was set to" , Global _InputVars [ GlobalVars _Key ] ) ;
}
else if ( id == 'TIMING_DROP' ) {
GlobalVars _Key = 'TIMING_STD' ;
Global _InputVars [ GlobalVars _Key ] = val ;
DEBUG ( "Global_InputVars['" + GlobalVars _Key + "'] was set to" , Global _InputVars [ GlobalVars _Key ] ) ;
timingUIChange ( ) ;
if ( val != 'Custom' && val != 'None' ) {
if ( Global _InputVars [ 'HRES' ] == '' || Global _InputVars [ 'VRES' ] == '' || Global _InputVars [ 'FREQ' ] == '' ) {
$ ( '#TIMING_FORMAT_NAME' ) . html ( '' ) ;
clearTiming ( ) ;
}
}
}
else if ( id == 'V_FP' || id == 'V_BP' || id == 'V_SW' ||
id == 'H_FP' || id == 'H_BP' || id == 'H_SW' ||
id == 'V_FP_INT' || id == 'V_SW_INT' || id == 'V_BP_INT' ) {
GlobalVars _Key = id ;
//val = Math.abs(parseNum(val));
if ( isNum ( val ) ) {
Global _InputVars [ id ] = Math . abs ( val ) ;
$ ( '#' + id ) . val ( val ) ;
if ( Global _InputVars [ 'V_FP' ] != '' && Global _InputVars [ 'V_BP' ] != '' && Global _InputVars [ 'V_SW' ] != '' ) {
$ ( '#V_BLANK' ) . html ( Global _InputVars [ 'V_FP' ] + Global _InputVars [ 'V_BP' ] + Global _InputVars [ 'V_SW' ] ) ; }
if ( Global _InputVars [ 'H_FP' ] != '' && Global _InputVars [ 'H_BP' ] != '' && Global _InputVars [ 'H_SW' ] != '' ) {
$ ( '#H_BLANK' ) . html ( Global _InputVars [ 'H_FP' ] + Global _InputVars [ 'H_BP' ] + Global _InputVars [ 'H_SW' ] ) ; }
if ( Global _InputVars [ 'V_FP_INT' ] != '' && Global _InputVars [ 'V_BP_INT' ] != '' && Global _InputVars [ 'V_SW_INT' ] != '' ) {
$ ( '#V_BLANK_INT' ) . html ( Global _InputVars [ 'V_FP_INT' ] + Global _InputVars [ 'V_BP_INT' ] + Global _InputVars [ 'V_SW_INT' ] ) ; }
}
else {
DEBUG ( id + ' input is not a number:' , val ) ;
Global _InputVars [ id ] = '' ;
$ ( '#' + id ) . val ( '' ) ;
if ( id == 'V_FP' || id == 'V_BP' || id == 'V_SW' ) { $ ( '#V_BLANK' ) . html ( '' ) ; }
if ( id == 'H_FP' || id == 'H_BP' || id == 'H_SW' ) { $ ( '#H_BLANK' ) . html ( '' ) ; }
if ( id == 'V_FP_INT' || id == 'V_SW_INT' || id == 'V_BP_INT' ) { $ ( '#V_BLANK_INT' ) . html ( '' ) ; }
}
DEBUG ( "Global_InputVars['" + GlobalVars _Key + "'] was set to" , Global _InputVars [ GlobalVars _Key ] ) ;
// Update value displayed in the UI input field
// Update total Vblank and Hblank numbers on the UI
}
}
function generate _table ( type , input _datarate ) {
if ( type == "Interface Support" ) {
table = $ ( "#interface_support_table" ) ;
contents = '' ;
contents += ( '<tr><th class="title" colspan="6">Interface Support</th></tr>' ) ;
contents += ( '<tr>' ) ;
contents += ( '<th rowspan="2">% Usage</th>' ) ;
contents += ( '<th rowspan="2">Interface</th>' ) ;
contents += ( '<th rowspan="2">Encoding</th>' ) ;
contents += ( '<th colspan="3" style="border-bottom:1px solid #FFFFFF;">Maximum</th></tr>' ) ;
contents += ( '<tr><th>Pixel Clock</th><th>Datarate</th><th>Bandwidth</th></tr>' ) ;
var name ;
var encoding ;
var datarate ;
var pixel _clock ;
var bandwidth ;
var overhead ;
var saturation ;
for ( var x = 0 ; x < Interface . length ; x ++ ) {
name = Interface [ x ] [ 'name' ] ;
encoding = Interface [ x ] [ 'encoding' ] ;
if ( encoding == 'unknown' ) {
datarate = Interface [ x ] [ 'datarate' ] ;
bandwidth = '?' ;
encoding = '?' ;
}
else {
overhead = Encoding _Overhead [ encoding ] ;
datarate = Interface [ x ] [ 'datarate' ] ;
bandwidth = datarate * overhead ;
}
pixel _clock = datarate / 24 ;
saturation = input _datarate / datarate ;
if ( input _datarate == - 1 ) {
contents += ( '<tr><td></td>' ) ;
}
else {
contents += ( '<tr><td>' + saturation . toFixed ( 1 ) + '%</td>' ) ;
}
contents += ( '<td style="text-align:left; white-space:nowrap;">' + name + '</td><td>' + encoding + '</td><td>' + SI ( pixel _clock , 'Hz' , { p : [ 'M0' , 'G3' ] } ) + '</td><td>' + SI ( datarate , 'bit/s' , 2 ) + '</td><td>' + SI ( bandwidth , 'bit/s' , 2 ) + '</td></tr>' ) ;
}
table . html ( contents ) ;
return ;
}
else if ( type == "Maximum Refresh Frequency" ) {
return ;
}
return ;
}
function input _ok ( ) {
// This checks to make sure all the necessary fields are filled in, and their contents are valid, before allowing the Calculation function to proceed.
var val ;
var checklist = [ 'HRES' , 'VRES' , 'FREQ' ] ;
for ( var i = 0 ; i < checklist . length ; i ++ ) {
val = Global _InputVars [ checklist [ i ] ] ;
if ( ! ( isPositive ( val ) ) ) {
DEBUG ( 'Calculation aborted. ' + checklist [ i ] + ' contains an empty or non-numeric string.' , val ) ;
return false ;
}
}
if ( ! isNum ( Global _InputVars [ 'COLOR_DEPTH' ] ) ) {
var abort = true ;
DEBUG ( 'Calculation aborted. Color Depth has not yet been defined.' ) ;
return false ;
}
if ( $ ( 'input[name=COLOR_DEPTH_SLCT]:checked' ) . val ( ) == 'Custom' ) {
val = Global _InputVars [ 'COLOR_DEPTH' ] ;
if ( ! ( isPositive ( val ) ) ) {
DEBUG ( 'Calculation aborted. COLOR_DEPTH_SLCT is set to Custom, but CUSTOM_COLOR_DEPTH contains an empty or non-numeric string, or 0.' , val ) ;
return false ;
}
}
if ( Global _InputVars [ 'PIXEL_FORMAT' ] == '' ) {
var abort = true ;
DEBUG ( 'Calculation aborted. Pixel Format has not yet been defined.' ) ;
return false ;
}
if ( Global _InputVars [ 'TIMING_STD' ] == '' ) {
var abort = true ;
DEBUG ( 'Calculation aborted. Timing Standard has not yet been defined.' ) ;
return false ;
}
else if ( Global _InputVars [ 'TIMING_STD' ] == 'Custom' ) {
checklist = [ 'V_FP' , 'V_BP' , 'V_SW' , 'H_FP' , 'H_BP' , 'H_SW' ] ;
var abort = false ;
for ( var i = 0 ; i < checklist . length ; i ++ ) {
val = Global _InputVars [ checklist [ i ] ] ;
if ( ! ( isPositiveZ ( val ) ) ) {
abort = true ;
}
}
if ( abort == true ) {
DEBUG ( 'Calculation aborted. TIMING_DROP is set to Custom, but one or more timing parameter fields contains an empty or non-numeric string.' , Global _InputVars ) ;
return false ;
}
}
if ( ! isNum ( Global _InputVars [ 'COMP' ] ) ) {
var abort = true ;
DEBUG ( 'Calculation aborted. COMPRESSION has not yet been defined.' ) ;
return false ;
}
if ( ! isNum ( Global _InputVars [ 'SCAN' ] ) ) {
var abort = true ;
DEBUG ( 'Calculation aborted. SCAN TYPE has not yet been defined.' ) ;
return false ;
}
if ( ! isNum ( Global _InputVars [ 'MARGINS' ] ) ) {
var abort = true ;
DEBUG ( 'Calculation aborted. Margins have not yet been defined.' ) ;
return false ;
}
if ( $ ( 'input[name=MARGINS_SLCT]:checked' ) . val ( ) == 'y' ) {
val = Global _InputVars [ 'MARGINS' ] ;
if ( ! ( isPositiveZ ( val ) ) ) {
DEBUG ( 'Calculation aborted. MARGINS_SLCT is set to Yes, but CUSTOM_MARGINS contains an empty or non-numeric string.' , val ) ;
return false ;
}
}
return true ;
}
function calcMain ( ) {
/ *
if ( Global _InputVars [ 'HRES' ] == '' ) { submitVar ( 'INPUT_HRES' ) }
if ( Global _InputVars [ 'VRES' ] == '' ) { submitVar ( 'INPUT_VRES' ) }
if ( Global _InputVars [ 'FREQ' ] == '' ) { submitVar ( 'INPUT_F' ) }
if ( Global _InputVars [ 'COLOR_DEPTH' ] == '' ) { submitVar ( 'COLOR_DEPTH_FORM' ) }
if ( Global _InputVars [ 'PIXEL_FORMAT' ] == '' ) { submitVar ( 'PIXEL_FORMAT_FORM' ) }
if ( Global _InputVars [ 'COMP' ] == '' ) { submitVar ( 'COMPRESSION_FORM' ) }
if ( Global _InputVars [ 'SCAN' ] == '' ) { submitVar ( 'SCAN_FORM' ) }
if ( Global _InputVars [ 'MARGINS' ] == '' ) { submitVar ( 'MARGINS_FORM' ) }
if ( Global _InputVars [ 'TIMING_STD' ] == '' ) { submitVar ( 'TIMING_DROP' ) }
if ( Global _InputVars [ 'V_FP' ] == '' ) { submitVar ( 'V_FP' ) }
if ( Global _InputVars [ 'V_BP' ] == '' ) { submitVar ( 'V_BP' ) }
if ( Global _InputVars [ 'V_SW' ] == '' ) { submitVar ( 'V_SW' ) }
if ( Global _InputVars [ 'H_FP' ] == '' ) { submitVar ( 'H_FP' ) }
if ( Global _InputVars [ 'H_BP' ] == '' ) { submitVar ( 'H_BP' ) }
if ( Global _InputVars [ 'H_SW' ] == '' ) { submitVar ( 'H_SW' ) }
if ( Global _InputVars [ 'V_FP_INT' ] == '' ) { submitVar ( 'V_FP_INT' ) }
if ( Global _InputVars [ 'V_BP_INT' ] == '' ) { submitVar ( 'V_BP_INT' ) }
if ( Global _InputVars [ 'V_SW_INT' ] == '' ) { submitVar ( 'V_SW_INT' ) }
* /
if ( ! input _ok ( ) ) { clearResults ( ) ; return ; }
var hres = Global _InputVars [ 'HRES' ] ;
var vres = Global _InputVars [ 'VRES' ] ;
var freq = Global _InputVars [ 'FREQ' ] ;
var color _depth = Global _InputVars [ 'COLOR_DEPTH' ] ;
var px _format = Global _InputVars [ 'PIXEL_FORMAT' ] ;
var comp = Global _InputVars [ 'COMP' ] ;
var scan = Global _InputVars [ 'SCAN' ] ;
var timing _standard = Global _InputVars [ 'TIMING_STD' ] ;
// Get timing parameters
Timing = getTiming ( timing _standard ) ;
if ( ! Timing ) { clearResults ( ) ; return ; } // Abort if getTiming returns false, it indicates the format is not defined for that timing standard.
DEBUG ( 'Timing:' , Timing ) ;
var h _eff = Timing [ 'H_EFF' ]
var v _eff = Timing [ 'V_EFF' ] * scan
var freq _act = Timing [ 'F_ACTUAL' ] ;
/ *
var results = {
hres : hres ,
vres : vres ,
freq : freq ,
px _bits : color _depth ,
px _format : px _format ,
comp : comp ,
scan : scan ,
Timing : Timing ,
// Calculate results
// Resolution with blanking intervals
h _eff : Timing [ 'H_EFF' ] ,
v _eff : Timing [ 'V_EFF' ] ,
// Aspect ratio
ratio _num : hres / vres ,
ratio _str : ( hres / GCD ( hres , vres ) ) + ':' + ( vres / GCD ( hres , vres ) ) ,
// Total pixel count of image
px _per _frame : hres * vres ,
px _per _frame _eff : ( Timing [ 'H_EFF' ] ) * ( Timing [ 'V_EFF' ] ) ,
// Size (bits) of one frame
bits _per _frame : hres * vres * color _depth ,
bits _per _frame _eff : ( Timing [ 'H_EFF' ] ) * ( Timing [ 'V_EFF' ] ) * color _depth ,
// Pixel clock
px _per _sec : hres * vres * Timing [ 'F_ACTUAL' ] ,
px _per _sec _eff : ( Timing [ 'H_EFF' ] ) * ( Timing [ 'V_EFF' ] ) * Timing [ 'F_ACTUAL' ] ,
// Raw bit rate
bits _per _sec _eff : ( Timing [ 'H_EFF' ] ) * ( Timing [ 'V_EFF' ] ) * color _depth * Timing [ 'F_ACTUAL' ] ,
} ; * /
Detailed _Results [ 'data_rate' ] = SI (
( h _eff * v _eff * freq _act * color _depth / px _format / scan / comp ) ,
'bit/s' ,
{ 'p' : 2 , 'output' : 'split' } ,
) ;
Detailed _Results [ '8b10b' ] = SI (
( h _eff * v _eff * freq _act * color _depth / px _format / scan / comp ) * ( 1.25 ) ,
'bit/s' ,
{ 'p' : 2 , 'output' : 'split' } ,
) ;
Detailed _Results [ '16b18b' ] = SI (
( h _eff * v _eff * freq _act * color _depth / px _format / scan / comp ) * ( 1.125 ) ,
'bit/s' ,
{ 'p' : 2 , 'output' : 'split' } ,
) ;
Detailed _Results [ 'pixel_rate' ] = SI (
( h _eff * v _eff * freq _act / scan ) ,
'px/s' ,
{ 'p' : [ 3 , 'b1' , 'k1' , 'M1' ] , 'output' : 'split' } ,
) ;
Detailed _Results [ 'pixel_rate_active' ] = SI (
( hres * vres * freq _act / scan ) ,
'px/s' ,
{ 'p' : [ 3 , 'b1' , 'k1' , 'M1' ] , 'output' : 'split' } ,
) ;
Detailed _Results [ 'active_px' ] = {
'h' : hres ,
'v' : vres ,
't' : SI ( hres * vres , 'px' , { 'p' : 0 , 'output' : 'split' , 'include' : [ 'b' ] } ) ,
}
Detailed _Results [ 'blank_px' ] = {
'h' : h _eff - hres ,
'v' : v _eff - vres ,
't' : SI ( ( h _eff * v _eff ) - ( hres * vres ) , 'px' , { 'p' : 0 , 'output' : 'split' , 'include' : [ 'b' ] } ) ,
}
Detailed _Results [ 'total_px' ] = {
'h' : h _eff ,
'v' : v _eff ,
't' : SI ( h _eff * v _eff , 'px' , { 'p' : 0 , 'output' : 'split' , 'exclude' : [ '<B' , '>B' ] } ) ,
}
Detailed _Results [ 'overhead_px' ] = {
'h' : SI ( 100 * ( ( h _eff / hres ) - 1 ) , '%' , { 'p' : 2 , 'output' : 'split' , 'exclude' : [ '<B' , '>B' ] } ) ,
'v' : SI ( 100 * ( ( v _eff / vres ) - 1 ) , '%' , { 'p' : 2 , 'output' : 'split' , 'exclude' : [ '<B' , '>B' ] } ) ,
't' : SI ( 100 * ( ( ( h _eff * v _eff ) / ( hres * vres ) ) - 1 ) , '%' , { 'p' : 2 , 'output' : 'split' , 'exclude' : [ '<B' , '>B' ] } ) ,
}
if ( $ ( 'input[name=COLOR_DEPTH_SLCT]:checked' ) . val ( ) == 'Custom' ) {
if ( color _depth % 3 == 0 ) { Detailed _Results [ 'bpc' ] = { 'val' : color _depth / 3 , 'unit' : 'bpc' } ; }
else { Detailed _Results [ 'bpc' ] = { 'val' : '-' , 'unit' : '' } ; }
}
else {
Detailed _Results [ 'bpc' ] = { 'val' : color _depth / 3 , 'unit' : 'bpc' }
}
Detailed _Results [ 'bpp' ] = { 'val' : color _depth , 'unit' : 'bit/px' } ;
Detailed _Results [ 'palette' ] = SI ( Math . pow ( 2 , color _depth ) , 'colors' , { 'p' : 0 , 'output' : 'split' , 'include' : [ 'b' ] } ) ;
if ( $ ( 'input[name=PX_FORMAT_SLCT]:checked' ) . val ( ) == 'RGB' ) { Detailed _Results [ 'px_format' ] = 'RGB' ; }
else if ( $ ( 'input[name=PX_FORMAT_SLCT]:checked' ) . val ( ) == 'YCBCR 4:4:4' ) { Detailed _Results [ 'px_format' ] = 'YC<sub>B</sub>C<sub>R</sub> 4:4:4' ; }
else if ( $ ( 'input[name=PX_FORMAT_SLCT]:checked' ) . val ( ) == 'YCBCR 4:2:2' ) { Detailed _Results [ 'px_format' ] = 'YC<sub>B</sub>C<sub>R</sub> 4:2:2' ; }
else if ( $ ( 'input[name=PX_FORMAT_SLCT]:checked' ) . val ( ) == 'YCBCR 4:2:0' ) { Detailed _Results [ 'px_format' ] = 'YC<sub>B</sub>C<sub>R</sub> 4:2:0' ; }
if ( scan == 1 ) { Detailed _Results [ 'scan' ] = 'Progressive' ; }
if ( scan == 2 ) { Detailed _Results [ 'scan' ] = 'Interlaced' ; }
Detailed _Results [ 'v_freq' ] = SI (
freq ,
'Hz' ,
{ 'p' : 3 , 'output' : 'split' , 'include' : [ '>=b' ] } ,
) ;
Detailed _Results [ 'v_freq_actual' ] = SI (
Timing [ 'F_ACTUAL' ] ,
'Hz' ,
{ 'p' : 3 , 'output' : 'split' , 'include' : [ '>=b' ] } ,
) ;
DEBUG ( 'freq:' , typeof ( freq ) , freq )
DEBUG ( 'f_actual' , typeof ( Timing [ 'F_ACTUAL' ] ) , Timing [ 'F_ACTUAL' ] )
DEBUG ( 'f - fa' , freq - Timing [ 'F_ACTUAL' ] )
Detailed _Results [ 'v_freq_dev' ] = SI (
Math . abs ( freq - Timing [ 'F_ACTUAL' ] ) ,
'Hz' ,
{ 'p' : 6 , 'output' : 'split' , 'include' : [ '>=b' ] } ,
) ;
Detailed _Results [ 'v_freq_dev_perc' ] = SI (
Math . abs ( 100 * ( ( freq - Timing [ 'F_ACTUAL' ] ) / freq ) ) ,
'%' ,
{ 'p' : 6 , 'output' : 'split' , 'include' : [ 'b' ] } ,
) ;
Detailed _Results [ 'v_per' ] = SI (
1 / freq ,
's' ,
{ 'p' : 3 , 'output' : 'split' , 'include' : [ '<=b' ] } ,
) ;
Detailed _Results [ 'v_per_actual' ] = SI (
1 / Timing [ 'F_ACTUAL' ] ,
's' ,
{ 'p' : 3 , 'output' : 'split' , 'include' : [ '<=b' ] } ,
) ;
Detailed _Results [ 'v_per_dev' ] = SI (
Math . abs ( ( 1 / freq ) - ( 1 / Timing [ 'F_ACTUAL' ] ) ) ,
's' ,
{ 'p' : 3 , 'output' : 'split' , 'include' : [ '<=b' ] } ,
) ;
Detailed _Results [ 'v_per_dev_perc' ] = SI (
Math . abs ( 100 * ( ( 1 / freq ) - ( 1 / Timing [ 'F_ACTUAL' ] ) ) / ( 1 / freq ) ) ,
'%' ,
{ 'p' : 6 , 'output' : 'split' , 'include' : [ 'b' ] } ,
) ;
Detailed _Results [ 'h_freq' ] = SI (
( v _eff * Timing [ 'F_ACTUAL' ] ) / scan ,
'Hz' ,
{ 'p' : 3 , 'output' : 'split' , 'include' : [ '>=b' ] } ,
) ;
Detailed _Results [ 'h_per' ] = SI (
scan / ( v _eff * Timing [ 'F_ACTUAL' ] ) ,
's' ,
{ 'p' : 3 , 'output' : 'split' , 'include' : [ '<=b' ] } ,
) ;
//DEBUG('Results:', SI(results['bits_per_sec_eff'], 'bit/s', 2), results);
updateDisplay ( ) ;
}
function getTiming ( timing _standard ) {
// Just a traffic control function
// Actual parameters are calculated in dedicated functions for each standard
if ( ! ( isPositiveZ ( Global _InputVars [ 'HRES' ] ) && isPositiveZ ( Global _InputVars [ 'VRES' ] ) && isPositiveZ ( Global _InputVars [ 'FREQ' ] ) ) ) {
DEBUG ( 'Timing calculation aborted, HRES, VRES, or FREQ contains invalid input.' , Global _InputVars [ 'HRES' ] , Global _InputVars [ 'VRES' ] , Global _InputVars [ 'FREQ' ] ) ;
return {
'V_FP' : '' ,
'V_BP' : '' ,
'V_SW' : '' ,
'H_FP' : '' ,
'H_BP' : '' ,
'H_SW' : '' ,
'V_FP_INT' : '' ,
'V_BP_INT' : '' ,
'V_SW_INT' : '' ,
'V_BL' : '' ,
'H_BL' : '' ,
'F_ACTUAL' : Global _InputVars [ 'FREQ' ] ,
} ;
}
DEBUG ( 'Timing Standard:' , timing _standard )
if ( timing _standard != 'Custom' ) {
if ( timing _standard == 'CVT-R2' ) {
DEBUG ( 'Fetching CVT-R2 Timing...' )
Timing = CVT _R ( 2 ) ;
if ( ! Timing ) {
DEBUG ( 'CVT-R2 calculation error.' ) ;
clearTiming ( ) ;
return false ; }
else {
$ ( '#TIMING_FORMAT_NAME' ) . html ( '<b>VESA Name:</b> ' + ( Global _InputVars [ 'HRES' ] * Global _InputVars [ 'VRES' ] / 1000000 ) . toFixed ( 2 ) + 'M' + Timing [ 'VESA_AR' ] + '-R' ) ;
}
}
else if ( timing _standard == 'CVT-RB' ) {
Timing = CVT _R ( 1 ) ;
if ( ! Timing ) {
DEBUG ( 'CVT-RB calculation error.' ) ;
$ ( '#TIMING_FORMAT_NAME' ) . html ( '' ) ;
clearTiming ( ) ;
return false ; }
else {
$ ( '#TIMING_FORMAT_NAME' ) . html ( '<b>VESA Name:</b> ' + ( Global _InputVars [ 'HRES' ] * Global _InputVars [ 'VRES' ] / 1000000 ) . toFixed ( 2 ) + 'M' + Timing [ 'VESA_AR' ] + '-R' ) ;
}
}
else if ( timing _standard == 'CVT' ) {
Timing = CVT ( ) ;
if ( ! Timing ) {
DEBUG ( 'CVT calculation error.' ) ;
$ ( '#TIMING_FORMAT_NAME' ) . html ( '' ) ;
clearTiming ( ) ;
return false ; }
else {
$ ( '#TIMING_FORMAT_NAME' ) . html ( '<b>VESA Name:</b> ' + ( Global _InputVars [ 'HRES' ] * Global _InputVars [ 'VRES' ] / 1000000 ) . toFixed ( 2 ) + 'M' + Timing [ 'VESA_AR' ] ) ;
}
}
else if ( timing _standard == 'GTF' ) {
Timing = GTF ( ) ;
$ ( '#TIMING_FORMAT_NAME' ) . html ( '' ) ;
if ( ! Timing ) {
DEBUG ( 'GTF calculation error.' ) ;
clearTiming ( ) ;
return false ;
}
}
else if ( timing _standard == 'DMT' ) {
Timing = DMT ( ) ;
if ( ! Timing ) {
DEBUG ( 'Not a DMT Format. DMT Function returned false.' ) ;
$ ( '#TIMING_FORMAT_NAME' ) . html ( 'Not a DMT format' ) ;
clearTiming ( ) ;
return false ; }
else {
$ ( '#TIMING_FORMAT_NAME' ) . html ( '<b>DMT ID:</b> ' + Timing [ 'ID' ] ) ;
}
}
else if ( timing _standard == 'CTA-861' ) {
Timing = CTA ( ) ;
if ( ! Timing ) {
DEBUG ( 'Not a CTA Format. CTA Function returned false.' ) ;
$ ( '#TIMING_FORMAT_NAME' ) . html ( 'Not a CTA format' ) ;
clearTiming ( ) ;
return false ; }
else {
$ ( '#TIMING_FORMAT_NAME' ) . html ( '<b>CTA VIC:</b> ' + Timing [ 'VIC' ] ) ;
}
}
else if ( timing _standard == 'None' ) {
Timing = {
'V_FP' : 0 ,
'V_BP' : 0 ,
'V_SW' : 0 ,
'H_FP' : 0 ,
'H_BP' : 0 ,
'H_SW' : 0 ,
'V_FP_INT' : 0 ,
'V_BP_INT' : 0 ,
'V_SW_INT' : 0 ,
'V_BL' : 0 ,
'H_BL' : 0 ,
'V_EFF' : Global _InputVars [ 'VRES' ] ,
'H_EFF' : Global _InputVars [ 'HRES' ] ,
'F_ACTUAL' : Global _InputVars [ 'FREQ' ] ,
}
$ ( '#TIMING_FORMAT_NAME' ) . html ( '' ) ;
}
// Update UI timing parameter fields with the newly generated timings
submitVar ( 'V_FP' , Timing [ 'V_FP' ] ) ;
submitVar ( 'V_BP' , Timing [ 'V_BP' ] ) ;
submitVar ( 'V_SW' , Timing [ 'V_SW' ] ) ;
submitVar ( 'H_FP' , Timing [ 'H_FP' ] ) ;
submitVar ( 'H_BP' , Timing [ 'H_BP' ] ) ;
submitVar ( 'H_SW' , Timing [ 'H_SW' ] ) ;
submitVar ( 'V_FP_INT' , Timing [ 'V_FP_INT' ] ) ;
submitVar ( 'V_SW_INT' , Timing [ 'V_SW_INT' ] ) ;
submitVar ( 'V_BP_INT' , Timing [ 'V_BP_INT' ] ) ;
}
else if ( timing _standard == 'Custom' ) {
// Read the timing from the UI
submitVar ( 'V_FP' , $ ( '#V_FP' ) . val ( ) ) ;
submitVar ( 'V_BP' , $ ( '#V_BP' ) . val ( ) ) ;
submitVar ( 'V_SW' , $ ( '#V_SW' ) . val ( ) ) ;
submitVar ( 'H_FP' , $ ( '#H_FP' ) . val ( ) ) ;
submitVar ( 'H_BP' , $ ( '#H_BP' ) . val ( ) ) ;
submitVar ( 'H_SW' , $ ( '#H_SW' ) . val ( ) ) ;
submitVar ( 'V_FP_INT' , Global _InputVars [ 'V_FP' ] + 0.5 ) ;
submitVar ( 'V_SW_INT' , Global _InputVars [ 'V_SW' ] ) ;
submitVar ( 'V_BP_INT' , Global _InputVars [ 'V_BP' ] + 0.5 ) ;
Timing = {
'V_FP' : Global _InputVars [ 'V_FP' ] ,
'V_BP' : Global _InputVars [ 'V_BP' ] ,
'V_SW' : Global _InputVars [ 'V_SW' ] ,
'H_FP' : Global _InputVars [ 'H_FP' ] ,
'H_BP' : Global _InputVars [ 'H_BP' ] ,
'H_SW' : Global _InputVars [ 'H_SW' ] ,
'V_FP_INT' : Global _InputVars [ 'V_FP_INT' ] ,
'V_BP_INT' : Global _InputVars [ 'V_BP_INT' ] ,
'V_SW_INT' : Global _InputVars [ 'V_SW_INT' ] ,
'V_BL' : Global _InputVars [ 'V_FP' ] + Global _InputVars [ 'V_BP' ] + Global _InputVars [ 'V_SW' ] ,
'H_BL' : Global _InputVars [ 'H_FP' ] + Global _InputVars [ 'H_BP' ] + Global _InputVars [ 'H_SW' ] ,
'V_EFF' : Global _InputVars [ 'VRES' ] + Global _InputVars [ 'V_FP' ] + Global _InputVars [ 'V_BP' ] + Global _InputVars [ 'V_SW' ] ,
'H_EFF' : Global _InputVars [ 'HRES' ] + Global _InputVars [ 'H_FP' ] + Global _InputVars [ 'H_BP' ] + Global _InputVars [ 'H_SW' ] ,
'F_ACTUAL' : Global _InputVars [ 'FREQ' ] ,
}
$ ( '#TIMING_FORMAT_NAME' ) . html ( '' ) ;
}
$ ( '#V_BLANK' ) . html ( Timing [ 'V_BL' ] ) ;
$ ( '#H_BLANK' ) . html ( Timing [ 'H_BL' ] ) ;
return Timing ;
}
function clearTiming ( ) {
submitVar ( 'V_FP' , '' ) ;
submitVar ( 'V_BP' , '' ) ;
submitVar ( 'V_SW' , '' ) ;
submitVar ( 'H_FP' , '' ) ;
submitVar ( 'H_BP' , '' ) ;
submitVar ( 'H_SW' , '' ) ;
submitVar ( 'V_FP_INT' , '' ) ;
submitVar ( 'V_SW_INT' , '' ) ;
submitVar ( 'V_BP_INT' , '' ) ;
return ;
}
function CVT _R ( R ) { // Variable R is an integer representing the reduced blanking revision to use, version 1 or version 2.
var H = Global _InputVars [ 'HRES' ] ; // Horizontal active pixels
var V = Global _InputVars [ 'VRES' ] ; // Vertical active pixels
var F = Global _InputVars [ 'FREQ' ] ; // Nominal vertical refresh frequency
var S = Global _InputVars [ 'SCAN' ] ; // 1 for progressive scan, 2 for interlaced
var M = Global _InputVars [ 'MARGINS' ] ; // Margins (%)
var I = ( S - 1 ) / 2 ; // 0 for progressive, 0.5 for interlaced
// Declaring variables for all results
var V _FP ; // Vertical front porch
var V _SW ; // Vertical sync width
var V _BP ; // Vertical back porch
var H _FP ; // Horizontal front porch
var H _SW ; // Horizontal sync width
var H _BP ; // Horizontal back porch
var V _BLANK ; // Total vertical blanking (V_FP + V_SW + V_BP)
var H _BLANK ; // Total horizontal blanking (H_FP + H_SW + H_BP)
var V _EFF ; // V + V_Blank + V_Margins
var H _EFF ; // H + H_Blank + H_Margins
var F _ACTUAL ; // Actual vertical refresh frequency (after pixel clock rounding)
var F _HOR ; // Horizontal refresh frequency
// Common constants
var V _PER _MIN = 0.00046 ; /* Minimum vertical blanking period for reduced blank timing (in seconds), defined by VESA CVT 1.2 standard */
var V _LINES = Math . floor ( V / S ) // If progressive scan, S = 1 and V_LINES = V. If interlaced, V_LINES = floor(V / 2).
if ( R == 1 ) {
// CVT-RB constants
H _BLANK = 160 ;
H _FP = 48 ;
H _BP = 80 ;
H _SW = 32 ;
V _FP = 3 ;
var V _BP _MIN = 6 ;
// All H timings are defined, as well as V_FP. Only V_SW and V_BP remain (and V_BLANK, the sum of all 3 V parameters)
// Determine vertical sync width (V_SW) from table of magic numbers defined in VESA CVT standard
var V _SYNC _TABLE = [
[ 4 / 3 , 4 , '3' ] ,
[ 16 / 9 , 5 , '9' ] ,
[ 8 / 5 , 6 , 'A' ] ,
[ 5 / 3 , 7 , '9' ] ,
[ 5 / 4 , 7 , '4' ] ,
]
var AR _NAME = '' ;
V _SW = 10 ; // default value defined in standard
for ( var i = 0 ; i < V _SYNC _TABLE . length ; i ++ ) {
if ( Math . abs ( ( H / V ) - V _SYNC _TABLE [ i ] [ 0 ] ) < 0.05 ) { // Check if aspect ratio of image (H/V) matches an aspect ratio defined in table, within 0.05
V _SW = V _SYNC _TABLE [ i ] [ 1 ] ;
AR _NAME = V _SYNC _TABLE [ i ] [ 2 ] ;
DEBUG ( 'AR_NAME' , AR _NAME )
break ;
}
}
// V_BP is determined in reverse, by calculating V_BLANK first (the sum of V_FP, V_SW, and V_BP) and subtracting out V_FP and V_SW.
var G = 8 ; // Cell granularity constant defined by CVT standard
var H _RND = Math . floor ( H / G ) * G ; // Round down horizontal resolution to be a multiple 8
if ( H _RND <= 0 ) { return false ; }
var V _MARGIN = Math . floor ( M / 100 ) * V _LINES ; // If margins percent (M) is 0, this result is 0
var H _MARGIN = Math . floor ( H _RND * M / 100 / G ) * G ; // If margins percent (M) is 0, this result is 0
var H _PER _EST = ( ( 1 / F ) - V _PER _MIN ) / ( V _LINES + ( 2 * V _MARGIN ) ) ; // Horizontal blanking period estimate
V _BLANK = Math . floor ( ( V _PER _MIN / H _PER _EST ) + 1 ) ;
var V _BLANK _MIN = V _FP + V _SW + V _BP _MIN ;
if ( V _BLANK < V _BLANK _MIN ) { V _BLANK = V _BLANK _MIN ; } // Enforce minimum value for V_blank
V _BP = V _BLANK - ( V _FP + V _SW ) ;
V _EFF = V _LINES + V _BLANK + V _MARGIN + I ; // (S-1)/2 = 0 for progressive, 0.5 for interlaced
H _EFF = H _RND + H _BLANK + H _MARGIN ;
// Calculate pixel clock, to enforce pixel clock rounding to the nearest 250 kHz, as required by the CVT standard
var CLK = F * ( V _EFF ) * ( H _EFF ) ; // Pixel clock (Hz)
CLK = Math . floor ( CLK / 250000 ) * 250000 ; // Pixel clock (Hz) rounded down to the next multiple of 0.25 MHz (250 kHz, 250000 Hz)
F _HOR = CLK / ( H _EFF ) ; // Horizontal refresh frequency (Hz)
F _ACTUAL = F _HOR / ( V _EFF ) ; // Pixel clock rounding is enforced via lowering the vertical refresh frequency to adjust pixel clock
}
else if ( R == 2 ) {
// CVT-R2 constants defined by CVT standard
H _BLANK = 80 ;
H _FP = 8 ;
H _BP = 40 ;
H _SW = 32 ;
V _BP = 6 ;
V _SW = 8 ;
var V _FP _MIN = 1 ;
// All parameters are defined as constant except V_FP
// V_FP is determined in reverse, by calculating V_BLANK first (the sum of V_FP, V_SW, and V_BP) and subtracting V_SW and V_BP out.
var V _MARGIN = Math . floor ( M / 100 ) * V _LINES ; // If margins percent (M) is 0, this result is 0
var H _MARGIN = Math . floor ( H * ( M / 100 ) ) ; // If margins percent (M) is 0, this result is 0
var H _PER _EST = ( ( 1 / F ) - V _PER _MIN ) / ( V _LINES + ( 2 * V _MARGIN ) ) ; // Horizontal blanking period estimate
V _BLANK = Math . floor ( ( V _PER _MIN / H _PER _EST ) + 1 ) ;
var V _BLANK _MIN = V _FP _MIN + V _SW + V _BP ;
if ( V _BLANK < V _BLANK _MIN ) { V _BLANK = V _BLANK _MIN ; } // Enforce minimum value for V_blank
V _FP = V _BLANK - ( V _BP + V _SW ) ;
V _EFF = V _LINES + V _BLANK + V _MARGIN + I ; // (S-1)/2 = 0 for progressive, 0.5 for interlaced
H _EFF = H + H _BLANK + H _MARGIN ;
// Calculate pixel clock, to enforce pixel clock rounding to the nearest 1 kHz, as required by the CVT standard
var CLK = F * ( V _EFF ) * ( H _EFF ) ; // Pixel clock (Hz)
CLK = Math . floor ( CLK / 1000 ) * 1000 ; // Pixel clock (Hz) rounded down to the next multiple of 0.001 MHz (1 kHz, 1000 Hz)
F _HOR = CLK / ( H _EFF ) ; // Horizontal refresh frequency (Hz)
F _ACTUAL = F _HOR / ( V _EFF ) ;
var V _SYNC _TABLE = [
[ 4 / 3 , 4 , '3' ] ,
[ 16 / 9 , 5 , '9' ] ,
[ 8 / 5 , 6 , 'A' ] ,
[ 5 / 3 , 7 , '9' ] ,
[ 5 / 4 , 7 , '4' ] ,
]
var AR _NAME = '' ;
for ( var i = 0 ; i < V _SYNC _TABLE . length ; i ++ ) {
if ( Math . abs ( ( H / V ) - V _SYNC _TABLE [ i ] [ 0 ] ) < 0.05 ) {
AR _NAME = V _SYNC _TABLE [ i ] [ 2 ] ;
}
}
}
//DEBUG('CLK', CLK);
//DEBUG('F_HOR', F_HOR);
//DEBUG('F_ACTUAL', F_ACTUAL);
//DEBUG(V_BLANK);
return {
'V_FP' : V _FP , // For interlaced, these vertical timing are used for the odd fields
'V_BP' : V _BP ,
'V_SW' : V _SW ,
'H_FP' : H _FP ,
'H_BP' : H _BP ,
'H_SW' : H _SW ,
'V_FP_INT' : V _FP + I , // For interlaced, V_FP and V_BP are 0.5 higher for even fields (V_SW is same)
'V_BP_INT' : V _BP + I ,
'V_SW_INT' : V _SW ,
'V_BL' : V _BLANK ,
'H_BL' : H _BLANK ,
'V_EFF' : V _EFF ,
'H_EFF' : H _EFF ,
'F_ACTUAL' : F _ACTUAL ,
'VESA_AR' : AR _NAME ,
} ;
}
function CVT ( ) {
var H = Global _InputVars [ 'HRES' ] ; // Horizontal active pixels
var V = Global _InputVars [ 'VRES' ] ; // Vertical active pixels
var F = Global _InputVars [ 'FREQ' ] ; // Nominal vertical refresh frequency
var S = Global _InputVars [ 'SCAN' ] ; // 1 for progressive scan, 2 for interlaced
var M = Global _InputVars [ 'MARGINS' ] ; // Margins (%)
var INTERLACE = ( S - 1 ) / 2 ;
// Declaring variables for all results
var V _FP ; // Vertical front porch
var V _SW ; // Vertical sync width
var V _BP ; // Vertical back porch
var H _FP ; // Horizontal front porch
var H _SW ; // Horizontal sync width
var H _BP ; // Horizontal back porch
var V _BLANK ; // Total vertical blanking (V_FP + V_SW + V_BP)
var H _BLANK ; // Total horizontal blanking (H_FP + H_SW + H_BP)
var V _EFF ; // V + V_Blank + V_Margins
var H _EFF ; // H + H_Blank + H_Margins
var F _ACTUAL ; // Actual vertical refresh frequency (after pixel clock rounding)
var F _HOR ; // Horizontal refresh frequency
// Constants
var V _SBP _MIN = 0.00055 ; /* Minimum duration of vertical sync + back porch (seconds) */
var V _BP _MIN = 6 ; // Minimum vertical back porch value (lines)
var V _LINES = Math . floor ( V / S ) // If progressive scan, S = 1 and V_LINES = V. If interlaced, V_LINES = floor(V / 2).
V _FP = 3 ; // Vertical front porch value (lines)
var G = 8 ; // Cell Granularity constant
var H _RND = Math . floor ( H / G ) * G ;
if ( H _RND <= 0 ) { return false ; }
var V _MARGIN = Math . floor ( M / 100 * V _LINES ) ; // If margins percent (M) is 0, this result is 0
var H _MARGIN = Math . floor ( H _RND * M / 100 / G ) * G ; // If margins percent (M) is 0, this result is 0
var H _SYNC _TARGET _WIDTH = 0.08 // Nominal horizontal sync pulse duration (percent of horizontal draw period)
// Determine V_SW from table
var V _SYNC _TABLE = [
[ 4 / 3 , 4 , '3' ] ,
[ 16 / 9 , 5 , '9' ] ,
[ 8 / 5 , 6 , 'A' ] ,
[ 5 / 3 , 7 , '9' ] ,
[ 5 / 4 , 7 , '4' ] ,
]
var AR _NAME = '' ;
V _SW = 10 ; // default value defined in standard
for ( var i = 0 ; i < V _SYNC _TABLE . length ; i ++ ) {
if ( Math . abs ( ( H / V ) - V _SYNC _TABLE [ i ] [ 0 ] ) < 0.05 ) { // Check if aspect ratio of image (H/V) matches an aspect ratio defined in table, within 0.05
V _SW = V _SYNC _TABLE [ i ] [ 1 ] ;
AR _NAME = V _SYNC _TABLE [ i ] [ 2 ] ;
}
}
// Estimate horizontal refresh period (seconds)
var H _EST = ( ( 1 / F ) - V _SBP _MIN ) / ( V _LINES + ( 2 * V _MARGIN ) + V _FP + INTERLACE )
// Estimate vertical sync + vertical back porch (lines), subtract V_SW to get V_BP
var V _BP = ( Math . floor ( V _SBP _MIN / H _EST ) + 1 ) - V _SW ;
if ( V _BP < V _BP _MIN ) { V _BP = V _BP _MIN ; } // Enforce minimum value for V_BP
// Total vertical resolution including blanking and margins
V _EFF = V _LINES + ( 2 * V _MARGIN ) + V _FP + V _SW + V _BP + INTERLACE ;
// Horizontal blanking is determined by formula from GTF standard
// Calculate Ideal Duty Cycle (%) from GTF formula
var IDC = 30 - ( 300000 * H _EST ) ;
if ( IDC < 20 ) { IDC = 20 ; } // Enforce minimum value for IDC
// Calculate horizontal blanking time (to next lowest character cell)
H _BLANK = Math . floor ( ( H _RND + ( 2 * H _MARGIN ) ) * IDC / ( 100 - IDC ) / ( 2 * G ) ) * ( 2 * G ) ;
// Total horizontal resolution including blanking and margins
H _EFF = H _RND + ( 2 * H _MARGIN ) + H _BLANK ;
// Determing horizontal timing parameters from magic formulas defined by standard
H _BP = H _BLANK / 2 ;
H _SW = Math . floor ( ( H _SYNC _TARGET _WIDTH * H _EFF ) / G ) * G ;
H _FP = H _BLANK - ( H _BP + H _SW ) ;
// Calculate Pixel Clock (Hz)
var CLK = H _EFF / H _EST ;
CLK = Math . floor ( CLK / 250000 ) * 250000 ; // Enforce pixel clock rounding to nearest 0.25 MHz (250,000 Hz)
// Calculate Horizontal Refresh Frequency (Hz)
F _HOR = CLK / H _EFF ;
// Calculate Vertical Refresh Frequency (Hz) after adjusting for pixel clock rounding
F _ACTUAL = F _HOR / V _EFF ;
return {
'V_FP' : V _FP , // For interlaced, these vertical timing are used for the odd fields
'V_BP' : V _BP ,
'V_SW' : V _SW ,
'H_FP' : H _FP ,
'H_BP' : H _BP ,
'H_SW' : H _SW ,
'V_FP_INT' : V _FP + INTERLACE , // For interlaced, V_FP and V_BP are 0.5 higher for even fields (V_SW is same)
'V_BP_INT' : V _BP + INTERLACE ,
'V_SW_INT' : V _SW ,
'V_BL' : V _BLANK ,
'H_BL' : H _BLANK ,
'V_EFF' : V _EFF ,
'H_EFF' : H _EFF ,
'F_ACTUAL' : F _ACTUAL ,
'VESA_AR' : AR _NAME ,
} ;
}
function CTA ( ) {
DEBUG ( 'Starting CTA' ) ;
var H = Global _InputVars [ 'HRES' ] ;
var V = Global _InputVars [ 'VRES' ] ;
var F = Global _InputVars [ 'FREQ' ] ;
var S = Global _InputVars [ 'SCAN' ] ;
// No CTA formats are below these points, no need to search entire list
if ( H < 640 || V < 240 || F < 23.9 ) { DEBUG ( 'Search aborted, one or more inputs is below the minimum value found in CTA.' , H , V , F ) ; return false ; }
if ( S == 1 ) { S = 'p' ; }
else if ( S == 2 ) { S = 'i' ; }
DEBUG ( 'Input:' , H , V , F , S ) ;
var CTA _H ;
var CTA _V ;
var CTA _F ;
var CTA _S ;
for ( var i = 0 ; i < CTA861 . length ; i ++ ) {
CTA _H = parseFloat ( CTA861 [ i ] [ 'H' ] ) ;
CTA _V = parseFloat ( CTA861 [ i ] [ 'V' ] ) ;
CTA _F = parseFloat ( CTA861 [ i ] [ 'V_FREQ' ] ) ;
CTA _S = CTA861 [ i ] [ 'SCAN' ] ;
DEBUG ( 'Parsing: VIC' , CTA861 [ i ] [ 'VIC' ] , '|' , CTA _H , ( H == CTA _H ) , '|' , CTA _V , ( V == CTA _V ) , '|' , ( CTA _F ) . toFixed ( 3 ) , ( Math . abs ( F - CTA _F ) < 0.01 ) , '|' , CTA _S , ( S == CTA _S ) ) ;
//DEBUG( (V == CTA_V), (Math.abs(F - CTA_F) < 0.01), (S == CTA_S))
if ( ( H == CTA _H ) && ( V == CTA _V ) && ( Math . abs ( F - CTA _F ) < 0.01 ) && ( S == CTA _S ) ) {
DEBUG ( 'Match Found' ) ;
// Special modifications to values based on whether interlacing is selected or not
if ( S == 'p' ) { S = 0 ; }
else if ( S == 'i' ) { S = 0.5 ; }
return {
'V_FP' : parseFloat ( CTA861 [ i ] [ 'V_FP' ] ) ,
'V_BP' : parseFloat ( CTA861 [ i ] [ 'V_BP' ] ) ,
'V_SW' : parseFloat ( CTA861 [ i ] [ 'V_SW' ] ) ,
'H_FP' : parseFloat ( CTA861 [ i ] [ 'H_FP' ] ) ,
'H_BP' : parseFloat ( CTA861 [ i ] [ 'H_BP' ] ) ,
'H_SW' : parseFloat ( CTA861 [ i ] [ 'H_SW' ] ) ,
'V_FP_INT' : parseFloat ( CTA861 [ i ] [ 'V_FP' ] ) + S ,
'V_BP_INT' : parseFloat ( CTA861 [ i ] [ 'V_BP' ] ) + S ,
'V_SW_INT' : parseFloat ( CTA861 [ i ] [ 'V_SW' ] ) ,
'V_BL' : parseFloat ( CTA861 [ i ] [ 'V_BLANK' ] ) - S ,
'H_BL' : parseFloat ( CTA861 [ i ] [ 'H_BLANK' ] ) ,
'V_EFF' : parseFloat ( CTA861 [ i ] [ 'V_EFF' ] ) * ( 1 - S ) ,
'H_EFF' : parseFloat ( CTA861 [ i ] [ 'H_EFF' ] ) ,
'F_ACTUAL' : parseFloat ( CTA861 [ i ] [ 'V_FREQ' ] ) ,
'VIC' : parseFloat ( CTA861 [ i ] [ 'VIC' ] ) ,
'CTA_REV' : CTA861 [ i ] [ 'CTA' ] ,
}
}
}
// Not found in CTA list
return false ;
}
function GTF ( ) {
// Input Variables
var V _FREQ _NOM = Global _InputVars [ 'FREQ' ] ;
var H = Global _InputVars [ 'HRES' ] ;
var V = Global _InputVars [ 'VRES' ] ;
var S = Global _InputVars [ 'SCAN' ] ;
var MARGINS = Global _InputVars [ 'MARGINS' ] ;
// Constants
var V _SW = 3 ; // Vertical sync pulse width (lines)
var V _FP = 1 ; // Vertical front porch (lines)
var V _MIN = 0.00055 ; // Min V_Blank period (seconds)
var G = 8 ; // Cell granularity (pixels)
var H _SYNC _WIDTH _TARGET = 0.08 ; // Nominal horizontal sync pulse duration (percent of horizontal draw period)
var INTERLACE = ( S - 1 ) / 2 ; // 0 for progressive, 0.5 for interlaced
// var m = 600 // Gradient (%/kHz)
// var c = 40 // offset (%)
// var k = 128 // blanking time scaling factor
// var j = 20 // scaling factor weighting
var M = 300 // m * (k / 256); // "M prime"
var C = 30 // (((c - j) * k) / 256) + j; // "C prime"
// Result Variables
var V _BP ;
var H _FP ;
var H _SW ;
var H _BP ;
var H _EFF
var V _EFF ;
var V _BLANK ;
var H _BLANK ;
// Calculations
var V _LINES = Math . round ( V / S ) ;
var V _MARGIN = Math . round ( ( MARGINS / 100 ) * V _LINES ) ;
var H _EST = ( ( 1 / V _FREQ _NOM ) - V _MIN ) / ( V _LINES + ( 2 * V _MARGIN ) + V _FP + INTERLACE ) ; // Horizontal refresh period estimate (seconds)
V _BP = Math . round ( V _MIN / H _EST ) - V _SW ;
V _BLANK = V _FP + V _SW + V _BP ;
V _EFF = V _LINES + V _BLANK + ( 2 * V _MARGIN ) + INTERLACE ; // Total lines
//var V_FREQ_EST = 1 / (H_EST * V_EFF); // Hz
//var H_PER = (H_EST * V_FREQ_EST) / V_FREQ_NOM
var H _PER = 1 / ( V _EFF * V _FREQ _NOM ) ; // Actual horizontal refresh period (seconds)
//var V_FREQ_ACT = 1 / (H_PER * V_EFF); // Hz
var IDC = C - ( M * H _PER * 1000 ) ;
DEBUG ( 'IDC:' , IDC ) ;
var H _MARGIN = Math . round ( ( H * ( MARGINS / 100 ) ) / G ) * G ;
H _BLANK = Math . round ( ( ( ( H + ( 2 * H _MARGIN ) ) * IDC ) / ( 100 - IDC ) ) / ( 2 * G ) ) * ( 2 * G ) ;
H _EFF = ( H + H _BLANK + ( 2 * H _MARGIN ) ) ;
H _SW = Math . round ( ( H _EFF * H _SYNC _WIDTH _TARGET ) / G ) * G ;
H _BP = ( H _BLANK / 2 ) ;
H _FP = H _BP - H _SW ;
//var CLK = H_EFF / H_PER;
//var H_FREQ = 1 / H_PER;
return {
'V_FP' : V _FP ,
'V_BP' : V _BP ,
'V_SW' : V _SW ,
'H_FP' : H _FP ,
'H_BP' : H _BP ,
'H_SW' : H _SW ,
'V_FP_INT' : V _FP + INTERLACE ,
'V_BP_INT' : V _BP + INTERLACE ,
'V_SW_INT' : V _SW ,
'H_BLANK' : H _BLANK ,
'V_BLANK' : V _BLANK ,
'H_EFF' : H _EFF ,
'V_EFF' : V _EFF ,
'F_ACTUAL' : V _FREQ _NOM ,
} ;
}
function DMT ( ) {
DEBUG ( 'Starting DMT Search' ) ;
var H = Global _InputVars [ 'HRES' ] ;
var V = Global _InputVars [ 'VRES' ] ;
var F = Global _InputVars [ 'FREQ' ] ;
var S = Global _InputVars [ 'SCAN' ] ;
// No DMT formats are below these points, no need to search entire list
if ( H < 640 || V < 350 || F < 43 ) { DEBUG ( 'Search aborted, one or more inputs is below the minimum value found in DMT.' , H , V , F ) ; return false ; }
if ( S == 1 ) { S = 'p' ; }
else if ( S == 2 ) { S = 'i' ; }
DEBUG ( 'Input:' , H , V , F , S ) ;
var DMT _H ;
var DMT _V ;
var DMT _F ;
var DMT _S ;
for ( var i = 0 ; i < DMT _List . length ; i ++ ) {
DMT _H = parseFloat ( DMT _List [ i ] [ 'H' ] ) ;
DMT _V = parseFloat ( DMT _List [ i ] [ 'V' ] ) ;
DMT _F = parseFloat ( DMT _List [ i ] [ 'NOM_FREQ' ] ) ;
DMT _F _ACTUAL = parseFloat ( DMT _List [ i ] [ 'V_FREQ' ] )
DMT _S = DMT _List [ i ] [ 'SCAN' ] ;
DEBUG ( 'Parsing: DMT ID' , DMT _List [ i ] [ 'ID' ] , '|' , DMT _H , ( H == DMT _H ) , '|' , DMT _V , ( V == DMT _V ) , '|' , ( DMT _F ) . toFixed ( 3 ) , ( Math . abs ( F - DMT _F ) < 0.01 ) , '|' , DMT _S , ( S == DMT _S ) ) ;
//DEBUG( (V == DMT_V), (Math.abs(F - DMT_F) < 0.01), (S == DMT_S))
if ( ( H == DMT _H ) && ( V == DMT _V ) && ( ( F == DMT _F ) || ( Math . abs ( F - DMT _F _ACTUAL ) < 0.01 ) ) && ( S == DMT _S ) ) {
DEBUG ( 'Match Found' ) ;
// Special modifications to values based on whether interlacing is selected or not
if ( S == 'p' ) { S = 0 ; }
else if ( S == 'i' ) { S = 0.5 ; }
var Timing ;
if ( DMT _List [ i ] [ 'STD' ] == 'CVT' ) {
Timing = CVT ( ) ;
Timing [ 'ID' ] = DMT _List [ i ] [ 'ID' ] ;
}
else if ( DMT _List [ i ] [ 'STD' ] == 'CVTRB' ) {
Timing = CVT _R ( 1 ) ;
Timing [ 'ID' ] = DMT _List [ i ] [ 'ID' ] ;
}
else if ( DMT _List [ i ] [ 'STD' ] == 'CVTR2' ) {
Timing = CVT _R ( 2 ) ;
Timing [ 'ID' ] = DMT _List [ i ] [ 'ID' ] ;
}
else {
Timing = {
'V_FP' : parseFloat ( DMT _List [ i ] [ 'V_FP' ] ) ,
'V_BP' : parseFloat ( DMT _List [ i ] [ 'V_BP' ] ) ,
'V_SW' : parseFloat ( DMT _List [ i ] [ 'V_SW' ] ) ,
'H_FP' : parseFloat ( DMT _List [ i ] [ 'H_FP' ] ) ,
'H_BP' : parseFloat ( DMT _List [ i ] [ 'H_BP' ] ) ,
'H_SW' : parseFloat ( DMT _List [ i ] [ 'H_SW' ] ) ,
'V_FP_INT' : parseFloat ( DMT _List [ i ] [ 'V_FP' ] ) + S ,
'V_BP_INT' : parseFloat ( DMT _List [ i ] [ 'V_BP' ] ) + S ,
'V_SW_INT' : parseFloat ( DMT _List [ i ] [ 'V_SW' ] ) ,
'V_BL' : parseFloat ( DMT _List [ i ] [ 'V_BLANK' ] ) - S ,
'H_BL' : parseFloat ( DMT _List [ i ] [ 'H_BLANK' ] ) ,
'V_EFF' : parseFloat ( DMT _List [ i ] [ 'V_EFF' ] ) * ( 1 - S ) ,
'H_EFF' : parseFloat ( DMT _List [ i ] [ 'H_EFF' ] ) ,
'F_ACTUAL' : parseFloat ( DMT _List [ i ] [ 'V_FREQ' ] ) ,
'ID' : parseFloat ( DMT _List [ i ] [ 'ID' ] ) ,
}
}
return Timing ;
}
}
// Not found in DMT list
return false ;
}
function updateDisplay ( ) {
var cells ;
var id ;
id _list = [ 'data_rate' , '8b10b' , '16b18b' , 'pixel_rate' , 'pixel_rate_active' ] ;
for ( var x = 0 ; x < id _list . length ; x ++ ) {
id = id _list [ x ] ;
cells = $ ( '#results_' + id ) . children ( ) ;
DEBUG ( 'Detailed Results:' , Detailed _Results [ id ] ) ;
DEBUG ( 'Cells:' , cells )
cells [ 1 ] . innerHTML = Detailed _Results [ id ] [ 'val' ] ;
cells [ 2 ] . innerHTML = Detailed _Results [ id ] [ 'unit' ] ;
}
id _list = [ 'active_px' , 'blank_px' , 'total_px' ] ;
for ( var x = 0 ; x < id _list . length ; x ++ ) {
id = id _list [ x ] ;
cells = $ ( '#results_' + id ) . children ( ) ;
DEBUG ( 'Detailed Results:' , Detailed _Results [ id ] ) ;
DEBUG ( 'Cells:' , cells )
cells [ 1 ] . innerHTML = Detailed _Results [ id ] [ 'h' ] ;
cells [ 2 ] . innerHTML = Detailed _Results [ id ] [ 'v' ] ;
cells [ 3 ] . innerHTML = Detailed _Results [ id ] [ 't' ] [ 'val' ] ;
cells [ 4 ] . innerHTML = Detailed _Results [ id ] [ 't' ] [ 'unit' ] ;
}
id = 'overhead_px' ;
cells = $ ( '#results_' + id ) . children ( ) ;
DEBUG ( 'Detailed Results:' , Detailed _Results [ id ] ) ;
DEBUG ( 'Cells:' , cells )
cells [ 1 ] . innerHTML = Detailed _Results [ id ] [ 'h' ] [ 'val' ] ;
cells [ 2 ] . innerHTML = Detailed _Results [ id ] [ 'v' ] [ 'val' ] ;
cells [ 3 ] . innerHTML = Detailed _Results [ id ] [ 't' ] [ 'val' ] ;
cells [ 4 ] . innerHTML = Detailed _Results [ id ] [ 't' ] [ 'unit' ] ;
id _list = [ 'bpc' , 'bpp' , 'palette' ] ;
for ( var x = 0 ; x < id _list . length ; x ++ ) {
id = id _list [ x ] ;
cells = $ ( '#results_' + id ) . children ( ) ;
DEBUG ( 'Detailed Results:' , Detailed _Results [ id ] ) ;
DEBUG ( 'Cells:' , cells )
cells [ 1 ] . innerHTML = Detailed _Results [ id ] [ 'val' ] ;
cells [ 2 ] . innerHTML = Detailed _Results [ id ] [ 'unit' ] ;
}
id = 'px_format' ;
cells = $ ( '#results_' + id ) . children ( ) ;
DEBUG ( 'Detailed Results:' , Detailed _Results [ id ] ) ;
DEBUG ( 'Cells:' , cells )
cells [ 1 ] . innerHTML = Detailed _Results [ id ]
id = 'scan' ;
cells = $ ( '#results_' + id ) . children ( ) ;
DEBUG ( 'Detailed Results:' , Detailed _Results [ id ] ) ;
DEBUG ( 'Cells:' , cells )
cells [ 1 ] . innerHTML = Detailed _Results [ id ]
id _list = [ 'v_freq' , 'v_freq_actual' , 'v_freq_dev' , 'v_freq_dev_perc' , 'v_per' , 'v_per_actual' , 'v_per_dev' , 'v_per_dev_perc' ] ;
for ( var x = 0 ; x < id _list . length ; x ++ ) {
id = id _list [ x ] ;
cells = $ ( '#results_' + id ) . children ( ) ;
DEBUG ( 'Detailed Results:' , Detailed _Results [ id ] ) ;
DEBUG ( 'Cells:' , cells )
cells [ 1 ] . innerHTML = Detailed _Results [ id ] [ 'val' ] ;
cells [ 2 ] . innerHTML = Detailed _Results [ id ] [ 'unit' ] ;
}
id _list = [ 'h_freq' , 'h_per' ] ;
for ( var x = 0 ; x < id _list . length ; x ++ ) {
id = id _list [ x ] ;
cells = $ ( '#results_' + id ) . children ( ) ;
DEBUG ( 'Detailed Results:' , Detailed _Results [ id ] ) ;
DEBUG ( 'Cells:' , cells )
cells [ 1 ] . innerHTML = Detailed _Results [ id ] [ 'val' ] ;
cells [ 2 ] . innerHTML = Detailed _Results [ id ] [ 'unit' ] ;
}
return ;
}
function clearResults ( ) {
return ;
}
function timingUIChange ( ) {
// Controls the enabled/disabled state of the custom timing format input fields
var timing _params = [
$ ( '#V_FP' ) ,
$ ( '#V_BP' ) ,
$ ( '#V_SW' ) ,
$ ( '#H_FP' ) ,
$ ( '#H_BP' ) ,
$ ( '#H_SW' ) ,
$ ( '#V_FP_INT' ) ,
$ ( '#V_BP_INT' ) ,
$ ( '#V_SW_INT' ) ,
] ;
value = $ ( '#TIMING_DROP' ) . val ( ) ;
if ( value == 'Custom' ) {
for ( var i = 0 ; i < timing _params . length ; i ++ ) {
param = timing _params [ i ] ;
param . prop ( 'disabled' , false ) ;
//if (field.prop('oldvalue') != '') {
// field.val(field.prop('oldvalue'));
//}
}
}
else {
for ( var i = 0 ; i < timing _params . length ; i ++ ) {
param = timing _params [ i ] ;
param . prop ( 'disabled' , true ) ;
//field.prop('oldvalue', field.val());
//field.val('');
}
}
value = $ ( 'input[name=SCAN_SLCT]:checked' ) . val ( ) ;
if ( value == 'i' ) {
$ ( '#V_BLANK_INT_LABEL' ) . css ( 'display' , 'table-cell' ) ;
$ ( '#V_FP_INT_CONTAINER' ) . css ( 'display' , 'table-cell' ) ;
$ ( '#V_BP_INT_CONTAINER' ) . css ( 'display' , 'table-cell' ) ;
$ ( '#V_SW_INT_CONTAINER' ) . css ( 'display' , 'table-cell' ) ;
$ ( '#V_BLANK_INT_CONTAINER' ) . css ( 'display' , 'table-cell' ) ;
$ ( '#V_BLANK_EVEN_LABEL' ) . html ( '(Even) V<sub>blank</sub>' ) ;
}
else if ( value == 'p' ) {
$ ( '#V_BLANK_INT_LABEL' ) . css ( 'display' , 'none' ) ;
$ ( '#V_FP_INT_CONTAINER' ) . css ( 'display' , 'none' ) ;
$ ( '#V_BP_INT_CONTAINER' ) . css ( 'display' , 'none' ) ;
$ ( '#V_SW_INT_CONTAINER' ) . css ( 'display' , 'none' ) ;
$ ( '#V_BLANK_INT_CONTAINER' ) . css ( 'display' , 'none' ) ;
$ ( '#V_BLANK_EVEN_LABEL' ) . html ( 'V<sub>blank</sub>' ) ;
}
else {
DEBUG ( 'Something somewhere has gone terribly wrong. Attemped to grab SCAN_SLCT value, and it was neither "p" nor "i"!' ) ;
}
}
function colordepthUIChange ( ) {
// Controls the enabled/disabled state of the custom timing format input fields
var field = $ ( '#CUSTOM_COLOR_DEPTH' ) ;
value = $ ( 'input[name=COLOR_DEPTH_SLCT]:checked' ) . val ( ) ;
if ( value == 'Custom' ) {
field . prop ( 'disabled' , false ) ;
$ ( 'input[name=CD_UNIT_SLCT]' ) . prop ( 'disabled' , false ) ;
}
else {
field . prop ( 'disabled' , true ) ;
$ ( 'input[name=CD_UNIT_SLCT]' ) . prop ( 'disabled' , true ) ;
}
}
function marginsUIChange ( ) {
// Controls the enabled/disabled state of the custom timing format input fields
var field = $ ( '#CUSTOM_MARGINS' ) ;
value = $ ( 'input[name=MARGINS_SLCT]:checked' ) . val ( ) ;
if ( value == 'y' ) {
field . prop ( 'disabled' , false ) ;
if ( field . val ( ) == '' ) {
field . val ( '1.8' ) ;
}
}
else {
field . prop ( 'disabled' , true ) ;
}
}
function LoadCTA861 ( ) {
// Loads the timing definitions for the CTA-861 standard from a txt file
//DEBUG('CTA Test 11');
var request = new XMLHttpRequest ( ) ;
request . open ( 'GET' , 'CTA861.txt' , true ) ;
request . send ( null ) ;
request . onreadystatechange = function ( ) {
DEBUG ( 'request.status:' , request . status )
if ( request . readyState === 4 && ( request . status === 200 || request . status === 0 ) ) {
CTA861 = $ . csv . toObjects ( request . responseText ) ;
//DEBUG(CTA861);
}
}
DEBUG ( 'Finished' ) ;
}
function LoadDMT ( ) {
// Loads the timing definitions for the DMT standard from a txt file
DEBUG ( 'DMT Test 1' ) ;
var request = new XMLHttpRequest ( ) ;
request . open ( 'GET' , 'DMT.txt' , true ) ;
request . send ( null ) ;
request . onreadystatechange = function ( ) {
DEBUG ( 'request.status:' , request . status )
if ( request . readyState === 4 && ( request . status === 200 || request . status === 0 ) ) {
DMT _List = $ . csv . toObjects ( request . responseText ) ;
//DEBUG(CTA861);
}
}
DEBUG ( 'Finished' ) ;
}
//Small functions
{
function Commas ( num ) {
var parts = num . toString ( ) . split ( "." ) ;
parts [ 0 ] = parts [ 0 ] . replace ( /\B(?=(\d{3})+(?!\d))/g , "," ) ;
return parts . join ( "." ) ;
}
function getPrecision ( x , watchdog ) {
// https://stackoverflow.com/questions/27082377/get-number-of-decimal-places-with-javascript
x = Math . abs ( x ) ;
watchdog = watchdog || 32 ;
var i = 0 ;
while ( x % 1 > 0 && i < watchdog ) {
i ++ ;
x = x * 10 ;
}
return i ;
}
function GCD ( a , b ) {
a = Math . abs ( a ) ;
b = Math . abs ( b ) ;
if ( b > a ) { var temp = a ; a = b ; b = temp ; }
while ( true ) {
if ( b == 0 ) return a ;
a %= b ;
if ( a == 0 ) return b ;
b %= a ;
}
}
function SameRatio ( H , V , A ) {
/* Checks if the ratio H/V is equal to the given ratio A (within a defined margin of error E) */
/* Negative signs on H, V, and A are ignored */
var E = 0.001 ; /* E is a percent error written as a decimal (i.e. E = 0.001 would give an acceptable error margin of 0.1%) */
if ( Math . abs ( ( Math . abs ( H / V ) / Math . abs ( A ) ) - 1 ) <= E ) { return true ; }
else { return false ; }
}
/ *
function parseNum ( val ) {
// Converts string to floating point if it has a decimal point, or integer if there is no decimal point. Also strips commas and spaces, and optionally applies absolute value.
if ( typeof val === "string" ) {
// val = val.replace(/[^0-9\. ]/g, ''); // Apply absolute value and ignore non-numeric characters
// val = val.replace(/[^0-9\. -]/g, ''); // Allow negative numbers and ignore non-numeric characters
//val = val.replace(/-/g, ''); // Remove minus signs
// Return NaN if...
if ( val == '' // input is blank
|| val . indexOf ( '.' ) != val . lastIndexOf ( '.' ) // input contains multiple decimal places
|| val . indexOf ( '-' ) != val . lastIndexOf ( '-' ) // input contains multiple minus signs
|| ( val . indexOf ( '-' ) != - 1 && val . indexOf ( '-' ) != 0 ) // input contains a minus sign in a position other than the first character
|| val . match ( /[^0-9.-]/g ) ) // input contains any character other than a number, decimal, minus, or space
{
return NaN ;
}
else {
// Once we have checked that the input contains no characters other than numerals, periods, and minus signs
// And that there are at most one period and one minus sign, and both are in valid positions, we can evaluate the number as either float or string.
// If for some reason either of them fail, it will still return NaN anyway
if ( val . indexOf ( '.' ) == - 1 )
return parseInt ( val ) ;
else {
return parseFloat ( val ) ;
}
}
}
else if ( Number . isNaN ( val ) ) {
return NaN ; // Check if val is literally 'NaN'
}
else if ( typeof val === "number" ) {
return val ; // NaN is recognized as a number, so this line must be after NaN is handled
}
else {
return NaN ;
}
} * /
function parseNum ( val ) {
// This function is designed to interpret strings with formatted numbers (which may contain currencies, digit grouping commas, units, etc.)
// It will return NaN if it cannot be interpreted as a valid number (i.e. no numeric characters, multiple periods or minus signs, etc.)
if ( typeof ( val ) === 'number' ) {
// If the input argument is already a number, then nothing needs to be done, simply return the input value
if ( Number . isNaN ( val ) == true ) {
// However, we do need to check that it isn't NaN, because that is identified as a number.
return NaN ;
}
else {
return val ;
}
}
else if ( typeof val === 'string' ) {
// Empty string is interpreted as 0
if ( val == '' ) { return 0 ; }
// First, remove all non-numeric characters on the outsides of the string
for ( var i = 0 ; i < val . length ; i ++ ) {
if ( ! ( i < val . length ) ) { break ; }
//DEBUG('i:', i, 'val:', val, 'val[i]:', val[i]);
// Loop through each character starting from the front
if ( ( /[^0-9.-]/g ) . test ( val [ i ] ) == true ) {
// If character is not a number, period, or minus sign, remove it
if ( i == 0 && val . length > 1 ) { val = val . slice ( 1 ) ; }
else if ( i == val . length - 1 ) { return NaN ; } // If this is the last character in the string, then there are no digits in the string; return NaN
else if ( i > 0 ) { val = ( val . slice ( 0 , i ) ) + ( val . slice ( i + 1 ) ) ; }
i = i - 1 ; // Since a character has been removed, the next character is now at the same index
continue ;
}
else if ( ( /[-]/g ) . test ( val [ i ] ) == true ) {
// If character is a negative sign, continue searching without deleting it. This is because there may still be non-number characters between the negative sign and the first digit, such as "-$1.00". The negative sign should stay but the dollar needs to be removed.
continue ;
}
else if ( ( /[.]/g ) . test ( val [ i ] ) == true ) {
// If character is a period, then following character MUST be a digit, unless it's the end of the number.
if ( i + 1 < val . length ) {
if ( ( /[0-9]/g ) . test ( val [ i + 1 ] ) == true ) {
// If the character after the period is a digit, then the first digit has been reached
break ;
}
else {
// If the string contained a period followed by a non-numeric character, it is not a number
return NaN ;
}
}
else {
// If i+1 was not < val.length, then the period is the last character in the string, which implicitly means the string contains no numeric characters.
return NaN ;
}
}
else if ( ( /[0-9]/g ) . test ( val [ i ] ) == true ) {
// If character was a numeric character, we have successfully stripped any leading characters and reached the start of the number.
break ;
}
}
// Now do a similar procedure starting from the backside, to strip any trailing characters (such as units of measurement)
for ( var i = ( val . length - 1 ) ; i >= 0 ; i -- ) {
if ( ( /[^0-9]/g ) . test ( val [ i ] ) == true ) {
// No need to modify iterator for this direction
// Since we are dealing with the end of the number, minus signs are no longer part of the number. Periods at the end are valid, but superfluous
// Since we are only checking the characters after the digits have ended, minus signs are not invalid, as they may be part of a unit of measurement. Therefore, they are simply removed, rather than returning NaN.
if ( val . length == 1 ) { return NaN ; }
else { val = val . slice ( 0 , i ) ; }
continue ;
}
else if ( ( /[0-9]/g ) . test ( val [ i ] ) == true ) {
// If character is a numeric character, we have reached the back end of the number and successfully stripped any trailing characters.
break ;
}
}
// We now strip any commas and whitespace throughout the string
val = val . replace ( /[, ]/g , '' ) ;
// If, after removing leading and trailing units, whitespace, and commas, there are any non-numeric characters (i.e. in the middle of the string after the numbers start), it is not a valid number
if ( ( /[^0-9.-]/g ) . test ( val ) == true ) {
return NaN ;
}
// Now that the string only contains numeric characters, minus signs, and periods, we must check if there are any invalid usages of the periods and signs, such as multiple periods/signs, or a minus sign anywhere other than the first character.
if ( val == '' // string is empty
|| val . indexOf ( '.' ) != val . lastIndexOf ( '.' ) // string contains multiple decimal point
|| val . indexOf ( '-' ) != val . lastIndexOf ( '-' ) // string contains multiple minus signs
|| ( val . indexOf ( '-' ) != - 1 && val . indexOf ( '-' ) != 0 ) ) // input contains a minus sign and it isn't the first character
{
return NaN ;
}
// Finished; string now only contains numbers, up to one period, and up to one minus sign as the first character of the string.
// If for some reason the parseFloat fails, the function will return NaN, so the output is still consistent with any other failed condition.
return parseFloat ( val ) ;
}
}
function isNum ( num ) {
// Returns false if input is not a number, including a blank string or NaN
// Can accept arrays, and returns true only if all elements would return true individually
if ( Array . isArray ( num ) == true ) {
for ( a = 0 ; a < num . length ; a ++ ) {
if ( Number . isNaN ( parseFloat ( num [ a ] ) ) == true ) {
return false ;
}
return true ;
}
}
else {
return ! Number . isNaN ( parseFloat ( num ) ) ;
}
}
function isPositive ( num ) {
if ( Array . isArray ( num ) == true ) {
for ( a = 0 ; a < num . length ; a ++ ) {
if ( Number . isNaN ( parseNum ( num [ a ] ) ) == true )
return false ;
else if ( num [ a ] <= 0 )
return false ;
}
return true ;
}
else {
if ( Number . isNaN ( parseNum ( num ) ) == true )
return false ;
else if ( num > 0 )
return true ;
else {
return false ;
}
}
}
function isPositiveZ ( num ) {
// Returns true if input is positive or zero. Can recognize formatted numbers (i.e. "1,234,567 Gbit/s" or "-$1,234 USD") as allowed by parseNum
// Combine with isNum() to allow only true (non-formatted) numbers and strings (i.e. if (isNum(x) && isPositiveZ(x))
/ *
True :
isPositiveZ ( 1 )
isPositiveZ ( '1' )
isPositiveZ ( 1.1 )
isPositiveZ ( '1.1' )
isPositiveZ ( '1.' ) Number string with stray decimal
isPositiveZ ( 0 ) or ( '0' )
isPositiveZ ( Infinity )
isPositiveZ ( [ 1 , '2' , 3.3 ] ) true iff all elements are non - negative
False :
isPositiveZ ( - 1 )
isPositiveZ ( '-1' )
isPositiveZ ( - 1.1 )
isPositiveZ ( '-1.1' )
isPositiveZ ( '1 ' ) Number with whitespace
isPositiveZ ( '' ) Empty String
isPositiveZ ( 'abc' )
isPositiveZ ( NaN )
isPositiveZ ( [ - 1 , '2' , 3.3 ] ) If any element is negative
* /
if ( Array . isArray ( num ) == true ) {
for ( a = 0 ; a < num . length ; a ++ ) {
if ( Number . isNaN ( parseNum ( num [ a ] ) ) == true )
return false ;
else if ( num [ a ] < 0 )
return false ;
}
return true ;
}
else {
if ( Number . isNaN ( parseNum ( num ) ) == true )
return false ;
else if ( num >= 0 )
return true ;
else {
return false ;
}
}
}
function isInt ( num ) {
/ *
True :
isInt ( 1 )
isInt ( '1' )
isInt ( - 1 )
isInt ( '-1' )
isInt ( 0 )
isInt ( [ 1 , - 2 , '3' ] )
isInt ( 1 , 'a' ) - > true ( be careful to enter multiple arguments as an array , otherwise it will only evaluate the first argument , as seen here )
False :
isInt ( 1.1 )
isInt ( '1 ' )
isInt ( '1 2' )
isInt ( 'abc' )
isInt ( 'abc123' )
isInt ( '' )
isInt ( NaN )
isInt ( Infinity )
isInt ( [ 1 , 2 , 3.3 ] ) Returns false if any of the array elements are not an integer
* /
if ( Array . isArray ( num ) == true ) {
for ( a = 0 ; a < num . length ; a ++ ) {
if ( Number . isInteger ( parseNum ( num [ a ] ) ) == false ) {
return false ;
}
}
return true ;
}
else {
num = parseNum ( num ) ;
return Number . isInteger ( num ) ;
}
}
function isFloat ( num ) {
/ *
True :
isFloat ( 1.1 )
isFloat ( '1.1' )
isFloat ( - 1.1 )
isFloat ( '-1.1' )
isFloat ( '.1' )
isFloat ( '-.1' )
isFloat ( [ 1.1 , - 1.2 , '1.3' ] )
isFloat ( Infinity )
isFloat ( [ 1.1 , 'a' ] ) - > true ( be careful to enter multiple arguments as an array , otherwise it will only evaluate the first argument , as seen here )
False :
isFloat ( 1.0 )
isFloat ( '1.0' )
isFloat ( 0 )
isFloat ( 1 )
isFloat ( '1.1.1' )
isFloat ( '' )
isFloat ( 'a' )
isFloat ( '1.1a' )
isFloat ( [ 1.1 , 1.2 , 3 ] )
isFloat ( NaN )
* /
if ( Array . isArray ( num ) == true ) {
for ( a = 0 ; a < num . length ; a ++ ) {
num [ a ] = parseNum ( num [ a ] ) ;
if ( Number . isInteger ( num [ a ] ) == true || Number . isNaN ( num [ a ] ) == true ) {
return false ;
}
}
return true ;
}
else {
num = parseNum ( num ) ;
return ! ( Number . isInteger ( num ) || Number . isNaN ( num ) ) ;
}
}
}
window . onpageshow = function ( ) {
DEBUG ( 'On Page Show function executing...' )
generate _table ( 'Interface Support' , - 1 ) ;
LoadCTA861 ( ) ;
LoadDMT ( ) ;
DEBUG ( 'Initializing HRES' )
$ ( '#INPUT_HRES' ) [ 0 ] . onchange ( ) ;
DEBUG ( 'Initializing VRES' )
$ ( '#INPUT_VRES' ) [ 0 ] . onchange ( ) ;
DEBUG ( 'Initializing FREQ' )
$ ( '#INPUT_F' ) [ 0 ] . onchange ( ) ;
DEBUG ( 'Initializing COLOR DEPTH' )
$ ( '#COLOR_DEPTH_FORM' ) [ 0 ] . onchange ( ) ;
DEBUG ( 'Initializing PIXEL FORMAT' )
$ ( '#PIXEL_FORMAT_FORM' ) [ 0 ] . onchange ( ) ;
DEBUG ( 'Initializing COMPRESSION' )
$ ( '#COMPRESSION_FORM' ) [ 0 ] . onchange ( ) ;
DEBUG ( 'Initializing SCAN' )
$ ( '#SCAN_FORM' ) [ 0 ] . onchange ( ) ;
DEBUG ( 'Initializing MARGINS' )
$ ( '#MARGINS_FORM' ) [ 0 ] . onchange ( ) ;
DEBUG ( 'Initializing TIMING STANDARD' )
$ ( '#TIMING_DROP' ) [ 0 ] . onchange ( ) ;
$ ( '#V_FP' ) [ 0 ] . onchange ( ) ;
$ ( '#V_BP' ) [ 0 ] . onchange ( ) ;
$ ( '#V_SW' ) [ 0 ] . onchange ( ) ;
$ ( '#H_FP' ) [ 0 ] . onchange ( ) ;
$ ( '#H_BP' ) [ 0 ] . onchange ( ) ;
$ ( '#H_SW' ) [ 0 ] . onchange ( ) ;
$ ( '#V_FP_INT' ) [ 0 ] . onchange ( ) ;
$ ( '#V_BP_INT' ) [ 0 ] . onchange ( ) ;
$ ( '#V_SW_INT' ) [ 0 ] . onchange ( ) ;
//calcMain();
}
//window.onload = window.onpageshow;