329 lines
14 KiB
C++
329 lines
14 KiB
C++
/*
|
|
* ldp.h
|
|
*
|
|
* Copyright (C) 2001 Matt Ownby
|
|
*
|
|
* This file is part of DAPHNE, a laserdisc arcade game emulator
|
|
*
|
|
* DAPHNE is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* DAPHNE is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
#ifndef LDP_PRE_H
|
|
#define LDP_PRE_H
|
|
|
|
// different states that the laserdisc player could be in
|
|
enum
|
|
{
|
|
LDP_ERROR, LDP_SEARCHING, LDP_STOPPED, LDP_PLAYING, LDP_PAUSED
|
|
};
|
|
|
|
// different non-blocking search results
|
|
enum
|
|
{
|
|
SEARCH_FAIL, // search failed
|
|
SEARCH_SUCCESS, // search succeeded
|
|
SEARCH_BUSY // search is still taking place, no change yet, my frenid
|
|
};
|
|
|
|
#include <SDL.h> // needed for datatypes
|
|
|
|
// for bug logging
|
|
#include <string>
|
|
#include <list>
|
|
|
|
using namespace std;
|
|
|
|
#ifdef WIN32
|
|
#pragma warning (disable:4786) // disable warning about truncating to 255 in debug info
|
|
#endif
|
|
|
|
#define FRAME_SIZE 7 // rdg2010
|
|
|
|
// the size to make your frame array (the frame + the NULL terminator)
|
|
#define FRAME_ARRAY_SIZE FRAME_SIZE + 1
|
|
|
|
class ldp
|
|
{
|
|
public:
|
|
ldp();
|
|
virtual ~ldp();
|
|
|
|
// Call this function to initialize the ldp (the constructor does _not_ call it).
|
|
// It's safe to call this function mulitple times.
|
|
bool pre_init();
|
|
|
|
// player-specific init stuff
|
|
// NOTE : this function should not be called directly, call pre_init instead
|
|
virtual bool init_player();
|
|
|
|
// Call this function to shutdown the ldp (the destructor also calls it).
|
|
// It's safe to call this function multiple times.
|
|
void pre_shutdown();
|
|
|
|
// player-specific shutdown stuff
|
|
// NOTE : this function should not be called directly, call pre_shutdown instead
|
|
virtual void shutdown_player();
|
|
|
|
void clear(); // clears any received frames
|
|
|
|
// searches to the 5-digit ASCII frame specified by 'pszFrame'
|
|
// if 'block_until_search_finished' is true, this function will return after the search has completed and will return
|
|
// true if the search was successful or false on error.
|
|
// if 'block_until_search_finished' is false, this function will return after the search has _begun_ and will return true
|
|
// if the player is currently executing the search or false if there was an error
|
|
// Call this instead of calling the search function directly!
|
|
// WARNING : if 'block_until_search_finished' is false, then the calling function
|
|
// MUST also call get_status() to determine when a seek has finished.
|
|
// If you aren't prepared to do this, make 'block_until_search_finished' true.
|
|
bool pre_search(const char *, bool block_until_search_finished);
|
|
|
|
// does the actual search. This func returns once the search has begun and you need to call get_search_result
|
|
// until the search isn't busy anymore.
|
|
// This function returns true if the LDP acknowledged the search
|
|
virtual bool nonblocking_search(char *);
|
|
|
|
// do not call this function directly! (get get_status instead)
|
|
// This is the LDP-specific function that checks to see if a search (issued previously) finished
|
|
// it returns one of the SEARCH_* enumerations ...
|
|
virtual int get_search_result();
|
|
|
|
bool pre_skip_forward(Uint32);
|
|
bool pre_skip_backward(Uint32);
|
|
|
|
// steps 1 frame forward
|
|
void pre_step_forward();
|
|
|
|
// steps 1 frame backward
|
|
void pre_step_backward();
|
|
|
|
virtual bool skip_forward(Uint32 frames_to_skip, Uint32 target_frame);
|
|
// NOTE : frames_to_skip and target_frame are both included for your convenience
|
|
// use frames_to_skip only if you cannot use target_frame (which is more accurate)
|
|
|
|
virtual bool skip_backward(Uint32 frames_to_skip, Uint32 target_frame);
|
|
// NOTE : frames_to_skip and target_frame are both included for your convenience
|
|
// use frames_to_skip only if you cannot use target_frame (which is more accurate)
|
|
|
|
void pre_play();
|
|
void pre_pause();
|
|
void pre_stop();
|
|
|
|
// Function all 'ldp-in' drivers should call to change the playback speed
|
|
// Input is a fraction (numerator/denominator) to avoid using a floating point value,
|
|
// which doesn't work well on the GP2X.
|
|
// Common speeds are 1X (1/1), 2X (2/1), 3X (3/1), 4X (4/1), 8X (8/1),
|
|
// 1/2X (1/2), 1/3X (1/3), 1/4X (1/4), 1/8X (1/8)
|
|
// Any weird speeds such as 7/2 have undefined behavior for now.
|
|
// Returns true if the speed has changed or false if the speed cannot be changed
|
|
bool pre_change_speed(unsigned int uNumerator, unsigned int uDenominator);
|
|
|
|
// LASERDISC-PLAYER-SPECIFIC IMPLEMENTATIONS OF VARIOUS FUNCTIONALITY
|
|
virtual unsigned int play();
|
|
virtual void pause();
|
|
virtual void stop();
|
|
|
|
// Implementation-specific version of pre_change_speed
|
|
// Returns true if the speed has changed or false if the speed cannot be changed
|
|
virtual bool change_speed(unsigned int uNumerator, unsigned int uDenominator);
|
|
|
|
// function that can replace make_delay when no cpu is present and thinking is required
|
|
void think_delay(unsigned int);
|
|
|
|
// When emulating a cpu, this function MUST be called EVERY 1 ms (according to cpu's reckoning) to keep us in sync w/ the cpu.
|
|
// This allows the cpu to do all timing calculations, which saves us from redundantly doing them again.
|
|
// (when not emulating a cpu, this function can be called less often, every frame for example, and we will do the calculations ourselves)
|
|
// This function updates the current frame so you cannot rely on get_current_frame to know when to call this function!!!
|
|
void pre_think();
|
|
|
|
// pre_think() calls think() for ldp-specific stuff
|
|
virtual void think();
|
|
|
|
// returns the current frame number that the disc is on
|
|
// this is a generic function which computes the current frame number using the elapsed time
|
|
// and the framerate of the disc. Obviously querying the laserdisc player would be preferable
|
|
// if possible (some laserdisc players don't like to be queried too often)
|
|
// SEEKING NOTES:
|
|
// if get_current_frames() is called during a NON-BLOCKING seek,
|
|
// it returns the frame the LDP was at right
|
|
// when seek was begun. It DOES NOT check to see if a seek is finished, which
|
|
// means that any driver that uses non-blocking seeking MUST also call get_status()
|
|
// to check for the completion of that seek.
|
|
// A laserdisc driver that supports non-blocking seeking (LD-V1000) SHOULD call
|
|
// get_status() to check to see if a search is complete. If an LDP isn't designed
|
|
// to return its status (ie the PR-8210) then either blocking seeking must be used
|
|
// or each game driver which uses this player must call get_status().
|
|
virtual unsigned int get_current_frame();
|
|
|
|
// returns m_uCurrentFrame or m_uCurrentFrame+1 if the disc is playing and we've already displayed the 2nd field of the frame
|
|
// (this is in an effort to fix overrun problems on super don)
|
|
unsigned int get_adjusted_current_frame();
|
|
|
|
// returns 0 if this is the first vblank of the frame (assuming vblanks and frames line up),
|
|
// or 1 if it's the second vblank of the frame
|
|
unsigned int get_vblank_mini_count();
|
|
|
|
// causes sram to be saved after every seek
|
|
virtual void set_sram_continuous_update(bool value);
|
|
|
|
virtual void enable_audio1();
|
|
virtual void enable_audio2();
|
|
virtual void disable_audio1();
|
|
virtual void disable_audio2();
|
|
virtual void request_screenshot();
|
|
virtual void set_search_blanking(bool enabled);
|
|
virtual void set_skip_blanking(bool enabled);
|
|
virtual void set_seek_frames_per_ms(double value);
|
|
virtual void set_min_seek_delay(unsigned int value);
|
|
|
|
// END LDP-SPECIFIC SECTION
|
|
|
|
bool is_vldp(); // returns true if our ldp type is VLDP
|
|
bool is_blitting_allowed(); // returns value of blitting_allowed
|
|
void set_blitting_allowed(bool bVal);
|
|
int get_status(); // returns status of laserdisc player
|
|
void framenum_to_frame(Uint32, char *); // converts int to 5-digit string
|
|
Uint32 get_search_latency();
|
|
void set_search_latency(unsigned int);
|
|
void set_stop_on_quit(bool); // enables the stop_on_quit bool flag
|
|
|
|
Uint32 get_discvideo_height(); // gets the height of the laserdisc video (only meaningful with mpeg)
|
|
Uint32 get_discvideo_width(); // gets the width of the laserdisc video (only meaningful with mpeg)
|
|
virtual bool lock_overlay(Uint32); // prevents yuv callback from being called (only meaningful with mpeg)
|
|
virtual bool unlock_overlay(Uint32);
|
|
|
|
// sets the value of this boolean
|
|
void set_use_nonblocking_searching(bool);
|
|
|
|
// returns the value of this boolean
|
|
bool get_use_nonblocking_searching();
|
|
|
|
unsigned int get_elapsed_ms_since_play();
|
|
|
|
// handles LDP-specific command-line arguments
|
|
virtual bool handle_cmdline_arg(const char *arg);
|
|
|
|
// Copies m_bug_log into 'log' and clears m_bug_log.
|
|
// Used by releasetest.
|
|
void get_bug_log(list<string> &log);
|
|
|
|
// debug function used by the cpu debugger
|
|
void print_frame_info();
|
|
|
|
void setVerbose(bool); // rdg2010
|
|
|
|
protected:
|
|
// helper function, shouldn't be called directly
|
|
void increment_current_frame();
|
|
|
|
bool need_serial; // whether this LDP driver needs the serial port initialized
|
|
bool serial_initialized; // whether serial has been initialized
|
|
bool player_initialized; // whether the LDP has been properly initialized
|
|
bool m_bIsVLDP; // this is true if our LDP type is VLDP
|
|
bool blitting_allowed; // whether it's ok to blit directly to the screen (SMPEG forbids this)
|
|
bool skipping_supported; // whether the laserdisc player supports skipping
|
|
bool skip_instead_of_search; // whether we should skip instead of search if searching forward a short distance
|
|
Uint32 max_skippable_frames; // maximum # of frames that player can skip (if skipping is supported)
|
|
Uint32 m_last_try_frame; // the last frame we _tried_ to seek to
|
|
Uint32 m_last_seeked_frame; // the last frame we successfully seeked to (used with m_play_time to calculate current frame)
|
|
// UPDATE : we aren't using cycles anymore (see pre_think())
|
|
// Uint64 m_play_cycles; // # of elapsed cpu cycles from when we last issued a play command
|
|
Uint32 m_play_time; // current time when we last issued a play command
|
|
unsigned int m_start_time; // time when ldp() class was instantiated (only used when not using a cpu)
|
|
int m_status; // the current status of the laserdisc player
|
|
Uint32 search_latency; // how many ms to stall before searching (to simulate slow laserdisc players)
|
|
bool m_stop_on_quit; // should the LDP stop when it quits?
|
|
Uint32 m_discvideo_width; // width of laserdisc video (only meaningful with mpeg)
|
|
Uint32 m_discvideo_height; // height of laserdisc video (only meaningful with mpeg)
|
|
bool m_use_nonblocking_searching; // true if ldp-in drivers should use pre_search in non-blocking mode (as of now, blocking mode is more stable but non-blocking mode is more accurate)
|
|
bool m_dont_get_search_result; // if we should not be calling get_search_result()
|
|
bool m_sram_continuous_update; // if sram is to be updated on a regular basis
|
|
|
|
// timer to be used to simulate search delay when in 'noldp' mode (for debugging)
|
|
Uint32 m_noldp_timer;
|
|
|
|
// used by 'releasetest' to do automatic self-testing
|
|
list<string> m_bug_log;
|
|
|
|
unsigned int m_uCurrentFrame; // the current frame, as calculated by pre_think(), returned by get_current_frame()
|
|
|
|
// current frame - m_last_seeked_frame (for VLDP's usage)
|
|
// For example, the first frame displayed after playing is 0.
|
|
unsigned int m_uCurrentOffsetFrame;
|
|
|
|
// How many milliseconds have elapsed since we started playing the disc.
|
|
// This value is changed by pre_think(), which must get called every 1 ms by the cpu loop
|
|
// This allows us to keep in sync w/ the cpu w/o doing extra expensive calculations.
|
|
unsigned int m_uElapsedMsSincePlay;
|
|
|
|
// how many milliseconds have elapsed while we've been stuck doing blocking seeking
|
|
// (blocking seeking is discouraged because it isn't proper emulation, but some real laserdisc players
|
|
// need to use it for skipping, and a few functions like step-forward use it,
|
|
// and it's probably not worth it to change that behavior as those functions are very rarely used)
|
|
unsigned int m_uBlockedMsSincePlay;
|
|
|
|
// if this is true, we won't increment m_uElapsedMsSincePlay until we get a vblank
|
|
bool m_bWaitingForVblankToPlay;
|
|
|
|
// the total offset of all frames we've skipped since play
|
|
// (for example if I skipped +5 and then -10, this number would be -5)
|
|
int m_iSkipOffsetSincePlay;
|
|
|
|
// how many ms we have to surpass before increasing m_uCurrentOffsetFrame and m_uCurrentFrame
|
|
unsigned int m_uMsFrameBoundary;
|
|
|
|
// How many milliseconds have elapsed since Daphne started
|
|
// This value is changed by pre_think() which is called every 1 ms by the cpu loop
|
|
// This value is used to calculate how many emulated vblanks have occurred.
|
|
unsigned int m_uElapsedMsSinceStart;
|
|
|
|
// how many vblanks have occurred since Daphne started, as calculated by pre_think()
|
|
unsigned int m_uVblankCount;
|
|
|
|
// how many vblanks have occurred since last frame changed
|
|
// (used if laserdisc FPS is half of vblank rate which is usually true)
|
|
unsigned int m_uVblankMiniCount;
|
|
|
|
// how many ms we have to surpass before increasing m_uVblankCount
|
|
unsigned int m_uMsVblankBoundary;
|
|
|
|
// How many frames to skip after displaying 1 frame (for playing at faster than 1X)
|
|
unsigned int m_uFramesToSkipPerFrame;
|
|
|
|
// How many frames to stall for after displaying 1 frame (for playing at slower than 1X)
|
|
unsigned int m_uFramesToStallPerFrame;
|
|
|
|
// State variable to keep track of whether we're stalling (according to m_uFramesToStallPerFrame)
|
|
unsigned int m_uStallFrames;
|
|
|
|
private:
|
|
// set to true if pre_init has been called (used to error checking)
|
|
bool m_bPreInitCalled;
|
|
bool m_bVerbose; // Control message displays on daphne_log.txt -- rdg2010
|
|
|
|
};
|
|
|
|
// same as regular ldp class but has no seek or skip delay (testing skipping games with skip delay is super annoying)
|
|
class fast_noldp : public ldp
|
|
{
|
|
// see ldp.h for comments on how to use these functions
|
|
bool nonblocking_search(char *);
|
|
int get_search_result();
|
|
bool skip_forward(Uint32 frames_to_skip, Uint32 target_frame);
|
|
bool skip_backward(Uint32 frames_to_skip, Uint32 target_frame);
|
|
};
|
|
|
|
extern ldp *g_ldp; // our global ldp class. Defined here so that every .cpp file doesn't have to define it.
|
|
|
|
#endif
|