ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SIDPlayer/src/main.cpp
Revision: 1.2
Committed: 2000-09-19T15:34:10Z (24 years, 1 month ago) by cebix
Branch: MAIN
Changes since 1.1: +34 -649 lines
Log Message:
can now compile as a portable command-line SDL-based application

File Contents

# Content
1 /*
2 * main.cpp - SIDPlayer common routines
3 *
4 * SIDPlayer (C) Copyright 1996-2000 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 uint32 speed_flags; // Speed flags (1 bit/song)
52
53
54
55 /*
56 * Init everything
57 */
58
59 void InitAll(void)
60 {
61 PrefsInit(0, NULL);
62 MemoryInit();
63 SIDInit();
64 CPUInit();
65 }
66
67
68 /*
69 * Exit everything
70 */
71
72 void ExitAll(void)
73 {
74 CPUExit();
75 SIDExit();
76 MemoryExit();
77 PrefsExit();
78 }
79
80
81 /*
82 * Read PSID file header to buffer
83 */
84
85 bool LoadPSIDHeader(const char *file, uint8 *p)
86 {
87 // Read header
88 memset(p, 0, PSID_MAX_HEADER_LENGTH);
89 FILE *f = fopen(file, "rb");
90 if (f == NULL)
91 return false;
92 size_t actual = fread(p, 1, PSID_MAX_HEADER_LENGTH, f);
93 fclose(f);
94 return actual >= PSID_MIN_HEADER_LENGTH;
95 }
96
97
98 /*
99 * Check for PSID header
100 */
101
102 bool IsPSIDHeader(const uint8 *p)
103 {
104 // Check signature and version
105 uint32 id = read_psid_32(p, PSID_ID);
106 uint16 version = read_psid_16(p, PSID_VERSION);
107 return id == 0x50534944 && (version == 1 || version == 2);
108 }
109
110
111 /*
112 * Check whether file is a PSID file
113 */
114
115 bool IsPSIDFile(const char *file)
116 {
117 // Load header
118 uint8 header[PSID_MAX_HEADER_LENGTH];
119 if (!LoadPSIDHeader(file, header))
120 return false;
121
122 // Check header
123 return IsPSIDHeader(header);
124 }
125
126
127 /*
128 * Load PSID file for playing
129 */
130
131 bool LoadPSIDFile(const char *file)
132 {
133 // Open file
134 FILE *f = fopen(file, "rb");
135 if (f == NULL)
136 return false;
137
138 // Clear C64 RAM
139 MemoryClear();
140 psid_loaded = false;
141
142 // Load and check header
143 uint8 header[PSID_MAX_HEADER_LENGTH];
144 memset(header, 0, PSID_MAX_HEADER_LENGTH);
145 size_t actual = fread(header, 1, PSID_MAX_HEADER_LENGTH, f);
146 if (actual < PSID_MIN_HEADER_LENGTH || !IsPSIDHeader(header)) {
147 fclose(f);
148 return false;
149 }
150
151 // Extract data from header
152 number_of_songs = read_psid_16(header, PSID_NUMBER);
153 if (number_of_songs == 0)
154 number_of_songs = 1;
155 current_song = read_psid_16(header, PSID_DEFSONG);
156 if (current_song)
157 current_song--;
158 if (current_song >= number_of_songs)
159 current_song = 0;
160
161 init_adr = read_psid_16(header, PSID_INIT);
162 play_adr = read_psid_16(header, PSID_MAIN);
163
164 speed_flags = read_psid_32(header, PSID_SPEED);
165
166 #if defined(__BEOS__)
167 int32 sl = 32, dl = 64, state = 0;
168 convert_to_utf8(B_ISO1_CONVERSION, (char *)(header + PSID_NAME), &sl, module_name, &dl, &state);
169 sl = 32, dl = 64, state = 0;
170 convert_to_utf8(B_ISO1_CONVERSION, (char *)(header + PSID_AUTHOR), &sl, author_name, &dl, &state);
171 sl = 32, dl = 64, state = 0;
172 convert_to_utf8(B_ISO1_CONVERSION, (char *)(header + PSID_COPYRIGHT), &sl, copyright_info, &dl, &state);
173 module_name[63] = 0;
174 author_name[63] = 0;
175 copyright_info[63] = 0;
176 #else
177 strncpy(module_name, (char *)(header + PSID_NAME), 32);
178 strncpy(author_name, (char *)(header + PSID_AUTHOR), 32);
179 strncpy(copyright_info, (char *)(header + PSID_COPYRIGHT), 32);
180 module_name[32] = 0;
181 author_name[32] = 0;
182 copyright_info[32] = 0;
183 #endif
184
185 // Seek to start of module data
186 fseek(f, read_psid_16(header, PSID_LENGTH), SEEK_SET);
187
188 // Find load address
189 uint16 load_adr = read_psid_16(header, PSID_START);
190 if (load_adr == 0) { // Load address is at start of module data
191 uint8 lo = fgetc(f);
192 uint8 hi = fgetc(f);
193 load_adr = (hi << 8) | lo;
194 }
195 if (init_adr == 0) // Init routine address is equal to load address
196 init_adr = load_adr;
197
198 // Load module data to C64 RAM
199 fread(ram + load_adr, 1, RAM_SIZE - load_adr, f);
200 fclose(f);
201
202 // Select default song
203 SelectSong(current_song);
204
205 // Set replay routine address if not given in header
206 if (play_adr == 0) { // Replay routine address is given by interrupt vector
207 if (ram[1] & 2) // Kernal ROM switched in
208 play_adr = (ram[0x0315] << 8) | ram[0x0314];
209 else // Kernal ROM switched out
210 play_adr = (ram[0xffff] << 8) | ram[0xfffe];
211 }
212
213 // Everything OK
214 psid_loaded = true;
215 return true;
216 }
217
218
219 /*
220 * Select song for playing
221 */
222
223 void SelectSong(int num)
224 {
225 if (num >= number_of_songs)
226 num = 0;
227 current_song = num;
228
229 // Reset SID
230 SIDReset(0);
231
232 // Set replay frequency
233 int freq = 50;
234 if (num < 32)
235 freq = speed_flags & (1 << num) ? 60 : 50;
236 SIDSetReplayFreq(freq);
237 SIDAdjustSpeed(100);
238
239 // Execute init routine
240 CPUExecute(init_adr, current_song, 0, 0, 1000000);
241 }