ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SIDPlayer/src/main.cpp
Revision: 1.7
Committed: 2003-10-21T16:56:19Z (21 years ago) by cebix
Branch: MAIN
Changes since 1.6: +22 -13 lines
Log Message:
- play_adr is updated from the IRQ vector every time before the replay routine
  is called if it was 0 in the PSID header (this makes some tunes play
  correctly now)
- f(void) -> f() (this is C++, dammit!)

File Contents

# User Rev Content
1 cebix 1.1 /*
2 cebix 1.2 * main.cpp - SIDPlayer common routines
3 cebix 1.1 *
4 cebix 1.6 * SIDPlayer (C) Copyright 1996-2003 Christian Bauer
5 cebix 1.1 *
6     * This program is free software; you can redistribute it and/or modify
7     * it under the terms of the GNU General Public License as published by
8     * the Free Software Foundation; either version 2 of the License, or
9     * (at your option) any later version.
10     *
11     * This program is distributed in the hope that it will be useful,
12     * but WITHOUT ANY WARRANTY; without even the implied warranty of
13     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14     * GNU General Public License for more details.
15     *
16     * You should have received a copy of the GNU General Public License
17     * along with this program; if not, write to the Free Software
18     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19     */
20    
21     #include "sys.h"
22    
23     #include <stdio.h>
24     #include <string.h>
25 cebix 1.2
26     #if defined(__BEOS__)
27     #include <support/UTF8.h>
28     #endif
29 cebix 1.1
30     #include "main.h"
31     #include "prefs.h"
32     #include "mem.h"
33     #include "cpu.h"
34     #include "sid.h"
35     #include "psid.h"
36    
37    
38     // Global variables
39     uint32 f_rand_seed = 1;
40 cebix 1.2 int number_of_songs, current_song;
41     char module_name[64];
42     char author_name[64];
43     char copyright_info[64];
44 cebix 1.1
45     // Flag: PSID file loaded and ready
46     static bool psid_loaded = false;
47    
48     // Data from PSID header
49 cebix 1.7 static uint16 init_adr; // C64 init routine address
50     uint16 play_adr; // C64 replay routine address
51     static bool play_adr_from_irq_vec; // Flag: dynamically update play_adr from IRQ vector ($0314/$0315 or $fffe/$ffff)
52     static uint32 speed_flags; // Speed flags (1 bit/song)
53 cebix 1.1
54    
55    
56     /*
57     * Init everything
58     */
59    
60 cebix 1.5 void InitAll(int &argc, char **&argv)
61 cebix 1.1 {
62 cebix 1.3 PrefsInit(argc, argv);
63 cebix 1.1 MemoryInit();
64     SIDInit();
65     CPUInit();
66     }
67    
68    
69     /*
70     * Exit everything
71     */
72    
73 cebix 1.7 void ExitAll()
74 cebix 1.1 {
75     CPUExit();
76     SIDExit();
77     MemoryExit();
78     PrefsExit();
79     }
80    
81    
82     /*
83     * Read PSID file header to buffer
84     */
85    
86     bool LoadPSIDHeader(const char *file, uint8 *p)
87     {
88     // Read header
89     memset(p, 0, PSID_MAX_HEADER_LENGTH);
90 cebix 1.2 FILE *f = fopen(file, "rb");
91     if (f == NULL)
92 cebix 1.1 return false;
93 cebix 1.2 size_t actual = fread(p, 1, PSID_MAX_HEADER_LENGTH, f);
94     fclose(f);
95 cebix 1.1 return actual >= PSID_MIN_HEADER_LENGTH;
96     }
97    
98    
99     /*
100     * Check for PSID header
101     */
102    
103     bool IsPSIDHeader(const uint8 *p)
104     {
105     // Check signature and version
106     uint32 id = read_psid_32(p, PSID_ID);
107     uint16 version = read_psid_16(p, PSID_VERSION);
108 cebix 1.2 return id == 0x50534944 && (version == 1 || version == 2);
109 cebix 1.1 }
110    
111    
112     /*
113     * Check whether file is a PSID file
114     */
115    
116     bool IsPSIDFile(const char *file)
117     {
118     // Load header
119     uint8 header[PSID_MAX_HEADER_LENGTH];
120     if (!LoadPSIDHeader(file, header))
121     return false;
122    
123     // Check header
124     return IsPSIDHeader(header);
125     }
126    
127    
128     /*
129     * Load PSID file for playing
130     */
131    
132     bool LoadPSIDFile(const char *file)
133     {
134     // Open file
135 cebix 1.2 FILE *f = fopen(file, "rb");
136     if (f == NULL)
137 cebix 1.1 return false;
138    
139     // Clear C64 RAM
140     MemoryClear();
141     psid_loaded = false;
142    
143     // Load and check header
144     uint8 header[PSID_MAX_HEADER_LENGTH];
145 cebix 1.2 memset(header, 0, PSID_MAX_HEADER_LENGTH);
146     size_t actual = fread(header, 1, PSID_MAX_HEADER_LENGTH, f);
147     if (actual < PSID_MIN_HEADER_LENGTH || !IsPSIDHeader(header)) {
148     fclose(f);
149 cebix 1.1 return false;
150     }
151    
152     // Extract data from header
153     number_of_songs = read_psid_16(header, PSID_NUMBER);
154     if (number_of_songs == 0)
155     number_of_songs = 1;
156     current_song = read_psid_16(header, PSID_DEFSONG);
157     if (current_song)
158     current_song--;
159     if (current_song >= number_of_songs)
160     current_song = 0;
161    
162     init_adr = read_psid_16(header, PSID_INIT);
163     play_adr = read_psid_16(header, PSID_MAIN);
164 cebix 1.7 play_adr_from_irq_vec = (play_adr == 0);
165 cebix 1.1
166     speed_flags = read_psid_32(header, PSID_SPEED);
167    
168 cebix 1.2 #if defined(__BEOS__)
169 cebix 1.1 int32 sl = 32, dl = 64, state = 0;
170     convert_to_utf8(B_ISO1_CONVERSION, (char *)(header + PSID_NAME), &sl, module_name, &dl, &state);
171     sl = 32, dl = 64, state = 0;
172     convert_to_utf8(B_ISO1_CONVERSION, (char *)(header + PSID_AUTHOR), &sl, author_name, &dl, &state);
173     sl = 32, dl = 64, state = 0;
174     convert_to_utf8(B_ISO1_CONVERSION, (char *)(header + PSID_COPYRIGHT), &sl, copyright_info, &dl, &state);
175     module_name[63] = 0;
176     author_name[63] = 0;
177     copyright_info[63] = 0;
178 cebix 1.2 #else
179     strncpy(module_name, (char *)(header + PSID_NAME), 32);
180     strncpy(author_name, (char *)(header + PSID_AUTHOR), 32);
181     strncpy(copyright_info, (char *)(header + PSID_COPYRIGHT), 32);
182     module_name[32] = 0;
183     author_name[32] = 0;
184     copyright_info[32] = 0;
185     #endif
186 cebix 1.1
187     // Seek to start of module data
188 cebix 1.2 fseek(f, read_psid_16(header, PSID_LENGTH), SEEK_SET);
189 cebix 1.1
190     // Find load address
191     uint16 load_adr = read_psid_16(header, PSID_START);
192     if (load_adr == 0) { // Load address is at start of module data
193 cebix 1.2 uint8 lo = fgetc(f);
194     uint8 hi = fgetc(f);
195 cebix 1.1 load_adr = (hi << 8) | lo;
196     }
197     if (init_adr == 0) // Init routine address is equal to load address
198     init_adr = load_adr;
199    
200     // Load module data to C64 RAM
201 cebix 1.2 fread(ram + load_adr, 1, RAM_SIZE - load_adr, f);
202     fclose(f);
203 cebix 1.1
204     // Select default song
205     SelectSong(current_song);
206    
207     // Everything OK
208     psid_loaded = true;
209     return true;
210 cebix 1.4 }
211    
212    
213     /*
214     * PSID file loaded and ready?
215     */
216    
217 cebix 1.7 bool IsPSIDLoaded()
218 cebix 1.4 {
219     return psid_loaded;
220 cebix 1.1 }
221    
222    
223     /*
224     * Select song for playing
225     */
226    
227     void SelectSong(int num)
228     {
229     if (num >= number_of_songs)
230     num = 0;
231     current_song = num;
232    
233     // Reset SID
234     SIDReset(0);
235    
236     // Set replay frequency
237     int freq = 50;
238     if (num < 32)
239     freq = speed_flags & (1 << num) ? 60 : 50;
240     SIDSetReplayFreq(freq);
241     SIDAdjustSpeed(100);
242    
243     // Execute init routine
244     CPUExecute(init_adr, current_song, 0, 0, 1000000);
245 cebix 1.7 }
246    
247    
248     /*
249     * Update play_adr from IRQ vector if necessary
250     */
251    
252     void UpdatePlayAdr()
253     {
254     if (play_adr_from_irq_vec) {
255     if (ram[1] & 2) // Kernal ROM switched in
256     play_adr = (ram[0x0315] << 8) | ram[0x0314];
257     else // Kernal ROM switched out
258     play_adr = (ram[0xffff] << 8) | ram[0xfffe];
259     }
260 cebix 1.1 }