Documentation ¶
Overview ¶
Package television implements the output device of the emulated VCS.
It is important to note that the Television type does not render pixels or mix sound. Instead, the television interface exposes two functions, AddPixelRenderer() and AddAudioMixer(). These can be used to add as many renderers and mixers as required.
For audio outputs that are time sensitive, the AddRealtimeAudioMixer() function should be used. This requires a slightly different implementation (see RealtimeAudioMixer interface) and only one such implemenation can be registered at any one time.
There is also the FrameTrigger and PauseTrigger interfaces for applications that have limited need for a full pixel renderer.
The main means of communication is the Signal() function. This function accepts an instance of SignalAttributes which gives details of how the television should be behaving.
The implementation also handles framerate limiting according to the current incoming TV signal. For debugging purposes, the framerate can also be set to a specific value
Frame sizing is also handled by the television package. Current information about the frame can be acquired with GetFrameInfo(). FrameInfo will also be sent to the PixelRenderers as appropriate.
Simple Television ¶
For backwards compatability and for applications that want simplified graphical output, a so-called 'simple television' can be created with the NewTelevisionSimple() function.
(I considered implemented the simple television as an entirely separate type and to introduce a Television interface at the VCS level. However, this seemed too disruptive at first flush and for relatively little gain)
The simple television does not have frame sizing but for the applications that are expected to require the simple television, it is not thought these features are required.
The VSYNC implementation in the 'simple television is very forgiving and will cause no screen roll.
Concurrency ¶
None of the functions in the Television type are safe to be called from goroutines other than the one the type was created in.
Logging ¶
The television does no logging. This is because the television can be used ephemerally and logging would be noisy. Callers of television package functions should decide whether it is appropriate to log.
Struct Embedding ¶
It is possible for instances of television to be embedded in other type structure, thereby extending the "features" of the television and allowing the extended type to be used wherever the Television interface is required. The digest package is a good example of this idea.ckage television
Compatability with Stella ¶
Note that the television implementation no longer attempts to report the same frame/scanline/clock information as Stella. Early versions of the implementation did because it facilitated A/B testing but since we're now confident that the TIA emulation is correct the need to keep in "sync" with Stella is no longer required.
Index ¶
- Variables
- type Adj
- type AudioMixer
- type Debugger
- type FrameInfo
- func (info FrameInfo) Crop() image.Rectangle
- func (info FrameInfo) IsAtariSafe() bool
- func (info FrameInfo) IsDifferent(cmp FrameInfo) bool
- func (info FrameInfo) OverscanClocks() int
- func (info FrameInfo) ScreenClocks() int
- func (info FrameInfo) String() string
- func (info FrameInfo) TotalClocks() int
- func (info FrameInfo) VBLANKClocks() int
- type FrameTrigger
- type HaltCondition
- type PauseTrigger
- type PixelRenderer
- type PixelRendererFPSCap
- type PixelRendererRotation
- type RealtimeAudioMixer
- type Resizer
- type ScanlineTrigger
- type State
- type Television
- func (tv *Television) AddAudioMixer(m AudioMixer)
- func (tv *Television) AddDebugger(dbg Debugger)
- func (tv *Television) AddFrameTrigger(f FrameTrigger)
- func (tv *Television) AddPixelRenderer(r PixelRenderer)
- func (tv *Television) AddRealtimeAudioMixer(m RealtimeAudioMixer)
- func (tv *Television) AddScanlineTrigger(f ScanlineTrigger)
- func (tv *Television) AdjCoords(adj Adj, amount int) coords.TelevisionCoords
- func (tv *Television) AttachVCS(env *environment.Environment, vcs VCS)
- func (tv *Television) End() error
- func (tv *Television) GetActualFPS() (float32, float32)
- func (tv *Television) GetCoords() coords.TelevisionCoords
- func (tv *Television) GetCreationSpecID() string
- func (tv *Television) GetFrameInfo() FrameInfo
- func (tv *Television) GetLastSignal() signal.SignalAttributes
- func (tv *Television) GetReqFPS() float32
- func (tv *Television) GetReqSpecID() string
- func (tv *Television) GetResizer() Resizer
- func (tv *Television) GetSpecID() string
- func (tv *Television) IsFrameNum(frame int) bool
- func (tv *Television) NudgeFPSCap(frames int)
- func (tv *Television) Plumb(vcs VCS, state *State)
- func (tv *Television) RemoveAudioMixer(m AudioMixer)
- func (tv *Television) RemoveFrameTrigger(f FrameTrigger)
- func (tv *Television) RemovePixelRenderer(r PixelRenderer)
- func (tv *Television) RemoveRealtimeAudioMixer()
- func (tv *Television) RemoveScanlineTrigger(f ScanlineTrigger)
- func (tv *Television) Reset(keepFrameNum bool) error
- func (tv *Television) SetEmulationState(state govern.State) error
- func (tv *Television) SetFPS(fps float32)
- func (tv *Television) SetFPSCap(limit bool) bool
- func (tv *Television) SetResizer(rz Resizer)
- func (tv *Television) SetRotation(rotation specification.Rotation)
- func (tv *Television) SetSpec(spec string, forced bool) error
- func (tv *Television) Signal(sig signal.SignalAttributes)
- func (tv *Television) Snapshot() *State
- func (tv *Television) String() string
- type VCS
Constants ¶
This section is empty.
Variables ¶
var HaltVBLANKChanged = errors.New("VBLANK bounds change")
var HaltVSYNCAbsent = errors.New("VSYNC absent")
var HaltVSYNCScanlineCount = errors.New("VSYNC scanline count change")
var HaltVSYNCScanlineStart = errors.New("VSYNC start scanline change")
var HaltVSYNCTooShort = errors.New("VSYNC signal too short")
list of HaltCondition values
Functions ¶
This section is empty.
Types ¶
type Adj ¶ added in v0.15.0
type Adj int
Adj is used to specify adjustment scale for the ReqAdjust() function.
type AudioMixer ¶
type AudioMixer interface { // for efficiency reasons, SetAudio() implementations can be sent // SignalAttributes values that do not have valid AudioData (ie. // AudioUpdate bit is zero). implemenations should therefore take care when // processing the sig slice // // the general algorithm for processing the sig slice is: // // for _, s := range sig { // if s&signal.AudioUpdate != signal.AudioUpdate { // continue // } // d := uint8((s & signal.AudioData) >> signal.AudioDataShift) // // ... // } SetAudio(sig []signal.SignalAttributes) error // some mixers may need to conclude and/or dispose of resources gently. // for simplicity, the AudioMixer should be considered unusable after // EndMixing() has been called EndMixing() error // Reset buffered audio and anything else that might need doing on, for // example, a cartridge change Reset() }
AudioMixer implementations work with sound; most probably playing it. An example of an AudioMixer that does not play sound but otherwise works with it is the digest.Audio type
type Debugger ¶ added in v0.33.0
type Debugger interface {
HaltFromTelevision(HaltCondition)
}
Interface to a developer helper that can cause the emulation to halt on various television related conditions
type FrameInfo ¶ added in v0.14.0
type FrameInfo struct { // a copy of the television Spec that is considered to be in action. All // fields with the exception of ID, Colors and HorizontalScanRate may have // been superceded by values in the FrameInfo field. But they are good to // have for reference Spec specification.Spec // FrameNum can be used to distinguish one FrameInfo instance from another FrameNum int // the top and bottom scanlines that are to be present visually to the // player. this is generally related to the state of VBLANK but in the case // of screens when the VBLANK is never set, the visible area is determined by // the extent of non-black output // // consumers of FrameInfo should use these values rather than deriving that // information from VBLANK // // see the Crop() function for the preferred way of using these values to // create the a rectangle of the visible screen area. in particular, note // how the VisibleBottom value is treated in that context VisibleTop int VisibleBottom int // the number of scanlines considered to be in the frame TotalScanlines int // the top/bottom bounds of VBLANK. this is *not* the same as VisibleTop and // VisbleBottom, which takes into account ideal screen sizing and // situations where VBLANK is never set VBLANKtop int VBLANKbottom int // VBLANKatari is true if VBLANK top/bottom are equal to the values // suggested by Atari VBLANKatari bool // the refresh rate. this value is derived from the number of scanlines // and is really a short-cut for: // // Spec.HorizontalScanRate / TotalScanlines RefreshRate float32 // has the TotalScanline field, and the RefreshRate field, changed since the // previous frame Jitter bool // whether the TV frame was begun as a result of a valid VSYNC signal FromVSYNC bool // VSYNCscanline is the scanline on which the VSYNC signal starts. not valid // if FromVSYNC is false VSYNCscanline int VSYNCcount int // IsSynced indicates that the television is synchronised with the incoming // VSYNC signal and is not rolling. this is different to FromVSYNC which // simply tells us that this current frame was started as a result of a // VSYNC signal (ie. the television might not yet have recorvered from a // desynchronisation) IsSynced bool // Stable is true once the television frame has been consistent for N // frames after reset. This is useful for pixel renderers that don't want // to show the loose frames that often occur after VCS hard-reset. // // once Stable is true then the Specification will not change (except // manually). This is important for ROMs that allow the VCS to run without // VSYNC - we don't want those ROMs to change the specifciation after he // startup period. A good example of such a ROM is Andrew Davie's 3e+ chess // demos. Stable bool // if the profile of the VSYNC signal has changed after the Stable flag has // been set then VSYNCunstable will be true VSYNCunstable bool // if the profile of the VBLANK bounds has changed after the Stable flag has // been set then VBLANKunstable will be true VBLANKunstable bool }
FrameInfo records the current frame information, as opposed to the optimal values of the specification.
func NewFrameInfo ¶ added in v0.14.0
func NewFrameInfo(spec specification.Spec) FrameInfo
NewFrameInfo returns an initialised FrameInfo for the specification.
func (FrameInfo) Crop ¶ added in v0.29.0
Crop returns an image.Rectangle for the cropped region of the screen. Using this is preferrable than using the VisibleTop/Bottom fields to construct the rectangle
If the VisibleTop/Bottom fields are used in preference to this function for whatever reason, bear in mind that the VisibleBottom field should be adjusted by +1 in order to include the all visible scanlines in the rectangle
To prove the need for this, consider what would happen if the screen was one scanline tall. In that case both the top and bottom values would be the same:
r := image.Rect(0, 10, 100, 10)
The height of this rectangle will be zero, as shown by the Size() function
isZero := r.Size().Y == 0
func (FrameInfo) IsAtariSafe ¶ added in v0.14.0
IsAtariSafe returns true if the current frame matches the AtariSafe values of the current specification.
func (FrameInfo) IsDifferent ¶ added in v0.29.0
IsDifferent returns true if any of the pertinent display information is different between the two copies of FrameInfo
func (FrameInfo) OverscanClocks ¶ added in v0.19.3
OverscanClocks returns the number of clocks in the Overscan portion of the frame.
func (FrameInfo) ScreenClocks ¶ added in v0.19.3
ScreenClocks returns the number of clocks in the visible portion of the frame.
func (FrameInfo) TotalClocks ¶ added in v0.18.0
TotalClocks returns the total number of clocks required to generate the frame. The value returned assumes scanlines are complete - which may not be the case.
func (FrameInfo) VBLANKClocks ¶ added in v0.19.3
VBLANKClocks returns the number of clocks in the VBLANK portion of the frame.
type FrameTrigger ¶
FrameTrigger implementations listen for NewFrame events. FrameTrigger is a subset of PixelRenderer
type HaltCondition ¶ added in v0.33.0
type HaltCondition error
HaltCondition is used to tell Debugger about the halt conditions
type PauseTrigger ¶ added in v0.10.1
FrameTrigger implementations listen for Pause events
type PixelRenderer ¶
type PixelRenderer interface { // NewFrame is called at the start of a new frame // // Renderers should be prepared to resize the rendering display to either a // smaller or larger frame size. Renderers should also expect NewFrame to be // called multiple times but not necesssarily with NewScanline() or // SetPixels() being called NewFrame(FrameInfo) error // NewScanline is called at the start of a new scanline NewScanline(scanline int) error // SetPixels is used to Render a series of signals. The number of signals // will always be television.MaxSignalHistory // // Producing a 2d image from the signals sent by SetPixels() can easily be // done by first allocating a bitmap of width specification.ClksScanline // and height specification.AbsoluateMaxScanlines. This bitmap will have // television.MaxSignalHistory entries // // Every signal from SetPixels() therefore corresponds to a pixel in the // bitmap - the first entry always referes to the top-left pixel // // If the entry contains signal.NoSignal then that screen pixel has not been // written to recently. However, the bitmap may still need to be updated // with "nil" information if the size of the screen has reduced // // For renderers that are producing an accurate visual image, the pixel // should always be set to video black if VBLANK is on. Some renderers // however may find it useful to set the pixel to the RGB value regardless // of VBLANK // // A very important note is that some ROMs use VBLANK to control pixel // color within the visible display area. For example: // // * Custer's Revenge // * Ladybug // * ET (turns VBLANK off late on scanline 40) // // In other words, the PixelRenderer should not simply assume VBLANK is // restricted to the "off-screen" areas as defined by the FrameInfo sent to // Resize() SetPixels(sig []signal.SignalAttributes, last int) error // Reset all pixels. Called when TV is reset. // // Note that a Reset event does not imply a Resize() event. Implementations // should not call the Resize() function as a byproduct of a Reset(). The // television will send an explicit Resize() request if it is appropriate Reset() // Some renderers may need to conclude and/or dispose of resources gently EndRendering() error }
PixelRenderer implementations displays, or otherwise works with, visual information from a television. For example digest.Video
PixelRenderer implementations often find it convenient to maintain a reference to the parent Television implementation and maybe even embed the Television interface. ie.
type ExampleTV struct { television.Television ... }
The most useful source of information though is the FrameInfo type supplied to the PixelRenderer through the Resize() and NewFrame() functions. A current copy of this information is also available from the television type GetFrameInfo() function
type PixelRendererFPSCap ¶ added in v0.23.0
type PixelRendererFPSCap interface {
SetFPSCap(limit bool)
}
PixelRendererFPSCap is an extension to the PixelRenderer interface. Pixel renderers that implement this interface will be notified when the television's frame capping policy is changed. Not all pixel renderers need to worry about frame rate.
type PixelRendererRotation ¶ added in v0.26.0
type PixelRendererRotation interface {
SetRotation(specification.Rotation)
}
PixelRendererRotation is an extension to the PixelRenderer interface. Pixel renderes that implement this interface can show the television image in a rotated aspect. Not all pixel renderers need to worry about rotation.
type RealtimeAudioMixer ¶ added in v0.15.0
type RealtimeAudioMixer interface { AudioMixer MoreAudio() bool }
RealtimeAudioMixer is an extension for the AudioMixer interface. Implementations of this interface expect to be given more audio data on demand
MoreAudio() is called periodically (every scanline) and the implementation should return true if more audio data is required immediately
type Resizer ¶ added in v0.32.0
type Resizer struct {
// contains filtered or unexported fields
}
Resizer handles the expansion of the visible area of the TV screen
ROMs used to test resizing:
* good base cases
- Pitfall
- Hero
* frame that needs to be resized after startup period
- Hack Em Hanglyman (pre-release)
* the occasional unsynced frame
- Hack Em Hanglyman (pre-release)
* lots of unsynced frames (during computer "thinking" period)
- Andrew Davies' Chess
* does not set VBLANK for pixels that are clearly not meant to be seen these ROMs rely on the SafeTop and SafeBottom values being correct
- Communist Mutants From Space
- Tapper
- Spike's Peak
* ROMs that do not set VBLANK *at all*. in these cases the commit() function uses the black top/bottom values rather than vblank top/bottom values.
- Hack Em Hanglyman (release and pre-release)
- Legacy of the Beast
*ROMs that *do* set VBLANK but might be caught by the black top/bottom rule if usingVBLANK was incorrectly set
- aTaRSI (demo)
- Supercharger "rewind tape" screen
* bottom of screen needs careful consideration
- Ladybug
- Man Goes Down
finally, the following conditions are worth documenting as being important:
* PAL ROMs without VSYNC cannot be sized or changed to the correct spec automatically
- Nightstalker
type ScanlineTrigger ¶ added in v0.19.3
ScanlineTrigger implementations listen for NewScanline events. It is a subset of PixelRenderer
type State ¶
type State struct {
// contains filtered or unexported fields
}
State encapsulates the television values that can change from moment to moment. Used by the rewind system when recording the current television state.
func (*State) GetCoords ¶ added in v0.15.0
func (s *State) GetCoords() coords.TelevisionCoords
GetCoords returns an instance of coords.TelevisionCoords.
func (*State) GetFrameInfo ¶ added in v0.25.0
GetFrameInfo returns the television's current frame information.
func (*State) GetLastSignal ¶ added in v0.25.0
func (s *State) GetLastSignal() signal.SignalAttributes
GetLastSignal returns a copy of the most SignalAttributes sent to the TV (via the Signal() function).
func (*State) GetReqSpecID ¶ added in v0.32.0
GetReqSpecID returns the specification that was most recently requested
func (*State) SetReqSpec ¶ added in v0.32.0
SetReqSpec sets the requested specification ID
type Television ¶
type Television struct {
// contains filtered or unexported fields
}
Television is a Television implementation of the Television interface. In all honesty, it's most likely the only implementation required.
func NewTelevision ¶
func NewTelevision(spec string) (*Television, error)
NewTelevision creates a new instance of the television type, satisfying the Television interface.
func (*Television) AddAudioMixer ¶
func (tv *Television) AddAudioMixer(m AudioMixer)
AddAudioMixer adds an implementation of AudioMixer.
func (*Television) AddDebugger ¶ added in v0.33.0
func (tv *Television) AddDebugger(dbg Debugger)
AddDebuuger adds an implementation of Debugger.
func (*Television) AddFrameTrigger ¶
func (tv *Television) AddFrameTrigger(f FrameTrigger)
AddFrameTrigger adds an implementation of FrameTrigger.
func (*Television) AddPixelRenderer ¶
func (tv *Television) AddPixelRenderer(r PixelRenderer)
AddPixelRenderer adds an implementation of PixelRenderer.
func (*Television) AddRealtimeAudioMixer ¶ added in v0.15.0
func (tv *Television) AddRealtimeAudioMixer(m RealtimeAudioMixer)
AddRealtimeAudioMixer adds a RealtimeAudioMixer. Any previous assignment is lost.
func (*Television) AddScanlineTrigger ¶ added in v0.19.3
func (tv *Television) AddScanlineTrigger(f ScanlineTrigger)
AddScanlineTrigger adds an implementation of ScanlineTrigger.
func (*Television) AdjCoords ¶ added in v0.15.0
func (tv *Television) AdjCoords(adj Adj, amount int) coords.TelevisionCoords
AdjCoords returns a coords.TelevisionCoords with the current coords adjusted by the specified amount.
func (*Television) AttachVCS ¶ added in v0.8.0
func (tv *Television) AttachVCS(env *environment.Environment, vcs VCS)
AttachVCS attaches an implementation of the VCSReturnChannel.
func (*Television) End ¶
func (tv *Television) End() error
some televisions may need to conclude and/or dispose of resources gently. implementations of End() should call EndRendering() and EndMixing() on each PixelRenderer and AudioMixer that has been added.
for simplicity, the Television should be considered unusable after EndRendering() has been called.
func (*Television) GetActualFPS ¶
func (tv *Television) GetActualFPS() (float32, float32)
GetActualFPS returns the current number of frames per second and the detected frequency of the TV signal.
Note that FPS measurement still works even when frame capping is disabled.
IS goroutine safe.
func (*Television) GetCoords ¶ added in v0.15.0
func (tv *Television) GetCoords() coords.TelevisionCoords
GetCoords returns an instance of coords.TelevisionCoords.
Like all Television functions this function is not safe to call from goroutines other than the one that created the Television.
func (*Television) GetCreationSpecID ¶ added in v0.32.0
func (tv *Television) GetCreationSpecID() string
GetCreationSpecID returns the specification that was requested on creation.
func (*Television) GetFrameInfo ¶ added in v0.14.0
func (tv *Television) GetFrameInfo() FrameInfo
GetFrameInfo returns the television's current frame information.
func (*Television) GetLastSignal ¶
func (tv *Television) GetLastSignal() signal.SignalAttributes
GetLastSignal returns a copy of the most SignalAttributes sent to the TV (via the Signal() function).
func (*Television) GetReqFPS ¶
func (tv *Television) GetReqFPS() float32
GetReqFPS returns the requested number of frames per second. Compare with GetActualFPS() to check for accuracy.
IS goroutine safe.
func (*Television) GetReqSpecID ¶
func (tv *Television) GetReqSpecID() string
GetReqSpecID returns the specification that was most recently requested.
func (*Television) GetResizer ¶ added in v0.32.0
func (tv *Television) GetResizer() Resizer
GetResizer returns a copy of the television resizer in it's current state.
func (*Television) GetSpecID ¶ added in v0.26.0
func (tv *Television) GetSpecID() string
GetSpecID returns the current specification.
func (*Television) IsFrameNum ¶ added in v0.35.0
func (tv *Television) IsFrameNum(frame int) bool
func (*Television) NudgeFPSCap ¶ added in v0.23.0
func (tv *Television) NudgeFPSCap(frames int)
NudgeFPSCap stops the FPS limiter for the specified number of frames. A value of zero (or less) will stop any existing nudge
func (*Television) Plumb ¶
func (tv *Television) Plumb(vcs VCS, state *State)
Plumb attaches an existing television state.
func (*Television) RemoveAudioMixer ¶ added in v0.16.0
func (tv *Television) RemoveAudioMixer(m AudioMixer)
RemoveAudioMixer removes a single AudioMixer implementation from the list of mixers. Order is not maintained.
func (*Television) RemoveFrameTrigger ¶ added in v0.16.0
func (tv *Television) RemoveFrameTrigger(f FrameTrigger)
RemoveFrameTrigger removes a single FrameTrigger implementation from the list of triggers. Order is not maintained.
func (*Television) RemovePixelRenderer ¶ added in v0.16.0
func (tv *Television) RemovePixelRenderer(r PixelRenderer)
RemovePixelRenderer removes a single PixelRenderer implementation from the list of renderers. Order is not maintained.
func (*Television) RemoveRealtimeAudioMixer ¶ added in v0.16.0
func (tv *Television) RemoveRealtimeAudioMixer()
RemoveRealtimeAudioMixer removes any RealtimeAudioMixer implementation from the Television.
func (*Television) RemoveScanlineTrigger ¶ added in v0.19.3
func (tv *Television) RemoveScanlineTrigger(f ScanlineTrigger)
RemoveScanlineTrigger removes a single ScanlineTrigger implementation from the list of triggers. Order is not maintained.
func (*Television) Reset ¶
func (tv *Television) Reset(keepFrameNum bool) error
Reset the television to an initial state.
func (*Television) SetEmulationState ¶ added in v0.15.0
func (tv *Television) SetEmulationState(state govern.State) error
SetEmulationState is called by emulation whenever state changes. How we handle incoming signals depends on the current state.
func (*Television) SetFPS ¶
func (tv *Television) SetFPS(fps float32)
SetFPS requests the number frames per second. This overrides the frame rate of the specification. A negative value restores frame rate to the ideal value (the frequency of the incoming signal).
func (*Television) SetFPSCap ¶
func (tv *Television) SetFPSCap(limit bool) bool
SetFPSCap whether the emulation should wait for FPS limiter. Returns the setting as it was previously.
func (*Television) SetResizer ¶ added in v0.32.0
func (tv *Television) SetResizer(rz Resizer)
SetResizer sets the state of the television resizer and sets the current frame info accordingly.
Note that the Resizer type does not include specification information. When transferring state between television instances it is okay to call SetSpec() but it should be done before SetResizer() is called
func (*Television) SetRotation ¶ added in v0.26.0
func (tv *Television) SetRotation(rotation specification.Rotation)
SetRotation instructs the television to a different orientation. In truth, the television just forwards the request to the pixel renderers.
func (*Television) SetSpec ¶
func (tv *Television) SetSpec(spec string, forced bool) error
SetSpec sets the television's specification if the creation ID is AUTO. This means that the television specification on creation overrides all other specifcation requests
The forced argument overrides this rule.
func (*Television) Signal ¶
func (tv *Television) Signal(sig signal.SignalAttributes)
Signal updates the current state of the television.
func (*Television) Snapshot ¶
func (tv *Television) Snapshot() *State
Snapshot makes a copy of the television state.
func (*Television) String ¶
func (tv *Television) String() string
type VCS ¶ added in v0.35.2
type VCS interface {
SetClockSpeed(specification.Spec)
}
VCS is used to send information from the TV back to the parent console
Source Files ¶
Directories ¶
Path | Synopsis |
---|---|
Package coords represents and can work with television coorindates
|
Package coords represents and can work with television coorindates |
Package limiter controls the refresh rate and the frame limiter for the television.
|
Package limiter controls the refresh rate and the frame limiter for the television. |
Package signal exposes the interface between the VCS and the television implementation.
|
Package signal exposes the interface between the VCS and the television implementation. |
Package specification contains the definitions, including colour, of the PAL and NTSC television protocols supported by the emulation.
|
Package specification contains the definitions, including colour, of the PAL and NTSC television protocols supported by the emulation. |