ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SIDPlayer/src/main.cpp
Revision: 1.8
Committed: 2004-01-12T15:15:49Z (20 years, 2 months ago) by cebix
Branch: MAIN
CVS Tags: HEAD
Changes since 1.7: +1 -1 lines
Log Message:
Happy New Year!

File Contents

# Content
1 /*
2 * main.cpp - SIDPlayer common routines
3 *
4 * SIDPlayer (C) Copyright 1996-2004 Christian Bauer
5 *
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
26 #if defined(__BEOS__)
27 #include <support/UTF8.h>
28 #endif
29
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 int number_of_songs, current_song;
41 char module_name[64];
42 char author_name[64];
43 char copyright_info[64];
44
45 // Flag: PSID file loaded and ready
46 static bool psid_loaded = false;
47
48 // Data from PSID header
49 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
54
55
56 /*
57 * Init everything
58 */
59
60 void InitAll(int &argc, char **&argv)
61 {
62 PrefsInit(argc, argv);
63 MemoryInit();
64 SIDInit();
65 CPUInit();
66 }
67
68
69 /*
70 * Exit everything
71 */
72
73 void ExitAll()
74 {
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 FILE *f = fopen(file, "rb");
91 if (f == NULL)
92 return false;
93 size_t actual = fread(p, 1, PSID_MAX_HEADER_LENGTH, f);
94 fclose(f);
95 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 return id == 0x50534944 && (version == 1 || version == 2);
109 }
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 FILE *f = fopen(file, "rb");
136 if (f == NULL)
137 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 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 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 play_adr_from_irq_vec = (play_adr == 0);
165
166 speed_flags = read_psid_32(header, PSID_SPEED);
167
168 #if defined(__BEOS__)
169 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 #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
187 // Seek to start of module data
188 fseek(f, read_psid_16(header, PSID_LENGTH), SEEK_SET);
189
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 uint8 lo = fgetc(f);
194 uint8 hi = fgetc(f);
195 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 fread(ram + load_adr, 1, RAM_SIZE - load_adr, f);
202 fclose(f);
203
204 // Select default song
205 SelectSong(current_song);
206
207 // Everything OK
208 psid_loaded = true;
209 return true;
210 }
211
212
213 /*
214 * PSID file loaded and ready?
215 */
216
217 bool IsPSIDLoaded()
218 {
219 return psid_loaded;
220 }
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 }
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 }