1 /*
2  * /home/ms/files/source/libsidtune/RCS/SidTune.h,v
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, write to the Free Software
16  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  */
18 
19 #ifndef SIDTUNE_H
20 #define SIDTUNE_H
21 
22 
23 #include "sidtypes.h"
24 #include "Buffer.h"
25 #include "SmartPtr.h"
26 
27 #include <fstream>
28 
29 
30 const uint_least16_t SIDTUNE_MAX_SONGS = 256;
31 // Also PSID file format limit.
32 
33 const uint_least16_t SIDTUNE_MAX_CREDIT_STRINGS = 10;
34 const uint_least16_t SIDTUNE_MAX_CREDIT_STRLEN = 80+1;
35 // 80 characters plus terminating zero.
36 
37 const uint_least32_t SIDTUNE_MAX_MEMORY = 65536;
38 const uint_least32_t SIDTUNE_MAX_FILELEN = 65536+2+0x7C;
39 // C64KB+LOAD+PSID
40 
41 const int SIDTUNE_SPEED_VBI = 0;        // Vertical-Blanking-Interrupt
42 const int SIDTUNE_SPEED_CIA_1A = 60;    // CIA 1 Timer A
43 
44 const int SIDTUNE_CLOCK_UNKNOWN = 0x00;
45 const int SIDTUNE_CLOCK_PAL     = 0x01; // These are also used in the
46 const int SIDTUNE_CLOCK_NTSC    = 0x02; // emulator engine!
47 const int SIDTUNE_CLOCK_ANY     = (SIDTUNE_CLOCK_PAL | SIDTUNE_CLOCK_NTSC);
48 
49 const int SIDTUNE_SIDMODEL_UNKNOWN = 0x00;
50 const int SIDTUNE_SIDMODEL_6581    = 0x01; // These are also used in the
51 const int SIDTUNE_SIDMODEL_8580    = 0x02; // emulator engine!
52 const int SIDTUNE_SIDMODEL_ANY     = (SIDTUNE_SIDMODEL_6581 | SIDTUNE_SIDMODEL_8580);
53 
54 const int SIDTUNE_COMPATIBILITY_C64   = 0x00; // File is C64 compatible
55 const int SIDTUNE_COMPATIBILITY_PSID  = 0x01; // File is PSID specific
56 const int SIDTUNE_COMPATIBILITY_R64   = 0x02; // File is Real C64 only
57 const int SIDTUNE_COMPATIBILITY_BASIC = 0x03; // File requires C64 Basic
58 
59 
60 // Required to export template
61 #ifndef _SidTune_cpp_
62 extern
63 #endif
64 template class SID_EXTERN Buffer_sidtt<const uint_least8_t>;
65 
66 struct SidTuneInfo
67 {
68     // An instance of this structure is used to transport values to
69     // and from SidTune objects.
70 
71     // You must read (i.e. activate) sub-song specific information
72     // via:
73     //        const SidTuneInfo& tuneInfo = SidTune[songNumber];
74     //        const SidTuneInfo& tuneInfo = SidTune.getInfo();
75     //        void SidTune.getInfo(tuneInfo&);
76 
77     // Consider the following fields as read-only, because the SidTune class
78     // does not provide an implementation of: bool setInfo(const SidTuneInfo&).
79     // Currently, the only way to get the class to accept values which
80     // are written to these fields is by creating a derived class.
81 
82     const char* formatString;   // the name of the identified file format
83     const char* statusString;   // error/status message of last operation
84 
85     const char* speedString;    // describing the speed a song is running at
86 
87     uint_least16_t loadAddr;
88     uint_least16_t initAddr;
89     uint_least16_t playAddr;
90 
91     uint_least16_t songs;
92     uint_least16_t startSong;
93 
94     // The SID chip base address(es) used by the sidtune.
95     uint_least16_t sidChipBase1;    // 0xD400 (normal, 1st SID)
96     uint_least16_t sidChipBase2;    // 0xD?00 (2nd SID) or 0 (no 2nd SID)
97 
98     // Available after song initialization.
99     //
100     uint_least16_t currentSong;    // the one that has been initialized
101     uint_least8_t songSpeed;       // intended speed, see top
102     uint_least8_t clockSpeed;      // -"-
103     uint_least8_t relocStartPage;  // First available page for relocation
104     uint_least8_t relocPages;      // Number of pages available for relocation
105     bool musPlayer;                // whether Sidplayer routine has been installed
106     int  sidModel;                 // Sid Model required for this sid
107     int  compatibility;            // compatibility requirements
108     bool fixLoad;                  // whether load address might be duplicate
109     uint_least16_t songLength;     // --- not yet supported ---
110     //
111     // Song title, credits, ...
112     // 0 = Title, 1 = Author, 2 = Copyright/Publisher
113     //
114     uint_least8_t numberOfInfoStrings;  // the number of available text info lines
115     char* infoString[SIDTUNE_MAX_CREDIT_STRINGS];
116     //
117     uint_least16_t numberOfCommentStrings;    // --- not yet supported ---
118     char ** commentString;                // --- not yet supported ---
119     //
120     uint_least32_t dataFileLen;    // length of single-file sidtune file
121     uint_least32_t c64dataLen;     // length of raw C64 data without load address
122     char* path;                    // path to sidtune files; "", if cwd
123     char* dataFileName;            // a first file: e.g. "foo.c64"; "", if none
124     char* infoFileName;            // a second file: e.g. "foo.sid"; "", if none
125     //
126 };
127 
128 
129 class SID_EXTERN SidTune
130 {
131  private:
132     typedef enum
133     {
134         LOAD_NOT_MINE = 0,
135         LOAD_OK,
136         LOAD_ERROR
137     } LoadStatus;
138 
139  public:  // ----------------------------------------------------------------
140 
141     // If your opendir() and readdir()->d_name return path names
142     // that contain the forward slash (/) as file separator, but
143     // your operating system uses a different character, there are
144     // extra functions that can deal with this special case. Set
145     // separatorIsSlash to true if you like path names to be split
146     // correctly.
147     // You do not need these extra functions if your systems file
148     // separator is the forward slash.
149     //
150     // Load a sidtune from a file.
151     //
152     // To retrieve data from standard input pass in filename "-".
153     // If you want to override the default filename extensions use this
154     // contructor. Please note, that if the specified ``sidTuneFileName''
155     // does exist and the loader is able to determine its file format,
156     // this function does not try to append any file name extension.
157     // See ``sidtune.cpp'' for the default list of file name extensions.
158     // You can specific ``sidTuneFileName = 0'', if you do not want to
159     // load a sidtune. You can later load one with open().
160     SidTune(const char* fileName, const char **fileNameExt = 0,
161             const bool separatorIsSlash = false);
162 
163     // Load a single-file sidtune from a memory buffer.
164     // Currently supported: PSID format
165     SidTune(const uint_least8_t* oneFileFormatSidtune, const uint_least32_t sidtuneLength);
166 
167     virtual ~SidTune();
168 
169     // The sidTune class does not copy the list of file name extensions,
170     // so make sure you keep it. If the provided pointer is 0, the
171     // default list will be activated. This is a static list which
172     // is used by all SidTune objects.
173     void setFileNameExtensions(const char **fileNameExt);
174 
175     // Load a sidtune into an existing object.
176     // From a file.
177     bool load(const char* fileName, const bool separatorIsSlash = false);
178 
179     // From a buffer.
180     bool read(const uint_least8_t* sourceBuffer, const uint_least32_t bufferLen);
181 
182     // Select sub-song (0 = default starting song)
183     // and retrieve active song information.
184     const SidTuneInfo& operator[](const uint_least16_t songNum);
185 
186     // Select sub-song (0 = default starting song)
187     // and return active song number out of [1,2,..,SIDTUNE_MAX_SONGS].
188     uint_least16_t selectSong(const uint_least16_t songNum);
189 
190     // Retrieve sub-song specific information.
191     // Beware! Still member-wise copy!
192     const SidTuneInfo& getInfo();
193 
194     // Get a copy of sub-song specific information.
195     // Beware! Still member-wise copy!
196     void getInfo(SidTuneInfo&);
197 
198     // Determine current state of object (true = okay, false = error).
199     // Upon error condition use ``getInfo'' to get a descriptive
200     // text string in ``SidTuneInfo.statusString''.
201     operator bool()  { return status; }
getStatus()202     bool getStatus()  { return status; }
203 
204     // Whether sidtune uses two SID chips.
isStereo()205     bool isStereo()
206     {
207         return (info.sidChipBase1!=0 && info.sidChipBase2!=0);
208     }
209 
210     // Copy sidtune into C64 memory (64 KB).
211     bool placeSidTuneInC64mem(uint_least8_t* c64buf);
212 
213     // --- file save & format conversion ---
214 
215     // These functions work for any successfully created object.
216     // overWriteFlag: true  = Overwrite existing file.
217     //                  false = Default, return error when file already
218     //                          exists.
219     // One could imagine an "Are you sure ?"-checkbox before overwriting
220     // any file.
221     // returns: true = Successful, false = Error condition.
222     bool saveC64dataFile( const char* destFileName, const bool overWriteFlag = false );
223     bool saveSIDfile( const char* destFileName, const bool overWriteFlag = false );
224     bool savePSIDfile( const char* destFileName, const bool overWriteFlag = false );
225 
226     // This function can be used to remove a duplicate C64 load address in
227     // the C64 data (example: FE 0F 00 10 4C ...). A duplicate load address
228     // of offset 0x02 is indicated by the ``fixLoad'' flag in the SidTuneInfo
229     // structure.
230     //
231     // The ``force'' flag here can be used to remove the first load address
232     // and set new INIT/PLAY addresses regardless of whether a duplicate
233     // load address has been detected and indicated by ``fixLoad''.
234     // For instance, some position independent sidtunes contain a load address
235     // of 0xE000, but are loaded to 0x0FFE and call the player code at 0x1000.
236     //
237     // Do not forget to save the sidtune file.
238     void fixLoadAddress(const bool force = false, uint_least16_t initAddr = 0,
239                         uint_least16_t playAddr = 0);
240 
241     // Does not affect status of object, and therefore can be used
242     // to load files. Error string is put into info.statusString, though.
243     bool loadFile(const char* fileName, Buffer_sidtt<const uint_least8_t>& bufferRef);
244 
245     bool saveToOpenFile( std::ofstream& toFile, const uint_least8_t* buffer, uint_least32_t bufLen );
246 
247  protected:  // -------------------------------------------------------------
248 
249     SidTuneInfo info;
250     bool status;
251 
252     uint_least8_t songSpeed[SIDTUNE_MAX_SONGS];
253     uint_least8_t clockSpeed[SIDTUNE_MAX_SONGS];
254     uint_least16_t songLength[SIDTUNE_MAX_SONGS];
255 
256     // holds text info from the format headers etc.
257     char infoString[SIDTUNE_MAX_CREDIT_STRINGS][SIDTUNE_MAX_CREDIT_STRLEN];
258 
259     // See instructions at top.
260     bool isSlashedFileName;
261 
262     // For files with header: offset to real data
263     uint_least32_t fileOffset;
264 
265     // Needed for MUS/STR player installation.
266     uint_least16_t musDataLen;
267 
268     Buffer_sidtt<const uint_least8_t> cache;
269 
270     // Filename extensions to append for various file types.
271     static const char** fileNameExtensions;
272 
273     // --- protected member functions ---
274 
275     // Convert 32-bit PSID-style speed word to internal tables.
276     void convertOldStyleSpeedToTables(uint_least32_t speed,
277          int clock = SIDTUNE_CLOCK_PAL);
278 
279     virtual int convertPetsciiToAscii (SmartPtr_sidtt<const uint_least8_t>&, char*);
280 
281     // Check compatibility details are sensible
282     bool checkCompatibility(void);
283     // Check for valid relocation information
284     bool checkRelocInfo(void);
285     // Common address resolution procedure
286     bool resolveAddrs(const uint_least8_t* c64data);
287 
288     // Support for various file formats.
289 
290     virtual LoadStatus PSID_fileSupport    (Buffer_sidtt<const uint_least8_t>& dataBuf);
291     virtual bool       PSID_fileSupportSave(std::ofstream& toFile, const uint_least8_t* dataBuffer);
292 
293     virtual LoadStatus SID_fileSupport     (Buffer_sidtt<const uint_least8_t>& dataBuf,
294                                             Buffer_sidtt<const uint_least8_t>& sidBuf);
295     virtual bool       SID_fileSupportSave (std::ofstream& toFile);
296 
297     virtual LoadStatus MUS_fileSupport     (Buffer_sidtt<const uint_least8_t>& musBuf,
298                                             Buffer_sidtt<const uint_least8_t>& strBuf);
299     LoadStatus         MUS_load            (Buffer_sidtt<const uint_least8_t>& musBuf,
300                                             bool init = false);
301     LoadStatus         MUS_load            (Buffer_sidtt<const uint_least8_t>& musBuf,
302                                             Buffer_sidtt<const uint_least8_t>& strBuf,
303                                             bool init = false);
304     virtual bool       MUS_detect          (const void* buffer, const uint_least32_t bufLen,
305                                             uint_least32_t& voice3Index);
306     virtual bool       MUS_mergeParts      (Buffer_sidtt<const uint_least8_t>& musBuf,
307                                             Buffer_sidtt<const uint_least8_t>& strBuf);
308     virtual void       MUS_setPlayerAddress();
309     virtual void       MUS_installPlayer   (uint_least8_t *c64buf);
310 
311     virtual LoadStatus INFO_fileSupport    (Buffer_sidtt<const uint_least8_t>& dataBuf,
312                                             Buffer_sidtt<const uint_least8_t>& infoBuf);
313     virtual LoadStatus PRG_fileSupport     (const char* fileName,
314                                             Buffer_sidtt<const uint_least8_t>& dataBuf);
315     virtual LoadStatus X00_fileSupport     (const char* fileName,
316                                             Buffer_sidtt<const uint_least8_t>& dataBuf);
317 
318     // Error and status message strings.
319     static const char* txt_songNumberExceed;
320     static const char* txt_empty;
321     static const char* txt_unrecognizedFormat;
322     static const char* txt_noDataFile;
323     static const char* txt_notEnoughMemory;
324     static const char* txt_cantLoadFile;
325     static const char* txt_cantOpenFile;
326     static const char* txt_fileTooLong;
327     static const char* txt_dataTooLong;
328     static const char* txt_cantCreateFile;
329     static const char* txt_fileIoError;
330     static const char* txt_VBI;
331     static const char* txt_CIA;
332     static const char* txt_noErrors;
333     static const char* txt_na;
334     static const char* txt_badAddr;
335     static const char* txt_badReloc;
336     static const char* txt_corrupt;
337 
338  private:  // ---------------------------------------------------------------
339 
340     void init();
341     void cleanup();
342 #if !defined(SIDTUNE_NO_STDIN_LOADER)
343     void getFromStdIn();
344 #endif
345     void getFromFiles(const char* name);
346 
347     void deleteFileNameCopies();
348 
349     // Try to retrieve single-file sidtune from specified buffer.
350     void getFromBuffer(const uint_least8_t* const buffer, const uint_least32_t bufferLen);
351 
352     // Cache the data of a single-file or two-file sidtune and its
353     // corresponding file names.
354     bool acceptSidTune(const char* dataFileName, const char* infoFileName,
355                        Buffer_sidtt<const uint_least8_t>& buf);
356 
357     bool createNewFileName(Buffer_sidtt<char>& destString,
358                            const char* sourceName, const char* sourceExt);
359 
360     int  decompressPP20(Buffer_sidtt<const uint_least8_t>& buf);
361 
362  private:    // prevent copying
363     SidTune(const SidTune&);
364     SidTune& operator=(SidTune&);
365 };
366 
367 #endif  /* SIDTUNE_H */
368