| SidTune.h | | SidTune.h | |
| | | | |
| skipping to change at line 28 | | skipping to change at line 28 | |
| | | | |
| #ifndef SIDTUNE_H | | #ifndef SIDTUNE_H | |
| #define SIDTUNE_H | | #define SIDTUNE_H | |
| | | | |
| #include "sidtypes.h" | | #include "sidtypes.h" | |
| #include "Buffer.h" | | #include "Buffer.h" | |
| #include "SmartPtr.h" | | #include "SmartPtr.h" | |
| | | | |
| #include <fstream> | | #include <fstream> | |
| | | | |
|
| | | /// Also PSID file format limit. | |
| const uint_least16_t SIDTUNE_MAX_SONGS = 256; | | const uint_least16_t SIDTUNE_MAX_SONGS = 256; | |
|
| // Also PSID file format limit. | | | |
| | | | |
| const uint_least16_t SIDTUNE_MAX_CREDIT_STRINGS = 10; | | const uint_least16_t SIDTUNE_MAX_CREDIT_STRINGS = 10; | |
|
| | | | |
| | | /// 80 characters plus terminating zero. | |
| const uint_least16_t SIDTUNE_MAX_CREDIT_STRLEN = 80+1; | | const uint_least16_t SIDTUNE_MAX_CREDIT_STRLEN = 80+1; | |
|
| // 80 characters plus terminating zero. | | | |
| | | | |
| const uint_least32_t SIDTUNE_MAX_MEMORY = 65536; | | const uint_least32_t SIDTUNE_MAX_MEMORY = 65536; | |
|
| | | | |
| | | /// C64KB+LOAD+PSID | |
| const uint_least32_t SIDTUNE_MAX_FILELEN = 65536+2+0x7C; | | const uint_least32_t SIDTUNE_MAX_FILELEN = 65536+2+0x7C; | |
|
| // C64KB+LOAD+PSID | | | |
| | | | |
|
| const int SIDTUNE_SPEED_VBI = 0; // Vertical-Blanking-Interrupt | | /// Vertical-Blanking-Interrupt | |
| const int SIDTUNE_SPEED_CIA_1A = 60; // CIA 1 Timer A | | const int SIDTUNE_SPEED_VBI = 0; | |
| | | | |
| | | /// CIA 1 Timer A | |
| | | const int SIDTUNE_SPEED_CIA_1A = 60; | |
| | | | |
| const int SIDTUNE_CLOCK_UNKNOWN = 0x00; | | const int SIDTUNE_CLOCK_UNKNOWN = 0x00; | |
| const int SIDTUNE_CLOCK_PAL = 0x01; // These are also used in the | | const int SIDTUNE_CLOCK_PAL = 0x01; // These are also used in the | |
| const int SIDTUNE_CLOCK_NTSC = 0x02; // emulator engine! | | const int SIDTUNE_CLOCK_NTSC = 0x02; // emulator engine! | |
| const int SIDTUNE_CLOCK_ANY = (SIDTUNE_CLOCK_PAL | SIDTUNE_CLOCK_NTSC); | | const int SIDTUNE_CLOCK_ANY = (SIDTUNE_CLOCK_PAL | SIDTUNE_CLOCK_NTSC); | |
| | | | |
| const int SIDTUNE_SIDMODEL_UNKNOWN = 0x00; | | const int SIDTUNE_SIDMODEL_UNKNOWN = 0x00; | |
| const int SIDTUNE_SIDMODEL_6581 = 0x01; // These are also used in the | | const int SIDTUNE_SIDMODEL_6581 = 0x01; // These are also used in the | |
| const int SIDTUNE_SIDMODEL_8580 = 0x02; // emulator engine! | | const int SIDTUNE_SIDMODEL_8580 = 0x02; // emulator engine! | |
| const int SIDTUNE_SIDMODEL_ANY = (SIDTUNE_SIDMODEL_6581 | SIDTUNE_SIDMO
DEL_8580); | | const int SIDTUNE_SIDMODEL_ANY = (SIDTUNE_SIDMODEL_6581 | SIDTUNE_SIDMO
DEL_8580); | |
| | | | |
|
| const int SIDTUNE_COMPATIBILITY_C64 = 0x00; // File is C64 compatible | | const int SIDTUNE_COMPATIBILITY_C64 = 0x00; ///< File is C64 compatible | |
| const int SIDTUNE_COMPATIBILITY_PSID = 0x01; // File is PSID specific | | const int SIDTUNE_COMPATIBILITY_PSID = 0x01; ///< File is PSID specific | |
| const int SIDTUNE_COMPATIBILITY_R64 = 0x02; // File is Real C64 only | | const int SIDTUNE_COMPATIBILITY_R64 = 0x02; ///< File is Real C64 only | |
| const int SIDTUNE_COMPATIBILITY_BASIC = 0x03; // File requires C64 Basic | | const int SIDTUNE_COMPATIBILITY_BASIC = 0x03; ///< File requires C64 Basic | |
| | | | |
| template class SID_EXTERN Buffer_sidtt<const uint_least8_t>; | | template class SID_EXTERN Buffer_sidtt<const uint_least8_t>; | |
| | | | |
|
| | | /** | |
| | | * An instance of this structure is used to transport values to | |
| | | * and from SidTune objects. | |
| | | * | |
| | | * You must read (i.e. activate) sub-song specific information | |
| | | * via: | |
| | | * const SidTuneInfo& tuneInfo = SidTune[songNumber]; | |
| | | * const SidTuneInfo& tuneInfo = SidTune.getInfo(); | |
| | | * void SidTune.getInfo(tuneInfo&); | |
| | | * | |
| | | * Consider the following fields as read-only, because the SidTune class | |
| | | * does not provide an implementation of: bool setInfo(const SidTuneInfo&). | |
| | | * Currently, the only way to get the class to accept values which | |
| | | * are written to these fields is by creating a derived class. | |
| | | */ | |
| struct SidTuneInfo | | struct SidTuneInfo | |
| { | | { | |
|
| // An instance of this structure is used to transport values to | | /// the name of the identified file format | |
| // and from SidTune objects. | | const char* formatString; | |
| | | | |
|
| // You must read (i.e. activate) sub-song specific information | | /// error/status message of last operation | |
| // via: | | const char* statusString; | |
| // const SidTuneInfo& tuneInfo = SidTune[songNumber]; | | | |
| // const SidTuneInfo& tuneInfo = SidTune.getInfo(); | | | |
| // void SidTune.getInfo(tuneInfo&); | | | |
| | | | |
| // Consider the following fields as read-only, because the SidTune clas | | | |
| s | | | |
| // does not provide an implementation of: bool setInfo(const SidTuneInf | | | |
| o&). | | | |
| // Currently, the only way to get the class to accept values which | | | |
| // are written to these fields is by creating a derived class. | | | |
| | | | |
|
| const char* formatString; // the name of the identified file format | | /// describing the speed a song is running at | |
| const char* statusString; // error/status message of last operation | | const char* speedString; | |
| | | | |
| const char* speedString; // describing the speed a song is running a | | | |
| t | | | |
| | | | |
| uint_least16_t loadAddr; | | uint_least16_t loadAddr; | |
| uint_least16_t initAddr; | | uint_least16_t initAddr; | |
| uint_least16_t playAddr; | | uint_least16_t playAddr; | |
| | | | |
| uint_least16_t songs; | | uint_least16_t songs; | |
| uint_least16_t startSong; | | uint_least16_t startSong; | |
| | | | |
|
| // The SID chip base address(es) used by the sidtune. | | /** | |
| uint_least16_t sidChipBase1; // 0xD400 (normal, 1st SID) | | * @name Base addresses | |
| uint_least16_t sidChipBase2; // 0xD?00 (2nd SID) or 0 (no 2nd SID) | | * The SID chip base address(es) used by the sidtune. | |
| | | */ | |
| // Available after song initialization. | | //@{ | |
| // | | uint_least16_t sidChipBase1; ///< 0xD400 (normal, 1st SID) | |
| uint_least16_t currentSong; // the one that has been initialized | | uint_least16_t sidChipBase2; ///< 0xD?00 (2nd SID) or 0 (no 2nd SID) | |
| uint_least8_t songSpeed; // intended speed, see top | | //@} | |
| uint_least8_t clockSpeed; // -"- | | | |
| uint_least8_t relocStartPage; // First available page for relocation | | /// Available after song initialization. | |
| uint_least8_t relocPages; // Number of pages available for relocat | | /// the one that has been initialized | |
| ion | | uint_least16_t currentSong; | |
| bool musPlayer; // whether Sidplayer routine has been in | | | |
| stalled | | /// intended speed, see top | |
| int sidModel1; // Sid Model required for first sid | | uint_least8_t songSpeed; | |
| int sidModel2; // Sid Model required for second sid | | | |
| int compatibility; // compatibility requirements | | /// -"- | |
| bool fixLoad; // whether load address might be duplica | | uint_least8_t clockSpeed; | |
| te | | | |
| uint_least16_t songLength; // --- not yet supported --- | | /// First available page for relocation | |
| // | | uint_least8_t relocStartPage; | |
| // Song title, credits, ... | | | |
| // 0 = Title, 1 = Author, 2 = Copyright/Publisher | | /// Number of pages available for relocation | |
| // | | uint_least8_t relocPages; | |
| uint_least8_t numberOfInfoStrings; // the number of available text inf | | | |
| o lines | | /// whether Sidplayer routine has been installed | |
| | | bool musPlayer; | |
| | | | |
| | | /// Sid Model required for first sid | |
| | | int sidModel1; | |
| | | | |
| | | /// Sid Model required for second sid | |
| | | int sidModel2; | |
| | | | |
| | | /// compatibility requirements | |
| | | int compatibility; | |
| | | | |
| | | /// whether load address might be duplicate | |
| | | bool fixLoad; | |
| | | | |
| | | /// --- not yet supported --- | |
| | | uint_least16_t songLength; | |
| | | | |
| | | /** | |
| | | * Song title, credits, ... | |
| | | * 0 = Title, 1 = Author, 2 = Copyright/Publisher | |
| | | */ | |
| | | uint_least8_t numberOfInfoStrings; | |
| | | | |
| | | /// the number of available text info lines | |
| char* infoString[SIDTUNE_MAX_CREDIT_STRINGS]; | | char* infoString[SIDTUNE_MAX_CREDIT_STRINGS]; | |
|
| // | | | |
| uint_least16_t numberOfCommentStrings; // --- not yet supported --- | | /// --- not yet supported --- | |
| char ** commentString; // --- not yet supported --- | | uint_least16_t numberOfCommentStrings; | |
| // | | | |
| uint_least32_t dataFileLen; // length of single-file sidtune file | | /// --- not yet supported --- | |
| uint_least32_t c64dataLen; // length of raw C64 data without load a | | char ** commentString; | |
| ddress | | | |
| char* path; // path to sidtune files; "", if cwd | | /// length of single-file sidtune file | |
| char* dataFileName; // a first file: e.g. "foo.c64"; "", if | | uint_least32_t dataFileLen; | |
| none | | | |
| char* infoFileName; // a second file: e.g. "foo.sid"; "", if | | /// length of raw C64 data without load address | |
| none | | uint_least32_t c64dataLen; | |
| // | | | |
| | | /// path to sidtune files; "", if cwd | |
| | | char* path; | |
| | | | |
| | | /// a first file: e.g. "foo.c64"; "", if none | |
| | | char* dataFileName; | |
| | | | |
| | | /// a second file: e.g. "foo.sid"; "", if none | |
| | | char* infoFileName; | |
| }; | | }; | |
| | | | |
|
| | | /** | |
| | | * SidTune | |
| | | */ | |
| class SID_EXTERN SidTune | | class SID_EXTERN SidTune | |
| { | | { | |
| private: | | private: | |
| typedef enum | | typedef enum | |
| { | | { | |
| LOAD_NOT_MINE = 0, | | LOAD_NOT_MINE = 0, | |
| LOAD_OK, | | LOAD_OK, | |
| LOAD_ERROR | | LOAD_ERROR | |
| } LoadStatus; | | } LoadStatus; | |
| | | | |
| public: // --------------------------------------------------------------
-- | | public: // --------------------------------------------------------------
-- | |
| | | | |
|
| // If your opendir() and readdir()->d_name return path names | | /** | |
| // that contain the forward slash (/) as file separator, but | | * Load a sidtune from a file. | |
| // your operating system uses a different character, there are | | * | |
| // extra functions that can deal with this special case. Set | | * To retrieve data from standard input pass in filename "-". | |
| // separatorIsSlash to true if you like path names to be split | | * If you want to override the default filename extensions use this | |
| // correctly. | | * contructor. Please note, that if the specified ``sidTuneFileName'' | |
| // You do not need these extra functions if your systems file | | * does exist and the loader is able to determine its file format, | |
| // separator is the forward slash. | | * this function does not try to append any file name extension. | |
| // | | * See ``sidtune.cpp'' for the default list of file name extensions. | |
| // Load a sidtune from a file. | | * You can specific ``sidTuneFileName = 0'', if you do not want to | |
| // | | * load a sidtune. You can later load one with open(). | |
| // To retrieve data from standard input pass in filename "-". | | */ | |
| // If you want to override the default filename extensions use this | | | |
| // contructor. Please note, that if the specified ``sidTuneFileName'' | | | |
| // does exist and the loader is able to determine its file format, | | | |
| // this function does not try to append any file name extension. | | | |
| // See ``sidtune.cpp'' for the default list of file name extensions. | | | |
| // You can specific ``sidTuneFileName = 0'', if you do not want to | | | |
| // load a sidtune. You can later load one with open(). | | | |
| SidTune(const char* fileName, const char **fileNameExt = 0, | | SidTune(const char* fileName, const char **fileNameExt = 0, | |
| const bool separatorIsSlash = false); | | const bool separatorIsSlash = false); | |
| | | | |
|
| // Load a single-file sidtune from a memory buffer. | | /** | |
| // Currently supported: PSID format | | * Load a single-file sidtune from a memory buffer. | |
| | | * Currently supported: PSID format | |
| | | */ | |
| SidTune(const uint_least8_t* oneFileFormatSidtune, const uint_least32_t
sidtuneLength); | | SidTune(const uint_least8_t* oneFileFormatSidtune, const uint_least32_t
sidtuneLength); | |
| | | | |
| virtual ~SidTune(); | | virtual ~SidTune(); | |
| | | | |
|
| // The sidTune class does not copy the list of file name extensions, | | /** | |
| // so make sure you keep it. If the provided pointer is 0, the | | * The sidTune class does not copy the list of file name extensions, | |
| // default list will be activated. This is a static list which | | * so make sure you keep it. If the provided pointer is 0, the | |
| // is used by all SidTune objects. | | * default list will be activated. This is a static list which | |
| | | * | |
| | | * is used by all SidTune objects. | |
| | | */ | |
| void setFileNameExtensions(const char **fileNameExt); | | void setFileNameExtensions(const char **fileNameExt); | |
| | | | |
|
| // Load a sidtune into an existing object. | | /** | |
| // From a file. | | * Load a sidtune into an existing object. | |
| | | * From a file. | |
| | | */ | |
| bool load(const char* fileName, const bool separatorIsSlash = false); | | bool load(const char* fileName, const bool separatorIsSlash = false); | |
| | | | |
|
| // From a buffer. | | /** | |
| | | * From a buffer. | |
| | | */ | |
| bool read(const uint_least8_t* sourceBuffer, const uint_least32_t buffe
rLen); | | bool read(const uint_least8_t* sourceBuffer, const uint_least32_t buffe
rLen); | |
| | | | |
|
| // Select sub-song (0 = default starting song) | | /** | |
| // and retrieve active song information. | | * Select sub-song (0 = default starting song) | |
| | | * and retrieve active song information. | |
| | | */ | |
| const SidTuneInfo& operator[](const uint_least16_t songNum); | | const SidTuneInfo& operator[](const uint_least16_t songNum); | |
| | | | |
|
| // Select sub-song (0 = default starting song) | | /** | |
| // and return active song number out of [1,2,..,SIDTUNE_MAX_SONGS]. | | * Select sub-song (0 = default starting song) | |
| | | * and return active song number out of [1,2,..,SIDTUNE_MAX_SONGS]. | |
| | | */ | |
| uint_least16_t selectSong(const uint_least16_t songNum); | | uint_least16_t selectSong(const uint_least16_t songNum); | |
| | | | |
|
| // Retrieve sub-song specific information. | | /** | |
| // Beware! Still member-wise copy! | | * Retrieve sub-song specific information. | |
| | | * Beware! Still member-wise copy! | |
| | | */ | |
| const SidTuneInfo& getInfo(); | | const SidTuneInfo& getInfo(); | |
| | | | |
|
| // Get a copy of sub-song specific information. | | /** | |
| // Beware! Still member-wise copy! | | * Get a copy of sub-song specific information. | |
| | | * Beware! Still member-wise copy! | |
| | | */ | |
| void getInfo(SidTuneInfo&); | | void getInfo(SidTuneInfo&); | |
| | | | |
|
| // Determine current state of object (true = okay, false = error). | | /** | |
| // Upon error condition use ``getInfo'' to get a descriptive | | * Determine current state of object (true = okay, false = error). | |
| // text string in ``SidTuneInfo.statusString''. | | * Upon error condition use ``getInfo'' to get a descriptive | |
| | | * text string in ``SidTuneInfo.statusString''. | |
| | | */ | |
| operator bool() { return status; } | | operator bool() { return status; } | |
| bool getStatus() { return status; } | | bool getStatus() { return status; } | |
| | | | |
|
| // Whether sidtune uses two SID chips. | | /** | |
| | | * Whether sidtune uses two SID chips. | |
| | | */ | |
| bool isStereo() | | bool isStereo() | |
| { | | { | |
| return (info.sidChipBase1!=0 && info.sidChipBase2!=0); | | return (info.sidChipBase1!=0 && info.sidChipBase2!=0); | |
| } | | } | |
| | | | |
|
| // Copy sidtune into C64 memory (64 KB). | | /** | |
| | | * Copy sidtune into C64 memory (64 KB). | |
| | | */ | |
| bool placeSidTuneInC64mem(uint_least8_t* c64buf); | | bool placeSidTuneInC64mem(uint_least8_t* c64buf); | |
| | | | |
| // --- file save & format conversion --- | | // --- file save & format conversion --- | |
| | | | |
|
| // These functions work for any successfully created object. | | /** | |
| // overWriteFlag: true = Overwrite existing file. | | * These functions work for any successfully created object. | |
| // false = Default, return error when file already | | * overWriteFlag: true = Overwrite existing file. | |
| // exists. | | * false = Default, return error when file already | |
| // One could imagine an "Are you sure ?"-checkbox before overwriting | | * exists. | |
| // any file. | | * One could imagine an "Are you sure ?"-checkbox before overwriting | |
| // returns: true = Successful, false = Error condition. | | * any file. | |
| | | * returns: true = Successful, false = Error condition. | |
| | | */ | |
| bool saveC64dataFile( const char* destFileName, const bool overWriteFla
g = false ); | | bool saveC64dataFile( const char* destFileName, const bool overWriteFla
g = false ); | |
| bool saveSIDfile( const char* destFileName, const bool overWriteFlag =
false ); | | bool saveSIDfile( const char* destFileName, const bool overWriteFlag =
false ); | |
| bool savePSIDfile( const char* destFileName, const bool overWriteFlag =
false ); | | bool savePSIDfile( const char* destFileName, const bool overWriteFlag =
false ); | |
| | | | |
|
| // This function can be used to remove a duplicate C64 load address in | | /** | |
| // the C64 data (example: FE 0F 00 10 4C ...). A duplicate load address | | * This function can be used to remove a duplicate C64 load address in | |
| // of offset 0x02 is indicated by the ``fixLoad'' flag in the SidTuneIn | | * the C64 data (example: FE 0F 00 10 4C ...). A duplicate load address | |
| fo | | * of offset 0x02 is indicated by the ``fixLoad'' flag in the SidTuneInf | |
| // structure. | | o | |
| // | | * structure. | |
| // The ``force'' flag here can be used to remove the first load address | | * | |
| // and set new INIT/PLAY addresses regardless of whether a duplicate | | * The ``force'' flag here can be used to remove the first load address | |
| // load address has been detected and indicated by ``fixLoad''. | | * and set new INIT/PLAY addresses regardless of whether a duplicate | |
| // For instance, some position independent sidtunes contain a load addr | | * load address has been detected and indicated by ``fixLoad''. | |
| ess | | * For instance, some position independent sidtunes contain a load addre | |
| // of 0xE000, but are loaded to 0x0FFE and call the player code at 0x10 | | ss | |
| 00. | | * of 0xE000, but are loaded to 0x0FFE and call the player code at 0x100 | |
| // | | 0. | |
| // Do not forget to save the sidtune file. | | * | |
| | | * Do not forget to save the sidtune file. | |
| | | */ | |
| void fixLoadAddress(const bool force = false, uint_least16_t initAddr =
0, | | void fixLoadAddress(const bool force = false, uint_least16_t initAddr =
0, | |
| uint_least16_t playAddr = 0); | | uint_least16_t playAddr = 0); | |
| | | | |
|
| // Does not affect status of object, and therefore can be used | | /** | |
| // to load files. Error string is put into info.statusString, though. | | * Does not affect status of object, and therefore can be used | |
| | | * to load files. Error string is put into info.statusString, though. | |
| | | */ | |
| bool loadFile(const char* fileName, Buffer_sidtt<const uint_least8_t>&
bufferRef); | | bool loadFile(const char* fileName, Buffer_sidtt<const uint_least8_t>&
bufferRef); | |
| | | | |
| bool saveToOpenFile( std::ofstream& toFile, const uint_least8_t* buffer
, uint_least32_t bufLen ); | | bool saveToOpenFile( std::ofstream& toFile, const uint_least8_t* buffer
, uint_least32_t bufLen ); | |
| | | | |
| protected: // -----------------------------------------------------------
-- | | protected: // -----------------------------------------------------------
-- | |
| | | | |
| SidTuneInfo info; | | SidTuneInfo info; | |
| bool status; | | bool status; | |
| | | | |
| uint_least8_t songSpeed[SIDTUNE_MAX_SONGS]; | | uint_least8_t songSpeed[SIDTUNE_MAX_SONGS]; | |
| uint_least8_t clockSpeed[SIDTUNE_MAX_SONGS]; | | uint_least8_t clockSpeed[SIDTUNE_MAX_SONGS]; | |
| uint_least16_t songLength[SIDTUNE_MAX_SONGS]; | | uint_least16_t songLength[SIDTUNE_MAX_SONGS]; | |
| | | | |
|
| // holds text info from the format headers etc. | | /// holds text info from the format headers etc. | |
| char infoString[SIDTUNE_MAX_CREDIT_STRINGS][SIDTUNE_MAX_CREDIT_STRLEN]; | | char infoString[SIDTUNE_MAX_CREDIT_STRINGS][SIDTUNE_MAX_CREDIT_STRLEN]; | |
| | | | |
|
| // See instructions at top. | | /** | |
| | | * If your opendir() and readdir()->d_name return path names | |
| | | * that contain the forward slash (/) as file separator, but | |
| | | * your operating system uses a different character, there are | |
| | | * extra functions that can deal with this special case. Set | |
| | | * separatorIsSlash to true if you like path names to be split | |
| | | * correctly. | |
| | | * You do not need these extra functions if your systems file | |
| | | * separator is the forward slash. | |
| | | */ | |
| bool isSlashedFileName; | | bool isSlashedFileName; | |
| | | | |
|
| // For files with header: offset to real data | | /// For files with header: offset to real data | |
| uint_least32_t fileOffset; | | uint_least32_t fileOffset; | |
| | | | |
|
| // Needed for MUS/STR player installation. | | /// Needed for MUS/STR player installation. | |
| uint_least16_t musDataLen; | | uint_least16_t musDataLen; | |
| | | | |
| Buffer_sidtt<const uint_least8_t> cache; | | Buffer_sidtt<const uint_least8_t> cache; | |
| | | | |
|
| // Filename extensions to append for various file types. | | /// Filename extensions to append for various file types. | |
| static const char** fileNameExtensions; | | static const char** fileNameExtensions; | |
| | | | |
| // --- protected member functions --- | | // --- protected member functions --- | |
| | | | |
|
| // Convert 32-bit PSID-style speed word to internal tables. | | /// Convert 32-bit PSID-style speed word to internal tables. | |
| void convertOldStyleSpeedToTables(uint_least32_t speed, | | void convertOldStyleSpeedToTables(uint_least32_t speed, | |
| int clock = SIDTUNE_CLOCK_PAL); | | int clock = SIDTUNE_CLOCK_PAL); | |
| | | | |
| virtual int convertPetsciiToAscii (SmartPtr_sidtt<const uint_least8_t>&
, char*); | | virtual int convertPetsciiToAscii (SmartPtr_sidtt<const uint_least8_t>&
, char*); | |
| | | | |
|
| // Check compatibility details are sensible | | /// Check compatibility details are sensible | |
| bool checkCompatibility(void); | | bool checkCompatibility(void); | |
|
| // Check for valid relocation information | | /// Check for valid relocation information | |
| bool checkRelocInfo(void); | | bool checkRelocInfo(void); | |
|
| // Common address resolution procedure | | /// Common address resolution procedure | |
| bool resolveAddrs(const uint_least8_t* c64data); | | bool resolveAddrs(const uint_least8_t* c64data); | |
| | | | |
| // Support for various file formats. | | // Support for various file formats. | |
| | | | |
| virtual LoadStatus PSID_fileSupport (Buffer_sidtt<const uint_least8_
t>& dataBuf); | | virtual LoadStatus PSID_fileSupport (Buffer_sidtt<const uint_least8_
t>& dataBuf); | |
| virtual bool PSID_fileSupportSave(std::ofstream& toFile, const ui
nt_least8_t* dataBuffer); | | virtual bool PSID_fileSupportSave(std::ofstream& toFile, const ui
nt_least8_t* dataBuffer); | |
| | | | |
| virtual LoadStatus SID_fileSupport (Buffer_sidtt<const uint_least8_
t>& dataBuf, | | virtual LoadStatus SID_fileSupport (Buffer_sidtt<const uint_least8_
t>& dataBuf, | |
| Buffer_sidtt<const uint_least8_
t>& sidBuf); | | Buffer_sidtt<const uint_least8_
t>& sidBuf); | |
| virtual bool SID_fileSupportSave (std::ofstream& toFile); | | virtual bool SID_fileSupportSave (std::ofstream& toFile); | |
| | | | |
| skipping to change at line 311 | | skipping to change at line 394 | |
| virtual void MUS_setPlayerAddress(); | | virtual void MUS_setPlayerAddress(); | |
| virtual void MUS_installPlayer (uint_least8_t *c64buf); | | virtual void MUS_installPlayer (uint_least8_t *c64buf); | |
| | | | |
| virtual LoadStatus INFO_fileSupport (Buffer_sidtt<const uint_least8_
t>& dataBuf, | | virtual LoadStatus INFO_fileSupport (Buffer_sidtt<const uint_least8_
t>& dataBuf, | |
| Buffer_sidtt<const uint_least8_
t>& infoBuf); | | Buffer_sidtt<const uint_least8_
t>& infoBuf); | |
| virtual LoadStatus PRG_fileSupport (const char* fileName, | | virtual LoadStatus PRG_fileSupport (const char* fileName, | |
| Buffer_sidtt<const uint_least8_
t>& dataBuf); | | Buffer_sidtt<const uint_least8_
t>& dataBuf); | |
| virtual LoadStatus X00_fileSupport (const char* fileName, | | virtual LoadStatus X00_fileSupport (const char* fileName, | |
| Buffer_sidtt<const uint_least8_
t>& dataBuf); | | Buffer_sidtt<const uint_least8_
t>& dataBuf); | |
| | | | |
|
| // Error and status message strings. | | /// @name Error and status message strings. | |
| | | //@{ | |
| static const char* txt_songNumberExceed; | | static const char* txt_songNumberExceed; | |
| static const char* txt_empty; | | static const char* txt_empty; | |
| static const char* txt_unrecognizedFormat; | | static const char* txt_unrecognizedFormat; | |
| static const char* txt_noDataFile; | | static const char* txt_noDataFile; | |
| static const char* txt_notEnoughMemory; | | static const char* txt_notEnoughMemory; | |
| static const char* txt_cantLoadFile; | | static const char* txt_cantLoadFile; | |
| static const char* txt_cantOpenFile; | | static const char* txt_cantOpenFile; | |
| static const char* txt_fileTooLong; | | static const char* txt_fileTooLong; | |
| static const char* txt_dataTooLong; | | static const char* txt_dataTooLong; | |
| static const char* txt_cantCreateFile; | | static const char* txt_cantCreateFile; | |
| static const char* txt_fileIoError; | | static const char* txt_fileIoError; | |
| static const char* txt_VBI; | | static const char* txt_VBI; | |
| static const char* txt_CIA; | | static const char* txt_CIA; | |
| static const char* txt_noErrors; | | static const char* txt_noErrors; | |
| static const char* txt_na; | | static const char* txt_na; | |
| static const char* txt_badAddr; | | static const char* txt_badAddr; | |
| static const char* txt_badReloc; | | static const char* txt_badReloc; | |
| static const char* txt_corrupt; | | static const char* txt_corrupt; | |
|
| | | //@} | |
| | | | |
| private: // -------------------------------------------------------------
-- | | private: // -------------------------------------------------------------
-- | |
| | | | |
| void init(); | | void init(); | |
| void cleanup(); | | void cleanup(); | |
| #if !defined(SIDTUNE_NO_STDIN_LOADER) | | #if !defined(SIDTUNE_NO_STDIN_LOADER) | |
| void getFromStdIn(); | | void getFromStdIn(); | |
| #endif | | #endif | |
| void getFromFiles(const char* name); | | void getFromFiles(const char* name); | |
| | | | |
| void deleteFileNameCopies(); | | void deleteFileNameCopies(); | |
| | | | |
|
| // Try to retrieve single-file sidtune from specified buffer. | | /// Try to retrieve single-file sidtune from specified buffer. | |
| void getFromBuffer(const uint_least8_t* const buffer, const uint_least3
2_t bufferLen); | | void getFromBuffer(const uint_least8_t* const buffer, const uint_least3
2_t bufferLen); | |
| | | | |
|
| // Cache the data of a single-file or two-file sidtune and its | | /** | |
| // corresponding file names. | | * Cache the data of a single-file or two-file sidtune and its | |
| | | * corresponding file names. | |
| | | */ | |
| bool acceptSidTune(const char* dataFileName, const char* infoFileName, | | bool acceptSidTune(const char* dataFileName, const char* infoFileName, | |
| Buffer_sidtt<const uint_least8_t>& buf); | | Buffer_sidtt<const uint_least8_t>& buf); | |
| | | | |
| bool createNewFileName(Buffer_sidtt<char>& destString, | | bool createNewFileName(Buffer_sidtt<char>& destString, | |
| const char* sourceName, const char* sourceExt); | | const char* sourceName, const char* sourceExt); | |
| | | | |
| int decompressPP20(Buffer_sidtt<const uint_least8_t>& buf); | | int decompressPP20(Buffer_sidtt<const uint_least8_t>& buf); | |
| | | | |
| private: // prevent copying | | private: // prevent copying | |
| SidTune(const SidTune&); | | SidTune(const SidTune&); | |
| | | | |
End of changes. 43 change blocks. |
| 145 lines changed or deleted | | 222 lines changed or added | |
|
| event.h | | event.h | |
| | | | |
| skipping to change at line 24 | | skipping to change at line 24 | |
| * the Free Software Foundation; either version 2 of the License, or
* | | * the Free Software Foundation; either version 2 of the License, or
* | |
| * (at your option) any later version.
* | | * (at your option) any later version.
* | |
| *
* | | *
* | |
| **************************************************************************
*/ | | **************************************************************************
*/ | |
| | | | |
| #ifndef _event_h_ | | #ifndef _event_h_ | |
| #define _event_h_ | | #define _event_h_ | |
| | | | |
| #include "sidtypes.h" | | #include "sidtypes.h" | |
| | | | |
|
| typedef uint_fast32_t event_clock_t; | | typedef int_fast64_t event_clock_t; | |
| | | | |
| | | /** | |
| | | * C64 system runs actions at system clock high and low | |
| | | * states. The PHI1 corresponds to the auxiliary chip activity | |
| | | * and PHI2 to CPU activity. For any clock, PHI1s are before | |
| | | * PHI2s. | |
| | | */ | |
| typedef enum {EVENT_CLOCK_PHI1 = 0, EVENT_CLOCK_PHI2 = 1} event_phase_t; | | typedef enum {EVENT_CLOCK_PHI1 = 0, EVENT_CLOCK_PHI2 = 1} event_phase_t; | |
|
| #define EVENT_CONTEXT_MAX_PENDING_EVENTS 0x100 | | | |
| | | | |
|
| | | /** | |
| | | * Event scheduler (based on alarm from Vice). Created in 2001 by Simon A. | |
| | | * White. | |
| | | * | |
| | | * Optimized EventScheduler and corresponding Event class by Antti S. Lankil | |
| | | a | |
| | | * in 2009. | |
| | | * | |
| | | * @author Antti Lankila | |
| | | */ | |
| class SID_EXTERN Event | | class SID_EXTERN Event | |
| { | | { | |
| friend class EventScheduler; | | friend class EventScheduler; | |
| | | | |
| private: | | private: | |
|
| | | class EventContext *m_context SID_DEPRECATED; | |
| | | | |
| | | /** Describe event for humans. */ | |
| const char * const m_name; | | const char * const m_name; | |
|
| class EventContext *m_context; | | | |
| event_clock_t m_clk; | | | |
| | | | |
|
| /* This variable is set by the event context | | /** The clock this event fires */ | |
| when it is scheduled */ | | event_clock_t triggerTime; | |
| | | | |
| | | /** | |
| | | * This variable is set by the event context | |
| | | * when it is scheduled | |
| | | */ | |
| bool m_pending; | | bool m_pending; | |
| | | | |
|
| /* Link to the next and previous events in the | | /** The next event in sequence */ | |
| list. */ | | Event *next; | |
| Event *m_next, *m_prev; | | | |
| | | | |
| public: | | public: | |
|
| | | /** | |
| | | * Events are used for delayed execution. Name is | |
| | | * not used by code, but is useful for debugging. | |
| | | * | |
| | | * @param name Descriptive string of the event. | |
| | | */ | |
| Event(const char * const name) | | Event(const char * const name) | |
| : m_name(name), | | : m_name(name), | |
| m_pending(false) {} | | m_pending(false) {} | |
| ~Event() {} | | ~Event() {} | |
| | | | |
|
| | | /** | |
| | | * Event code to be executed. Events are allowed to safely | |
| | | * reschedule themselves with the EventScheduler during | |
| | | * invocations. | |
| | | */ | |
| virtual void event (void) = 0; | | virtual void event (void) = 0; | |
|
| bool pending () { return m_pending; } | | | |
| void cancel (); | | /** Is Event scheduled? */ | |
| void schedule(EventContext &context, event_clock_t cycles, | | bool pending () const { return m_pending; } | |
| | | | |
| | | /** | |
| | | * Cancel the specified event. | |
| | | * | |
| | | * @deprecated use EventContext::cancel | |
| | | */ | |
| | | SID_DEPRECATED void cancel (); | |
| | | | |
| | | /** | |
| | | * Add event to pending queue. | |
| | | * | |
| | | * @deprecated use EventContext::schedule | |
| | | */ | |
| | | SID_DEPRECATED void schedule(EventContext &context, event_clock_t cy | |
| | | cles, | |
| event_phase_t phase); | | event_phase_t phase); | |
| }; | | }; | |
| | | | |
| template< class This > | | template< class This > | |
| class EventCallback: public Event | | class EventCallback: public Event | |
| { | | { | |
| private: | | private: | |
| typedef void (This::*Callback) (); | | typedef void (This::*Callback) (); | |
| This &m_this; | | This &m_this; | |
| Callback const m_callback; | | Callback const m_callback; | |
| | | | |
| skipping to change at line 80 | | skipping to change at line 125 | |
| m_callback(callback) {} | | m_callback(callback) {} | |
| }; | | }; | |
| | | | |
| // Public Event Context | | // Public Event Context | |
| class EventContext | | class EventContext | |
| { | | { | |
| friend class Event; | | friend class Event; | |
| | | | |
| public: | | public: | |
| virtual void cancel (Event &event) = 0; | | virtual void cancel (Event &event) = 0; | |
|
| virtual void schedule (Event &event, event_clock_t cycles, | | virtual void schedule (Event &event, const event_clock_t cycles, | |
| event_phase_t phase) = 0; | | const event_phase_t phase) = 0; | |
| virtual event_clock_t getTime (event_phase_t phase) const = 0; | | virtual void schedule (Event &event, const event_clock_t cycles) = 0; | |
| virtual event_clock_t getTime (event_clock_t clock, event_phase_t phase | | virtual event_clock_t getTime (const event_phase_t phase) const = 0; | |
| ) const = 0; | | virtual event_clock_t getTime (const event_clock_t clock, const event_p | |
| | | hase_t phase) const = 0; | |
| virtual event_phase_t phase () const = 0; | | virtual event_phase_t phase () const = 0; | |
| }; | | }; | |
| | | | |
|
| // Private Event Context Object (The scheduler) | | /** | |
| class EventScheduler: public EventContext, public Event | | * Fast EventScheduler, which maintains a linked list of Events. | |
| | | * This scheduler takes neglible time even when it is used to | |
| | | * schedule events for nearly every clock. | |
| | | * | |
| | | * Events occur on an internal clock which is 2x the visible clock. | |
| | | * The visible clock is divided to two phases called phi1 and phi2. | |
| | | * | |
| | | * The phi1 clocks are used by VIC and CIA chips, phi2 clocks by CPU. | |
| | | * | |
| | | * Scheduling an event for a phi1 clock when system is in phi2 causes the | |
| | | * event to be moved to the next cycle. (This behavior may be a bug of the | |
| | | * original EventScheduler specification. Likely reason is to avoid | |
| | | * scheduling an event into past.) | |
| | | * | |
| | | * Getting a phi1 time when system is in phi2 causes the next phi1 clock | |
| | | * to be returned. | |
| | | * | |
| | | * To make scheduling even faster, I am considering making event cancellatio | |
| | | n | |
| | | * before rescheduling mandatory, as caller is generally in position to | |
| | | * automatically know if the event needs to be canceled first. | |
| | | * | |
| | | * @author Antti S. Lankila | |
| | | */ | |
| | | class EventScheduler: public EventContext | |
| { | | { | |
| private: | | private: | |
|
| EventCallback<EventScheduler> m_timeWarp; | | event_clock_t currentTime; | |
| uint m_events; | | Event *firstEvent; | |
| uint m_events_future; | | | |
| | | | |
| private: | | private: | |
| void event (void); | | void event (void); | |
| | | | |
|
| | | /** | |
| | | * Scan the event queue and schedule event for execution. | |
| | | * | |
| | | * @param event The event to add | |
| | | */ | |
| | | void schedule(Event &event) { | |
| | | | |
| | | if (event.m_pending) | |
| | | cancel(event); | |
| | | | |
| | | event.m_pending = true; | |
| | | | |
| | | /* find the right spot where to tuck this new event */ | |
| | | Event **scan = &firstEvent; | |
| | | for (;;) { | |
| | | if (*scan == 0 || (*scan)->triggerTime > event.triggerTime) { | |
| | | event.next = *scan; | |
| | | *scan = &event; | |
| | | break; | |
| | | } | |
| | | scan = &((*scan)->next); | |
| | | } | |
| | | } | |
| | | | |
| protected: | | protected: | |
|
| void schedule (Event &event, event_clock_t cycles, | | /** Add event to pending queue. | |
| event_phase_t phase); | | * | |
| void cancel (Event &event) | | * @param event the event to add | |
| { | | * @param cycles the clock to fire | |
| event.m_pending = false; | | * @param phase when to fire the event | |
| event.m_prev->m_next = event.m_next; | | */ | |
| event.m_next->m_prev = event.m_prev; | | void schedule (Event &event, const event_clock_t cycles, | |
| m_events--; | | const event_phase_t phase) { | |
| | | event.triggerTime = (cycles << 1) + currentTime + (currentTime & 1 | |
| | | ^ (phase == EVENT_CLOCK_PHI1 ? 0 : 1)); | |
| | | schedule(event); | |
| | | } | |
| | | | |
| | | /** Add event to pending queue in the same phase as current event. | |
| | | * | |
| | | * @param event the event to add | |
| | | * @param cycles how many cycles from now to fire | |
| | | */ | |
| | | void schedule(Event &event, const event_clock_t cycles) { | |
| | | event.triggerTime = (cycles << 1) + currentTime; | |
| | | schedule(event); | |
| } | | } | |
| | | | |
|
| | | /** Cancel the specified event. | |
| | | * | |
| | | * @param event the event to cancel | |
| | | */ | |
| | | void cancel (Event &event); | |
| | | | |
| public: | | public: | |
|
| EventScheduler (const char * const name); | | EventScheduler () | |
| | | : currentTime(0), | |
| | | firstEvent(0) {} | |
| | | | |
| | | /** Cancel all pending events and reset time. */ | |
| void reset (void); | | void reset (void); | |
| | | | |
|
| | | /** Fire next event, advance system time to that event */ | |
| void clock (void) | | void clock (void) | |
| { | | { | |
|
| // m_clk++; | | Event &event = *firstEvent; | |
| // while (m_events && (m_clk >= m_next->m_clk)) | | firstEvent = firstEvent->next; | |
| // dispatch (*m_next); | | event.m_pending = false; | |
| Event &e = *m_next; | | currentTime = event.triggerTime; | |
| m_clk = e.m_clk; | | event.event(); | |
| cancel (e); | | | |
| //printf ("Event \"%s\"\n", e.m_name); | | | |
| e.event(); | | | |
| } | | } | |
| | | | |
|
| // Get time with respect to a specific clock phase | | /** Get time with respect to a specific clock phase | |
| event_clock_t getTime (event_phase_t phase) const | | * | |
| { return (m_clk + (phase ^ 1)) >> 1; } | | * @param phase the phase | |
| event_clock_t getTime (event_clock_t clock, event_phase_t phase) const | | * @return the time according to specified phase. | |
| { return ((getTime (phase) - clock) << 1) >> 1; } // 31 bit res. | | */ | |
| event_phase_t phase () const { return (event_phase_t) (m_clk & 1); } | | event_clock_t getTime (const event_phase_t phase) const | |
| | | { return (currentTime + (phase ^ 1)) >> 1; } | |
| | | | |
| | | /** Get clocks since specified clock in given phase. | |
| | | * | |
| | | * @param clock the time to compare to | |
| | | * @param phase the phase to comapre to | |
| | | * @return the time between specified clock and now | |
| | | */ | |
| | | event_clock_t getTime (const event_clock_t clock, const event_phase_t p | |
| | | hase) const | |
| | | { return getTime (phase) - clock; } | |
| | | | |
| | | /** Return current clock phase | |
| | | * | |
| | | * @return The current phase | |
| | | */ | |
| | | event_phase_t phase () const { return (event_phase_t) (currentTime & 1) | |
| | | ; } | |
| }; | | }; | |
| | | | |
| inline void Event::schedule (EventContext &context, event_clock_t cycles, | | inline void Event::schedule (EventContext &context, event_clock_t cycles, | |
| event_phase_t phase) | | event_phase_t phase) | |
| { | | { | |
|
| context.schedule (*this, cycles, phase); | | m_context = &context; | |
| | | m_context->schedule (*this, cycles, phase); | |
| } | | } | |
| | | | |
| inline void Event::cancel () | | inline void Event::cancel () | |
| { | | { | |
| if (m_pending) | | if (m_pending) | |
| m_context->cancel (*this); | | m_context->cancel (*this); | |
| } | | } | |
| | | | |
| #endif // _event_h_ | | #endif // _event_h_ | |
| | | | |
End of changes. 21 change blocks. |
| 46 lines changed or deleted | | 181 lines changed or added | |
|