Mercurial > hg > xmms-sid
comparison src/xmms-sid.c @ 660:b0743dc9165d
Change tabs to 4 spaces, everywhere.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Wed, 02 Apr 2008 22:10:05 +0300 |
parents | 04ea91a61225 |
children | f22a708d29fd |
comparison
equal
deleted
inserted
replaced
659:04ea91a61225 | 660:b0743dc9165d |
---|---|
56 /* | 56 /* |
57 * List of players and links to their functions | 57 * List of players and links to their functions |
58 */ | 58 */ |
59 static const xs_player_t xs_playerlist[] = { | 59 static const xs_player_t xs_playerlist[] = { |
60 #ifdef HAVE_SIDPLAY1 | 60 #ifdef HAVE_SIDPLAY1 |
61 {XS_ENG_SIDPLAY1, | 61 {XS_ENG_SIDPLAY1, |
62 xs_sidplay1_probe, | 62 xs_sidplay1_probe, |
63 xs_sidplay1_init, xs_sidplay1_close, | 63 xs_sidplay1_init, xs_sidplay1_close, |
64 xs_sidplay1_initsong, xs_sidplay1_fillbuffer, | 64 xs_sidplay1_initsong, xs_sidplay1_fillbuffer, |
65 xs_sidplay1_load, xs_sidplay1_delete, | 65 xs_sidplay1_load, xs_sidplay1_delete, |
66 xs_sidplay1_getinfo, xs_sidplay1_updateinfo, | 66 xs_sidplay1_getinfo, xs_sidplay1_updateinfo, |
67 NULL | 67 NULL |
68 }, | 68 }, |
69 #endif | 69 #endif |
70 #ifdef HAVE_SIDPLAY2 | 70 #ifdef HAVE_SIDPLAY2 |
71 {XS_ENG_SIDPLAY2, | 71 {XS_ENG_SIDPLAY2, |
72 xs_sidplay2_probe, | 72 xs_sidplay2_probe, |
73 xs_sidplay2_init, xs_sidplay2_close, | 73 xs_sidplay2_init, xs_sidplay2_close, |
74 xs_sidplay2_initsong, xs_sidplay2_fillbuffer, | 74 xs_sidplay2_initsong, xs_sidplay2_fillbuffer, |
75 xs_sidplay2_load, xs_sidplay2_delete, | 75 xs_sidplay2_load, xs_sidplay2_delete, |
76 xs_sidplay2_getinfo, xs_sidplay2_updateinfo, | 76 xs_sidplay2_getinfo, xs_sidplay2_updateinfo, |
77 xs_sidplay2_flush | 77 xs_sidplay2_flush |
78 }, | 78 }, |
79 #endif | 79 #endif |
80 }; | 80 }; |
81 | 81 |
82 const gint xs_nplayerlist = (sizeof(xs_playerlist) / sizeof(xs_playerlist[0])); | 82 const gint xs_nplayerlist = (sizeof(xs_playerlist) / sizeof(xs_playerlist[0])); |
83 | 83 |
91 | 91 |
92 static GtkWidget *xs_subctrl = NULL; | 92 static GtkWidget *xs_subctrl = NULL; |
93 static GtkObject *xs_subctrl_adj = NULL; | 93 static GtkObject *xs_subctrl_adj = NULL; |
94 XS_MUTEX(xs_subctrl); | 94 XS_MUTEX(xs_subctrl); |
95 | 95 |
96 void xs_subctrl_close(void); | 96 void xs_subctrl_close(void); |
97 void xs_subctrl_update(void); | 97 void xs_subctrl_update(void); |
98 | 98 |
99 | 99 |
100 /* | 100 /* |
101 * Error messages | 101 * Error messages |
102 */ | 102 */ |
103 void xs_error(const char *fmt, ...) | 103 void xs_error(const char *fmt, ...) |
104 { | 104 { |
105 va_list ap; | 105 va_list ap; |
106 fprintf(stderr, "XMMS-SID: "); | 106 fprintf(stderr, "XMMS-SID: "); |
107 va_start(ap, fmt); | 107 va_start(ap, fmt); |
108 vfprintf(stderr, fmt, ap); | 108 vfprintf(stderr, fmt, ap); |
109 va_end(ap); | 109 va_end(ap); |
110 } | 110 } |
111 | 111 |
112 #ifndef DEBUG_NP | 112 #ifndef DEBUG_NP |
113 void XSDEBUG(const char *fmt, ...) | 113 void XSDEBUG(const char *fmt, ...) |
114 { | 114 { |
115 #ifdef DEBUG | 115 #ifdef DEBUG |
116 va_list ap; | 116 va_list ap; |
117 fprintf(stderr, "XSDEBUG: "); | 117 fprintf(stderr, "XSDEBUG: "); |
118 va_start(ap, fmt); | 118 va_start(ap, fmt); |
119 vfprintf(stderr, fmt, ap); | 119 vfprintf(stderr, fmt, ap); |
120 va_end(ap); | 120 va_end(ap); |
121 #endif | 121 #endif |
122 } | 122 } |
123 #endif | 123 #endif |
124 | 124 |
125 | 125 |
126 /* | 126 /* |
127 * Initialization functions | 127 * Initialization functions |
128 */ | 128 */ |
129 void xs_reinit(void) | 129 void xs_reinit(void) |
130 { | 130 { |
131 gint iPlayer; | 131 gint iPlayer; |
132 gboolean isInitialized; | 132 gboolean isInitialized; |
133 | 133 |
134 /* Stop playing, if we are */ | 134 /* Stop playing, if we are */ |
135 XS_MUTEX_LOCK(xs_status); | 135 XS_MUTEX_LOCK(xs_status); |
136 if (xs_status.isPlaying) { | 136 if (xs_status.isPlaying) { |
137 XS_MUTEX_UNLOCK(xs_status); | 137 XS_MUTEX_UNLOCK(xs_status); |
138 xs_stop(); | 138 xs_stop(); |
139 } else { | 139 } else { |
140 XS_MUTEX_UNLOCK(xs_status); | 140 XS_MUTEX_UNLOCK(xs_status); |
141 } | 141 } |
142 | 142 |
143 XS_MUTEX_LOCK(xs_status); | 143 XS_MUTEX_LOCK(xs_status); |
144 XS_MUTEX_LOCK(xs_cfg); | 144 XS_MUTEX_LOCK(xs_cfg); |
145 | 145 |
146 /* Initialize status and sanitize configuration */ | 146 /* Initialize status and sanitize configuration */ |
147 memset(&xs_status, 0, sizeof(xs_status)); | 147 memset(&xs_status, 0, sizeof(xs_status)); |
148 | 148 |
149 if (xs_cfg.audioFrequency < 8000) | 149 if (xs_cfg.audioFrequency < 8000) |
150 xs_cfg.audioFrequency = 8000; | 150 xs_cfg.audioFrequency = 8000; |
151 | 151 |
152 if (xs_cfg.oversampleFactor < XS_MIN_OVERSAMPLE) | 152 if (xs_cfg.oversampleFactor < XS_MIN_OVERSAMPLE) |
153 xs_cfg.oversampleFactor = XS_MIN_OVERSAMPLE; | 153 xs_cfg.oversampleFactor = XS_MIN_OVERSAMPLE; |
154 else if (xs_cfg.oversampleFactor > XS_MAX_OVERSAMPLE) | 154 else if (xs_cfg.oversampleFactor > XS_MAX_OVERSAMPLE) |
155 xs_cfg.oversampleFactor = XS_MAX_OVERSAMPLE; | 155 xs_cfg.oversampleFactor = XS_MAX_OVERSAMPLE; |
156 | 156 |
157 if (xs_cfg.audioChannels != XS_CHN_MONO) | 157 if (xs_cfg.audioChannels != XS_CHN_MONO) |
158 xs_cfg.oversampleEnable = FALSE; | 158 xs_cfg.oversampleEnable = FALSE; |
159 | 159 |
160 xs_status.audioFrequency = xs_cfg.audioFrequency; | 160 xs_status.audioFrequency = xs_cfg.audioFrequency; |
161 xs_status.audioBitsPerSample = xs_cfg.audioBitsPerSample; | 161 xs_status.audioBitsPerSample = xs_cfg.audioBitsPerSample; |
162 xs_status.audioChannels = xs_cfg.audioChannels; | 162 xs_status.audioChannels = xs_cfg.audioChannels; |
163 xs_status.audioFormat = -1; | 163 xs_status.audioFormat = -1; |
164 xs_status.oversampleEnable = xs_cfg.oversampleEnable; | 164 xs_status.oversampleEnable = xs_cfg.oversampleEnable; |
165 xs_status.oversampleFactor = xs_cfg.oversampleFactor; | 165 xs_status.oversampleFactor = xs_cfg.oversampleFactor; |
166 | 166 |
167 /* Try to initialize emulator engine */ | 167 /* Try to initialize emulator engine */ |
168 XSDEBUG("initializing emulator engine #%i...\n", xs_cfg.playerEngine); | 168 XSDEBUG("initializing emulator engine #%i...\n", xs_cfg.playerEngine); |
169 | 169 |
170 iPlayer = 0; | 170 iPlayer = 0; |
171 isInitialized = FALSE; | 171 isInitialized = FALSE; |
172 while ((iPlayer < xs_nplayerlist) && !isInitialized) { | 172 while ((iPlayer < xs_nplayerlist) && !isInitialized) { |
173 if (xs_playerlist[iPlayer].plrIdent == xs_cfg.playerEngine) { | 173 if (xs_playerlist[iPlayer].plrIdent == xs_cfg.playerEngine) { |
174 if (xs_playerlist[iPlayer].plrInit(&xs_status)) { | 174 if (xs_playerlist[iPlayer].plrInit(&xs_status)) { |
175 isInitialized = TRUE; | 175 isInitialized = TRUE; |
176 xs_status.sidPlayer = (xs_player_t *) & xs_playerlist[iPlayer]; | 176 xs_status.sidPlayer = (xs_player_t *) & xs_playerlist[iPlayer]; |
177 } | 177 } |
178 } | 178 } |
179 iPlayer++; | 179 iPlayer++; |
180 } | 180 } |
181 | 181 |
182 XSDEBUG("init#1: %s, %i\n", (isInitialized) ? "OK" : "FAILED", iPlayer); | 182 XSDEBUG("init#1: %s, %i\n", (isInitialized) ? "OK" : "FAILED", iPlayer); |
183 | 183 |
184 iPlayer = 0; | 184 iPlayer = 0; |
185 while ((iPlayer < xs_nplayerlist) && !isInitialized) { | 185 while ((iPlayer < xs_nplayerlist) && !isInitialized) { |
186 if (xs_playerlist[iPlayer].plrInit(&xs_status)) { | 186 if (xs_playerlist[iPlayer].plrInit(&xs_status)) { |
187 isInitialized = TRUE; | 187 isInitialized = TRUE; |
188 xs_status.sidPlayer = (xs_player_t *) & xs_playerlist[iPlayer]; | 188 xs_status.sidPlayer = (xs_player_t *) & xs_playerlist[iPlayer]; |
189 xs_cfg.playerEngine = xs_playerlist[iPlayer].plrIdent; | 189 xs_cfg.playerEngine = xs_playerlist[iPlayer].plrIdent; |
190 } else | 190 } else |
191 iPlayer++; | 191 iPlayer++; |
192 } | 192 } |
193 | 193 |
194 XSDEBUG("init#2: %s, %i\n", (isInitialized) ? "OK" : "FAILED", iPlayer); | 194 XSDEBUG("init#2: %s, %i\n", (isInitialized) ? "OK" : "FAILED", iPlayer); |
195 | 195 |
196 | 196 |
197 /* Get settings back, in case the chosen emulator backend changed them */ | 197 /* Get settings back, in case the chosen emulator backend changed them */ |
198 xs_cfg.audioFrequency = xs_status.audioFrequency; | 198 xs_cfg.audioFrequency = xs_status.audioFrequency; |
199 xs_cfg.audioBitsPerSample = xs_status.audioBitsPerSample; | 199 xs_cfg.audioBitsPerSample = xs_status.audioBitsPerSample; |
200 xs_cfg.audioChannels = xs_status.audioChannels; | 200 xs_cfg.audioChannels = xs_status.audioChannels; |
201 xs_cfg.oversampleEnable = xs_status.oversampleEnable; | 201 xs_cfg.oversampleEnable = xs_status.oversampleEnable; |
202 | 202 |
203 XS_MUTEX_UNLOCK(xs_status); | 203 XS_MUTEX_UNLOCK(xs_status); |
204 XS_MUTEX_UNLOCK(xs_cfg); | 204 XS_MUTEX_UNLOCK(xs_cfg); |
205 | 205 |
206 /* Initialize song-length database */ | 206 /* Initialize song-length database */ |
207 xs_songlen_close(); | 207 xs_songlen_close(); |
208 if (xs_cfg.songlenDBEnable && (xs_songlen_init() != 0)) { | 208 if (xs_cfg.songlenDBEnable && (xs_songlen_init() != 0)) { |
209 xs_error("Error initializing song-length database!\n"); | 209 xs_error("Error initializing song-length database!\n"); |
210 } | 210 } |
211 | 211 |
212 /* Initialize STIL database */ | 212 /* Initialize STIL database */ |
213 xs_stil_close(); | 213 xs_stil_close(); |
214 if (xs_cfg.stilDBEnable && (xs_stil_init() != 0)) { | 214 if (xs_cfg.stilDBEnable && (xs_stil_init() != 0)) { |
215 xs_error("Error initializing STIL database!\n"); | 215 xs_error("Error initializing STIL database!\n"); |
216 } | 216 } |
217 | 217 |
218 } | 218 } |
219 | 219 |
220 | 220 |
221 /* | 221 /* |
222 * Initialize XMMS-SID | 222 * Initialize XMMS-SID |
223 */ | 223 */ |
224 void xs_init(void) | 224 void xs_init(void) |
225 { | 225 { |
226 XSDEBUG("xs_init()\n"); | 226 XSDEBUG("xs_init()\n"); |
227 | 227 |
228 /* Initialize and get configuration */ | 228 /* Initialize and get configuration */ |
229 xs_init_configuration(); | 229 xs_init_configuration(); |
230 xs_read_configuration(); | 230 xs_read_configuration(); |
231 | 231 |
232 /* Initialize subsystems */ | 232 /* Initialize subsystems */ |
233 xs_reinit(); | 233 xs_reinit(); |
234 | 234 |
235 XSDEBUG("OK\n"); | 235 XSDEBUG("OK\n"); |
236 } | 236 } |
237 | 237 |
238 | 238 |
239 /* | 239 /* |
240 * Shut down XMMS-SID | 240 * Shut down XMMS-SID |
241 */ | 241 */ |
242 void xs_close(void) | 242 void xs_close(void) |
243 { | 243 { |
244 XSDEBUG("xs_close(): shutting down...\n"); | 244 XSDEBUG("xs_close(): shutting down...\n"); |
245 | 245 |
246 /* Stop playing, free structures */ | 246 /* Stop playing, free structures */ |
247 xs_stop(); | 247 xs_stop(); |
248 | 248 |
249 xs_tuneinfo_free(xs_status.tuneInfo); | 249 xs_tuneinfo_free(xs_status.tuneInfo); |
250 xs_status.tuneInfo = NULL; | 250 xs_status.tuneInfo = NULL; |
251 xs_status.sidPlayer->plrDeleteSID(&xs_status); | 251 xs_status.sidPlayer->plrDeleteSID(&xs_status); |
252 xs_status.sidPlayer->plrClose(&xs_status); | 252 xs_status.sidPlayer->plrClose(&xs_status); |
253 | 253 |
254 xs_songlen_close(); | 254 xs_songlen_close(); |
255 xs_stil_close(); | 255 xs_stil_close(); |
256 | 256 |
257 XSDEBUG("shutdown finished.\n"); | 257 XSDEBUG("shutdown finished.\n"); |
258 } | 258 } |
259 | 259 |
260 | 260 |
261 /* | 261 /* |
262 * Check whether the given file is handled by this plugin | 262 * Check whether the given file is handled by this plugin |
263 */ | 263 */ |
264 gint xs_is_our_file(gchar *pcFilename) | 264 gint xs_is_our_file(gchar *pcFilename) |
265 { | 265 { |
266 gchar *pcExt; | 266 gchar *pcExt; |
267 assert(xs_status.sidPlayer); | 267 assert(xs_status.sidPlayer); |
268 | 268 |
269 /* Check the filename */ | 269 /* Check the filename */ |
270 if (pcFilename == NULL) | 270 if (pcFilename == NULL) |
271 return FALSE; | 271 return FALSE; |
272 | 272 |
273 /* Try to detect via detection routine, if required */ | 273 /* Try to detect via detection routine, if required */ |
274 if (xs_cfg.detectMagic) { | 274 if (xs_cfg.detectMagic) { |
275 xs_file_t *f; | 275 xs_file_t *f; |
276 if ((f = xs_fopen(pcFilename, "rb")) != NULL) { | 276 if ((f = xs_fopen(pcFilename, "rb")) != NULL) { |
277 if (xs_status.sidPlayer->plrProbe(f)) | 277 if (xs_status.sidPlayer->plrProbe(f)) |
278 return TRUE; | 278 return TRUE; |
279 xs_fclose(f); | 279 xs_fclose(f); |
280 } | 280 } |
281 } | 281 } |
282 | 282 |
283 /* Detect just by checking filename extension */ | 283 /* Detect just by checking filename extension */ |
284 pcExt = xs_strrchr(pcFilename, '.'); | 284 pcExt = xs_strrchr(pcFilename, '.'); |
285 if (pcExt) { | 285 if (pcExt) { |
286 pcExt++; | 286 pcExt++; |
287 switch (xs_cfg.playerEngine) { | 287 switch (xs_cfg.playerEngine) { |
288 case XS_ENG_SIDPLAY1: | 288 case XS_ENG_SIDPLAY1: |
289 case XS_ENG_SIDPLAY2: | 289 case XS_ENG_SIDPLAY2: |
290 if (!g_strcasecmp(pcExt, "psid")) | 290 if (!g_strcasecmp(pcExt, "psid")) |
291 return TRUE; | 291 return TRUE; |
292 if (!g_strcasecmp(pcExt, "sid")) | 292 if (!g_strcasecmp(pcExt, "sid")) |
293 return TRUE; | 293 return TRUE; |
294 if (!g_strcasecmp(pcExt, "dat")) | 294 if (!g_strcasecmp(pcExt, "dat")) |
295 return TRUE; | 295 return TRUE; |
296 if (!g_strcasecmp(pcExt, "inf")) | 296 if (!g_strcasecmp(pcExt, "inf")) |
297 return TRUE; | 297 return TRUE; |
298 if (!g_strcasecmp(pcExt, "info")) | 298 if (!g_strcasecmp(pcExt, "info")) |
299 return TRUE; | 299 return TRUE; |
300 break; | 300 break; |
301 } | 301 } |
302 } | 302 } |
303 | 303 |
304 return FALSE; | 304 return FALSE; |
305 } | 305 } |
306 | 306 |
307 | 307 |
308 /* | 308 /* |
309 * Main playing thread loop | 309 * Main playing thread loop |
310 */ | 310 */ |
311 void *xs_playthread(void *argPointer) | 311 void *xs_playthread(void *argPointer) |
312 { | 312 { |
313 xs_status_t myStatus; | 313 xs_status_t myStatus; |
314 xs_tuneinfo_t *myTune; | 314 xs_tuneinfo_t *myTune; |
315 gboolean audioOpen = FALSE, doPlay = FALSE, isFound = FALSE; | 315 gboolean audioOpen = FALSE, doPlay = FALSE, isFound = FALSE; |
316 gint audioGot, songLength, i; | 316 gint audioGot, songLength, i; |
317 gchar *audioBuffer = NULL, *oversampleBuffer = NULL, *tmpTitle; | 317 gchar *audioBuffer = NULL, *oversampleBuffer = NULL, *tmpTitle; |
318 | 318 |
319 (void) argPointer; | 319 (void) argPointer; |
320 | 320 |
321 /* Initialize */ | 321 /* Initialize */ |
322 XSDEBUG("entering player thread\n"); | 322 XSDEBUG("entering player thread\n"); |
323 XS_MUTEX_LOCK(xs_status); | 323 XS_MUTEX_LOCK(xs_status); |
324 memcpy(&myStatus, &xs_status, sizeof(xs_status_t)); | 324 memcpy(&myStatus, &xs_status, sizeof(xs_status_t)); |
325 myTune = xs_status.tuneInfo; | 325 myTune = xs_status.tuneInfo; |
326 for (i = 0; i <= myTune->nsubTunes; i++) | 326 for (i = 0; i <= myTune->nsubTunes; i++) |
327 myTune->subTunes[i].tunePlayed = FALSE; | 327 myTune->subTunes[i].tunePlayed = FALSE; |
328 XS_MUTEX_UNLOCK(xs_status); | 328 XS_MUTEX_UNLOCK(xs_status); |
329 | 329 |
330 /* Allocate audio buffer */ | 330 /* Allocate audio buffer */ |
331 audioBuffer = (gchar *) g_malloc(XS_AUDIOBUF_SIZE); | 331 audioBuffer = (gchar *) g_malloc(XS_AUDIOBUF_SIZE); |
332 if (audioBuffer == NULL) { | 332 if (audioBuffer == NULL) { |
333 xs_error("Couldn't allocate memory for audio data buffer!\n"); | 333 xs_error("Couldn't allocate memory for audio data buffer!\n"); |
334 goto xs_err_exit; | 334 goto xs_err_exit; |
335 } | 335 } |
336 | 336 |
337 if (myStatus.oversampleEnable) { | 337 if (myStatus.oversampleEnable) { |
338 oversampleBuffer = (gchar *) g_malloc(XS_AUDIOBUF_SIZE * myStatus.oversampleFactor); | 338 oversampleBuffer = (gchar *) g_malloc(XS_AUDIOBUF_SIZE * myStatus.oversampleFactor); |
339 if (oversampleBuffer == NULL) { | 339 if (oversampleBuffer == NULL) { |
340 xs_error("Couldn't allocate memory for audio oversampling buffer!\n"); | 340 xs_error("Couldn't allocate memory for audio oversampling buffer!\n"); |
341 goto xs_err_exit; | 341 goto xs_err_exit; |
342 } | 342 } |
343 } | 343 } |
344 | 344 |
345 /* | 345 /* |
346 * Main player loop: while not stopped, loop here - play subtunes | 346 * Main player loop: while not stopped, loop here - play subtunes |
347 */ | 347 */ |
348 audioOpen = FALSE; | 348 audioOpen = FALSE; |
349 doPlay = TRUE; | 349 doPlay = TRUE; |
350 while (xs_status.isPlaying && doPlay) { | 350 while (xs_status.isPlaying && doPlay) { |
351 /* Automatic sub-tune change logic */ | 351 /* Automatic sub-tune change logic */ |
352 XS_MUTEX_LOCK(xs_cfg); | 352 XS_MUTEX_LOCK(xs_cfg); |
353 XS_MUTEX_LOCK(xs_status); | 353 XS_MUTEX_LOCK(xs_status); |
354 myStatus.isPlaying = TRUE; | 354 myStatus.isPlaying = TRUE; |
355 | 355 |
356 if (xs_status.currSong < 1 || myStatus.currSong < 1) { | 356 if (xs_status.currSong < 1 || myStatus.currSong < 1) { |
357 XS_MUTEX_UNLOCK(xs_status); | 357 XS_MUTEX_UNLOCK(xs_status); |
358 XS_MUTEX_UNLOCK(xs_cfg); | 358 XS_MUTEX_UNLOCK(xs_cfg); |
359 goto xs_err_exit; | 359 goto xs_err_exit; |
360 } | 360 } |
361 | 361 |
362 if (xs_cfg.subAutoEnable && (myStatus.currSong == xs_status.currSong)) { | 362 if (xs_cfg.subAutoEnable && (myStatus.currSong == xs_status.currSong)) { |
363 /* Check if currently selected sub-tune has been played already */ | 363 /* Check if currently selected sub-tune has been played already */ |
364 if (myTune->subTunes[myStatus.currSong-1].tunePlayed) { | 364 if (myTune->subTunes[myStatus.currSong-1].tunePlayed) { |
365 /* Find a tune that has not been played */ | 365 /* Find a tune that has not been played */ |
366 XSDEBUG("tune #%i already played, finding next match ...\n", myStatus.currSong); | 366 XSDEBUG("tune #%i already played, finding next match ...\n", myStatus.currSong); |
367 isFound = FALSE; | 367 isFound = FALSE; |
368 i = 0; | 368 i = 0; |
369 while (!isFound && (++i <= myTune->nsubTunes)) { | 369 while (!isFound && (++i <= myTune->nsubTunes)) { |
370 if (xs_cfg.subAutoMinOnly) { | 370 if (xs_cfg.subAutoMinOnly) { |
371 /* A tune with minimum length must be found */ | 371 /* A tune with minimum length must be found */ |
372 if (!myTune->subTunes[i-1].tunePlayed && | 372 if (!myTune->subTunes[i-1].tunePlayed && |
373 myTune->subTunes[i-1].tuneLength >= xs_cfg.subAutoMinTime) | 373 myTune->subTunes[i-1].tuneLength >= xs_cfg.subAutoMinTime) |
374 isFound = TRUE; | 374 isFound = TRUE; |
375 } else { | 375 } else { |
376 /* Any unplayed tune is okay */ | 376 /* Any unplayed tune is okay */ |
377 if (!myTune->subTunes[i-1].tunePlayed) | 377 if (!myTune->subTunes[i-1].tunePlayed) |
378 isFound = TRUE; | 378 isFound = TRUE; |
379 } | 379 } |
380 } | 380 } |
381 | 381 |
382 if (isFound) { | 382 if (isFound) { |
383 /* Set the new sub-tune */ | 383 /* Set the new sub-tune */ |
384 XSDEBUG("found #%i\n", i); | 384 XSDEBUG("found #%i\n", i); |
385 xs_status.currSong = i; | 385 xs_status.currSong = i; |
386 } else | 386 } else |
387 /* This is the end */ | 387 /* This is the end */ |
388 doPlay = FALSE; | 388 doPlay = FALSE; |
389 | 389 |
390 XS_MUTEX_UNLOCK(xs_status); | 390 XS_MUTEX_UNLOCK(xs_status); |
391 XS_MUTEX_UNLOCK(xs_cfg); | 391 XS_MUTEX_UNLOCK(xs_cfg); |
392 continue; /* This is ugly, but ... */ | 392 continue; /* This is ugly, but ... */ |
393 } | 393 } |
394 } | 394 } |
395 | 395 |
396 /* Tell that we are initializing, update sub-tune controls */ | 396 /* Tell that we are initializing, update sub-tune controls */ |
397 myStatus.currSong = xs_status.currSong; | 397 myStatus.currSong = xs_status.currSong; |
398 myTune->subTunes[myStatus.currSong-1].tunePlayed = TRUE; | 398 myTune->subTunes[myStatus.currSong-1].tunePlayed = TRUE; |
399 XS_MUTEX_UNLOCK(xs_status); | 399 XS_MUTEX_UNLOCK(xs_status); |
400 XS_MUTEX_UNLOCK(xs_cfg); | 400 XS_MUTEX_UNLOCK(xs_cfg); |
401 | 401 |
402 XSDEBUG("subtune #%i selected, initializing...\n", myStatus.currSong); | 402 XSDEBUG("subtune #%i selected, initializing...\n", myStatus.currSong); |
403 | 403 |
404 GDK_THREADS_ENTER(); | 404 GDK_THREADS_ENTER(); |
405 xs_subctrl_update(); | 405 xs_subctrl_update(); |
406 GDK_THREADS_LEAVE(); | 406 GDK_THREADS_LEAVE(); |
407 | 407 |
408 /* Check minimum playtime */ | 408 /* Check minimum playtime */ |
409 songLength = myTune->subTunes[myStatus.currSong-1].tuneLength; | 409 songLength = myTune->subTunes[myStatus.currSong-1].tuneLength; |
410 if (xs_cfg.playMinTimeEnable && (songLength >= 0)) { | 410 if (xs_cfg.playMinTimeEnable && (songLength >= 0)) { |
411 if (songLength < xs_cfg.playMinTime) | 411 if (songLength < xs_cfg.playMinTime) |
412 songLength = xs_cfg.playMinTime; | 412 songLength = xs_cfg.playMinTime; |
413 } | 413 } |
414 | 414 |
415 /* Initialize song */ | 415 /* Initialize song */ |
416 if (!myStatus.sidPlayer->plrInitSong(&myStatus)) { | 416 if (!myStatus.sidPlayer->plrInitSong(&myStatus)) { |
417 xs_error("Couldn't initialize SID-tune '%s' (sub-tune #%i)!\n", | 417 xs_error("Couldn't initialize SID-tune '%s' (sub-tune #%i)!\n", |
418 myTune->sidFilename, myStatus.currSong); | 418 myTune->sidFilename, myStatus.currSong); |
419 goto xs_err_exit; | 419 goto xs_err_exit; |
420 } | 420 } |
421 | 421 |
422 /* Open the audio output */ | 422 /* Open the audio output */ |
423 XSDEBUG("open audio output (%d, %d, %d)\n", | 423 XSDEBUG("open audio output (%d, %d, %d)\n", |
424 myStatus.audioFormat, myStatus.audioFrequency, myStatus.audioChannels); | 424 myStatus.audioFormat, myStatus.audioFrequency, myStatus.audioChannels); |
425 | 425 |
426 if (!xs_plugin_ip.output-> | 426 if (!xs_plugin_ip.output-> |
427 open_audio(myStatus.audioFormat, myStatus.audioFrequency, myStatus.audioChannels)) { | 427 open_audio(myStatus.audioFormat, myStatus.audioFrequency, myStatus.audioChannels)) { |
428 xs_error("Couldn't open XMMS audio output (fmt=%x, freq=%i, nchan=%i)!\n", | 428 xs_error("Couldn't open XMMS audio output (fmt=%x, freq=%i, nchan=%i)!\n", |
429 myStatus.audioFormat, | 429 myStatus.audioFormat, |
430 myStatus.audioFrequency, | 430 myStatus.audioFrequency, |
431 myStatus.audioChannels); | 431 myStatus.audioChannels); |
432 | 432 |
433 XS_MUTEX_LOCK(xs_status); | 433 XS_MUTEX_LOCK(xs_status); |
434 xs_status.isError = TRUE; | 434 xs_status.isError = TRUE; |
435 XS_MUTEX_UNLOCK(xs_status); | 435 XS_MUTEX_UNLOCK(xs_status); |
436 goto xs_err_exit; | 436 goto xs_err_exit; |
437 } | 437 } |
438 | 438 |
439 audioOpen = TRUE; | 439 audioOpen = TRUE; |
440 | 440 |
441 /* Set song information for current subtune */ | 441 /* Set song information for current subtune */ |
442 XSDEBUG("set tune info\n"); | 442 XSDEBUG("set tune info\n"); |
443 myStatus.sidPlayer->plrUpdateSIDInfo(&myStatus); | 443 myStatus.sidPlayer->plrUpdateSIDInfo(&myStatus); |
444 tmpTitle = xs_make_titlestring(myTune, myStatus.currSong); | 444 tmpTitle = xs_make_titlestring(myTune, myStatus.currSong); |
445 | 445 |
446 xs_plugin_ip.set_info( | 446 xs_plugin_ip.set_info( |
447 tmpTitle, | 447 tmpTitle, |
448 (songLength > 0) ? (songLength * 1000) : 0, | 448 (songLength > 0) ? (songLength * 1000) : 0, |
449 -1, | 449 -1, |
450 myStatus.audioFrequency, | 450 myStatus.audioFrequency, |
451 myStatus.audioChannels); | 451 myStatus.audioChannels); |
452 | 452 |
453 g_free(tmpTitle); | 453 g_free(tmpTitle); |
454 | 454 |
455 XSDEBUG("playing\n"); | 455 XSDEBUG("playing\n"); |
456 | 456 |
457 /* | 457 /* |
458 * Play the subtune | 458 * Play the subtune |
459 */ | 459 */ |
460 while (xs_status.isPlaying && myStatus.isPlaying && (xs_status.currSong == myStatus.currSong)) { | 460 while (xs_status.isPlaying && myStatus.isPlaying && (xs_status.currSong == myStatus.currSong)) { |
461 /* Render audio data */ | 461 /* Render audio data */ |
462 if (myStatus.oversampleEnable) { | 462 if (myStatus.oversampleEnable) { |
463 /* Perform oversampled rendering */ | 463 /* Perform oversampled rendering */ |
464 audioGot = myStatus.sidPlayer->plrFillBuffer( | 464 audioGot = myStatus.sidPlayer->plrFillBuffer( |
465 &myStatus, | 465 &myStatus, |
466 oversampleBuffer, | 466 oversampleBuffer, |
467 (XS_AUDIOBUF_SIZE * myStatus.oversampleFactor)); | 467 (XS_AUDIOBUF_SIZE * myStatus.oversampleFactor)); |
468 | 468 |
469 audioGot /= myStatus.oversampleFactor; | 469 audioGot /= myStatus.oversampleFactor; |
470 | 470 |
471 /* Execute rate-conversion with filtering */ | 471 /* Execute rate-conversion with filtering */ |
472 if (xs_filter_rateconv(audioBuffer, oversampleBuffer, | 472 if (xs_filter_rateconv(audioBuffer, oversampleBuffer, |
473 myStatus.audioFormat, myStatus.oversampleFactor, audioGot) < 0) { | 473 myStatus.audioFormat, myStatus.oversampleFactor, audioGot) < 0) { |
474 xs_error("Oversampling rate-conversion pass failed.\n"); | 474 xs_error("Oversampling rate-conversion pass failed.\n"); |
475 XS_MUTEX_LOCK(xs_status); | 475 XS_MUTEX_LOCK(xs_status); |
476 xs_status.isError = TRUE; | 476 xs_status.isError = TRUE; |
477 XS_MUTEX_UNLOCK(xs_status); | 477 XS_MUTEX_UNLOCK(xs_status); |
478 goto xs_err_exit; | 478 goto xs_err_exit; |
479 } | 479 } |
480 } else { | 480 } else { |
481 audioGot = myStatus.sidPlayer->plrFillBuffer( | 481 audioGot = myStatus.sidPlayer->plrFillBuffer( |
482 &myStatus, audioBuffer, XS_AUDIOBUF_SIZE); | 482 &myStatus, audioBuffer, XS_AUDIOBUF_SIZE); |
483 } | 483 } |
484 | 484 |
485 /* I <3 visualice/haujobb */ | 485 /* I <3 visualice/haujobb */ |
486 xs_plugin_ip.add_vis_pcm( | 486 xs_plugin_ip.add_vis_pcm( |
487 xs_plugin_ip.output->written_time(), | 487 xs_plugin_ip.output->written_time(), |
488 myStatus.audioFormat, myStatus.audioChannels, | 488 myStatus.audioFormat, myStatus.audioChannels, |
489 audioGot, audioBuffer); | 489 audioGot, audioBuffer); |
490 | 490 |
491 /* Wait a little */ | 491 /* Wait a little */ |
492 while (xs_status.isPlaying && | 492 while (xs_status.isPlaying && |
493 (xs_status.currSong == myStatus.currSong) && | 493 (xs_status.currSong == myStatus.currSong) && |
494 (xs_plugin_ip.output->buffer_free() < audioGot)) | 494 (xs_plugin_ip.output->buffer_free() < audioGot)) |
495 xmms_usleep(500); | 495 xmms_usleep(500); |
496 | 496 |
497 /* Output audio */ | 497 /* Output audio */ |
498 if (xs_status.isPlaying && (xs_status.currSong == myStatus.currSong)) | 498 if (xs_status.isPlaying && (xs_status.currSong == myStatus.currSong)) |
499 xs_plugin_ip.output->write_audio(audioBuffer, audioGot); | 499 xs_plugin_ip.output->write_audio(audioBuffer, audioGot); |
500 | 500 |
501 /* Check if we have played enough */ | 501 /* Check if we have played enough */ |
502 if (xs_cfg.playMaxTimeEnable) { | 502 if (xs_cfg.playMaxTimeEnable) { |
503 if (xs_cfg.playMaxTimeUnknown) { | 503 if (xs_cfg.playMaxTimeUnknown) { |
504 if ((songLength < 0) && | 504 if ((songLength < 0) && |
505 (xs_plugin_ip.output->output_time() >= (xs_cfg.playMaxTime * 1000))) | 505 (xs_plugin_ip.output->output_time() >= (xs_cfg.playMaxTime * 1000))) |
506 myStatus.isPlaying = FALSE; | 506 myStatus.isPlaying = FALSE; |
507 } else { | 507 } else { |
508 if (xs_plugin_ip.output->output_time() >= (xs_cfg.playMaxTime * 1000)) | 508 if (xs_plugin_ip.output->output_time() >= (xs_cfg.playMaxTime * 1000)) |
509 myStatus.isPlaying = FALSE; | 509 myStatus.isPlaying = FALSE; |
510 } | 510 } |
511 } | 511 } |
512 | 512 |
513 if (songLength >= 0) { | 513 if (songLength >= 0) { |
514 if (xs_plugin_ip.output->output_time() >= (songLength * 1000)) | 514 if (xs_plugin_ip.output->output_time() >= (songLength * 1000)) |
515 myStatus.isPlaying = FALSE; | 515 myStatus.isPlaying = FALSE; |
516 } | 516 } |
517 } | 517 } |
518 | 518 |
519 XSDEBUG("subtune ended/stopped\n"); | 519 XSDEBUG("subtune ended/stopped\n"); |
520 | 520 |
521 /* Close audio output plugin */ | 521 /* Close audio output plugin */ |
522 if (audioOpen) { | 522 if (audioOpen) { |
523 XSDEBUG("close audio #1\n"); | 523 XSDEBUG("close audio #1\n"); |
524 xs_plugin_ip.output->close_audio(); | 524 xs_plugin_ip.output->close_audio(); |
525 audioOpen = FALSE; | 525 audioOpen = FALSE; |
526 XSDEBUG("closed\n"); | 526 XSDEBUG("closed\n"); |
527 } | 527 } |
528 | 528 |
529 /* Now determine if we continue by selecting other subtune or something */ | 529 /* Now determine if we continue by selecting other subtune or something */ |
530 if (!myStatus.isPlaying && !xs_cfg.subAutoEnable) | 530 if (!myStatus.isPlaying && !xs_cfg.subAutoEnable) |
531 doPlay = FALSE; | 531 doPlay = FALSE; |
532 } | 532 } |
533 | 533 |
534 xs_err_exit: | 534 xs_err_exit: |
535 XSDEBUG("out of playing loop\n"); | 535 XSDEBUG("out of playing loop\n"); |
536 | 536 |
537 /* Close audio output plugin */ | 537 /* Close audio output plugin */ |
538 if (audioOpen) { | 538 if (audioOpen) { |
539 XSDEBUG("close audio #2\n"); | 539 XSDEBUG("close audio #2\n"); |
540 xs_plugin_ip.output->close_audio(); | 540 xs_plugin_ip.output->close_audio(); |
541 XSDEBUG("closed\n"); | 541 XSDEBUG("closed\n"); |
542 } | 542 } |
543 | 543 |
544 g_free(audioBuffer); | 544 g_free(audioBuffer); |
545 g_free(oversampleBuffer); | 545 g_free(oversampleBuffer); |
546 | 546 |
547 /* Set playing status to false (stopped), thus when | 547 /* Set playing status to false (stopped), thus when |
548 * XMMS next calls xs_get_time(), it can return appropriate | 548 * XMMS next calls xs_get_time(), it can return appropriate |
549 * value "not playing" status and XMMS knows to move to | 549 * value "not playing" status and XMMS knows to move to |
550 * next entry in the playlist .. or whatever it wishes. | 550 * next entry in the playlist .. or whatever it wishes. |
551 */ | 551 */ |
552 XS_MUTEX_LOCK(xs_status); | 552 XS_MUTEX_LOCK(xs_status); |
553 xs_status.isPlaying = FALSE; | 553 xs_status.isPlaying = FALSE; |
554 XS_MUTEX_UNLOCK(xs_status); | 554 XS_MUTEX_UNLOCK(xs_status); |
555 | 555 |
556 /* Exit the playing thread */ | 556 /* Exit the playing thread */ |
557 XSDEBUG("exiting thread, bye.\n"); | 557 XSDEBUG("exiting thread, bye.\n"); |
558 XS_THREAD_EXIT(NULL); | 558 XS_THREAD_EXIT(NULL); |
559 } | 559 } |
560 | 560 |
561 | 561 |
562 /* | 562 /* |
563 * Start playing the given file | 563 * Start playing the given file |
565 * Usually you would also initialize the output-plugin, but | 565 * Usually you would also initialize the output-plugin, but |
566 * this is XMMS-SID and we do it on the player thread instead. | 566 * this is XMMS-SID and we do it on the player thread instead. |
567 */ | 567 */ |
568 void xs_play_file(gchar * pcFilename) | 568 void xs_play_file(gchar * pcFilename) |
569 { | 569 { |
570 assert(xs_status.sidPlayer); | 570 assert(xs_status.sidPlayer); |
571 | 571 |
572 XSDEBUG("play '%s'\n", pcFilename); | 572 XSDEBUG("play '%s'\n", pcFilename); |
573 | 573 |
574 /* Get tune information */ | 574 /* Get tune information */ |
575 if ((xs_status.tuneInfo = xs_status.sidPlayer->plrGetSIDInfo(pcFilename)) == NULL) | 575 if ((xs_status.tuneInfo = xs_status.sidPlayer->plrGetSIDInfo(pcFilename)) == NULL) |
576 return; | 576 return; |
577 | 577 |
578 /* Initialize the tune */ | 578 /* Initialize the tune */ |
579 if (!xs_status.sidPlayer->plrLoadSID(&xs_status, pcFilename)) { | 579 if (!xs_status.sidPlayer->plrLoadSID(&xs_status, pcFilename)) { |
580 xs_tuneinfo_free(xs_status.tuneInfo); | 580 xs_tuneinfo_free(xs_status.tuneInfo); |
581 xs_status.tuneInfo = NULL; | 581 xs_status.tuneInfo = NULL; |
582 return; | 582 return; |
583 } | 583 } |
584 | 584 |
585 XSDEBUG("load ok\n"); | 585 XSDEBUG("load ok\n"); |
586 | 586 |
587 /* Set general status information */ | 587 /* Set general status information */ |
588 xs_status.isPlaying = TRUE; | 588 xs_status.isPlaying = TRUE; |
589 xs_status.isError = FALSE; | 589 xs_status.isError = FALSE; |
590 xs_status.currSong = xs_status.tuneInfo->startTune; | 590 xs_status.currSong = xs_status.tuneInfo->startTune; |
591 | 591 |
592 /* Start the playing thread! */ | 592 /* Start the playing thread! */ |
593 if (pthread_create(&xs_decode_thread, NULL, xs_playthread, NULL) < 0) { | 593 if (pthread_create(&xs_decode_thread, NULL, xs_playthread, NULL) < 0) { |
594 xs_error("Couldn't create playing thread!\n"); | 594 xs_error("Couldn't create playing thread!\n"); |
595 xs_tuneinfo_free(xs_status.tuneInfo); | 595 xs_tuneinfo_free(xs_status.tuneInfo); |
596 xs_status.tuneInfo = NULL; | 596 xs_status.tuneInfo = NULL; |
597 xs_status.sidPlayer->plrDeleteSID(&xs_status); | 597 xs_status.sidPlayer->plrDeleteSID(&xs_status); |
598 } | 598 } |
599 | 599 |
600 /* Okay, here the playing thread has started up and we | 600 /* Okay, here the playing thread has started up and we |
601 * return from here to XMMS. Rest is up to XMMS's GUI | 601 * return from here to XMMS. Rest is up to XMMS's GUI |
602 * and playing thread. | 602 * and playing thread. |
603 */ | 603 */ |
604 XSDEBUG("systems should be up?\n"); | 604 XSDEBUG("systems should be up?\n"); |
605 } | 605 } |
606 | 606 |
607 | 607 |
608 /* | 608 /* |
609 * Stop playing | 609 * Stop playing |
615 * | 615 * |
616 * Finally tune and other memory allocations are free'd. | 616 * Finally tune and other memory allocations are free'd. |
617 */ | 617 */ |
618 void xs_stop(void) | 618 void xs_stop(void) |
619 { | 619 { |
620 XSDEBUG("stop requested\n"); | 620 XSDEBUG("stop requested\n"); |
621 | 621 |
622 /* Close the sub-tune control window, if any */ | 622 /* Close the sub-tune control window, if any */ |
623 xs_subctrl_close(); | 623 xs_subctrl_close(); |
624 | 624 |
625 /* Lock xs_status and stop playing thread */ | 625 /* Lock xs_status and stop playing thread */ |
626 XS_MUTEX_LOCK(xs_status); | 626 XS_MUTEX_LOCK(xs_status); |
627 if (xs_status.isPlaying) { | 627 if (xs_status.isPlaying) { |
628 XSDEBUG("stopping...\n"); | 628 XSDEBUG("stopping...\n"); |
629 xs_status.isPlaying = FALSE; | 629 xs_status.isPlaying = FALSE; |
630 XS_MUTEX_UNLOCK(xs_status); | 630 XS_MUTEX_UNLOCK(xs_status); |
631 XS_THREAD_JOIN(xs_decode_thread); | 631 XS_THREAD_JOIN(xs_decode_thread); |
632 } else { | 632 } else { |
633 XS_MUTEX_UNLOCK(xs_status); | 633 XS_MUTEX_UNLOCK(xs_status); |
634 } | 634 } |
635 | 635 |
636 XSDEBUG("done, updating status\n"); | 636 XSDEBUG("done, updating status\n"); |
637 | 637 |
638 /* Status is now stopped, update the sub-tune | 638 /* Status is now stopped, update the sub-tune |
639 * controller in fileinfo window (if open) | 639 * controller in fileinfo window (if open) |
640 */ | 640 */ |
641 xs_fileinfo_update(); | 641 xs_fileinfo_update(); |
642 | 642 |
643 /* Free tune information */ | 643 /* Free tune information */ |
644 XS_MUTEX_LOCK(xs_status); | 644 XS_MUTEX_LOCK(xs_status); |
645 xs_status.sidPlayer->plrDeleteSID(&xs_status); | 645 xs_status.sidPlayer->plrDeleteSID(&xs_status); |
646 xs_tuneinfo_free(xs_status.tuneInfo); | 646 xs_tuneinfo_free(xs_status.tuneInfo); |
647 xs_status.tuneInfo = NULL; | 647 xs_status.tuneInfo = NULL; |
648 XS_MUTEX_UNLOCK(xs_status); | 648 XS_MUTEX_UNLOCK(xs_status); |
649 XSDEBUG("ok\n"); | 649 XSDEBUG("ok\n"); |
650 } | 650 } |
651 | 651 |
652 | 652 |
653 /* | 653 /* |
654 * Pause/unpause the playing | 654 * Pause/unpause the playing |
655 */ | 655 */ |
656 void xs_pause(short pauseState) | 656 void xs_pause(short pauseState) |
657 { | 657 { |
658 XS_MUTEX_LOCK(xs_status); | 658 XS_MUTEX_LOCK(xs_status); |
659 /* FIXME FIX ME todo: pause should disable sub-tune controls */ | 659 /* FIXME FIX ME todo: pause should disable sub-tune controls */ |
660 XS_MUTEX_UNLOCK(xs_status); | 660 XS_MUTEX_UNLOCK(xs_status); |
661 | 661 |
662 xs_subctrl_close(); | 662 xs_subctrl_close(); |
663 xs_fileinfo_update(); | 663 xs_fileinfo_update(); |
664 xs_plugin_ip.output->pause(pauseState); | 664 xs_plugin_ip.output->pause(pauseState); |
665 } | 665 } |
666 | 666 |
667 | 667 |
668 /* | 668 /* |
669 * Pop-up subtune selector | 669 * Pop-up subtune selector |
670 */ | 670 */ |
671 void xs_subctrl_setsong(void) | 671 void xs_subctrl_setsong(void) |
672 { | 672 { |
673 gint n; | 673 gint n; |
674 | 674 |
675 XS_MUTEX_LOCK(xs_status); | 675 XS_MUTEX_LOCK(xs_status); |
676 XS_MUTEX_LOCK(xs_subctrl); | 676 XS_MUTEX_LOCK(xs_subctrl); |
677 | 677 |
678 if (xs_status.tuneInfo && xs_status.isPlaying) { | 678 if (xs_status.tuneInfo && xs_status.isPlaying) { |
679 n = (gint) GTK_ADJUSTMENT(xs_subctrl_adj)->value; | 679 n = (gint) GTK_ADJUSTMENT(xs_subctrl_adj)->value; |
680 if ((n >= 1) && (n <= xs_status.tuneInfo->nsubTunes)) | 680 if ((n >= 1) && (n <= xs_status.tuneInfo->nsubTunes)) |
681 xs_status.currSong = n; | 681 xs_status.currSong = n; |
682 } | 682 } |
683 | 683 |
684 XS_MUTEX_UNLOCK(xs_subctrl); | 684 XS_MUTEX_UNLOCK(xs_subctrl); |
685 XS_MUTEX_UNLOCK(xs_status); | 685 XS_MUTEX_UNLOCK(xs_status); |
686 } | 686 } |
687 | 687 |
688 | 688 |
689 void xs_subctrl_prevsong(void) | 689 void xs_subctrl_prevsong(void) |
690 { | 690 { |
691 XS_MUTEX_LOCK(xs_status); | 691 XS_MUTEX_LOCK(xs_status); |
692 | 692 |
693 if (xs_status.tuneInfo && xs_status.isPlaying) { | 693 if (xs_status.tuneInfo && xs_status.isPlaying) { |
694 if (xs_status.currSong > 1) | 694 if (xs_status.currSong > 1) |
695 xs_status.currSong--; | 695 xs_status.currSong--; |
696 } | 696 } |
697 | 697 |
698 XS_MUTEX_UNLOCK(xs_status); | 698 XS_MUTEX_UNLOCK(xs_status); |
699 | 699 |
700 xs_subctrl_update(); | 700 xs_subctrl_update(); |
701 } | 701 } |
702 | 702 |
703 | 703 |
704 void xs_subctrl_nextsong(void) | 704 void xs_subctrl_nextsong(void) |
705 { | 705 { |
706 XS_MUTEX_LOCK(xs_status); | 706 XS_MUTEX_LOCK(xs_status); |
707 | 707 |
708 if (xs_status.tuneInfo && xs_status.isPlaying) { | 708 if (xs_status.tuneInfo && xs_status.isPlaying) { |
709 if (xs_status.currSong < xs_status.tuneInfo->nsubTunes) | 709 if (xs_status.currSong < xs_status.tuneInfo->nsubTunes) |
710 xs_status.currSong++; | 710 xs_status.currSong++; |
711 } | 711 } |
712 | 712 |
713 XS_MUTEX_UNLOCK(xs_status); | 713 XS_MUTEX_UNLOCK(xs_status); |
714 | 714 |
715 xs_subctrl_update(); | 715 xs_subctrl_update(); |
716 } | 716 } |
717 | 717 |
718 | 718 |
719 void xs_subctrl_update(void) | 719 void xs_subctrl_update(void) |
720 { | 720 { |
721 GtkAdjustment *tmpAdj; | 721 GtkAdjustment *tmpAdj; |
722 | 722 |
723 XS_MUTEX_LOCK(xs_status); | 723 XS_MUTEX_LOCK(xs_status); |
724 XS_MUTEX_LOCK(xs_subctrl); | 724 XS_MUTEX_LOCK(xs_subctrl); |
725 | 725 |
726 /* Check if control window exists, we are currently playing and have a tune */ | 726 /* Check if control window exists, we are currently playing and have a tune */ |
727 if (xs_subctrl) { | 727 if (xs_subctrl) { |
728 if (xs_status.tuneInfo && xs_status.isPlaying) { | 728 if (xs_status.tuneInfo && xs_status.isPlaying) { |
729 tmpAdj = GTK_ADJUSTMENT(xs_subctrl_adj); | 729 tmpAdj = GTK_ADJUSTMENT(xs_subctrl_adj); |
730 | 730 |
731 tmpAdj->value = xs_status.currSong; | 731 tmpAdj->value = xs_status.currSong; |
732 tmpAdj->lower = 1; | 732 tmpAdj->lower = 1; |
733 tmpAdj->upper = xs_status.tuneInfo->nsubTunes; | 733 tmpAdj->upper = xs_status.tuneInfo->nsubTunes; |
734 XS_MUTEX_UNLOCK(xs_status); | 734 XS_MUTEX_UNLOCK(xs_status); |
735 XS_MUTEX_UNLOCK(xs_subctrl); | 735 XS_MUTEX_UNLOCK(xs_subctrl); |
736 gtk_adjustment_value_changed(tmpAdj); | 736 gtk_adjustment_value_changed(tmpAdj); |
737 } else { | 737 } else { |
738 XS_MUTEX_UNLOCK(xs_status); | 738 XS_MUTEX_UNLOCK(xs_status); |
739 XS_MUTEX_UNLOCK(xs_subctrl); | 739 XS_MUTEX_UNLOCK(xs_subctrl); |
740 xs_subctrl_close(); | 740 xs_subctrl_close(); |
741 } | 741 } |
742 } else { | 742 } else { |
743 XS_MUTEX_UNLOCK(xs_subctrl); | 743 XS_MUTEX_UNLOCK(xs_subctrl); |
744 XS_MUTEX_UNLOCK(xs_status); | 744 XS_MUTEX_UNLOCK(xs_status); |
745 } | 745 } |
746 | 746 |
747 xs_fileinfo_update(); | 747 xs_fileinfo_update(); |
748 } | 748 } |
749 | 749 |
750 | 750 |
751 void xs_subctrl_close(void) | 751 void xs_subctrl_close(void) |
752 { | 752 { |
753 XS_MUTEX_LOCK(xs_subctrl); | 753 XS_MUTEX_LOCK(xs_subctrl); |
754 | 754 |
755 if (xs_subctrl) { | 755 if (xs_subctrl) { |
756 gtk_widget_destroy(xs_subctrl); | 756 gtk_widget_destroy(xs_subctrl); |
757 xs_subctrl = NULL; | 757 xs_subctrl = NULL; |
758 } | 758 } |
759 | 759 |
760 XS_MUTEX_UNLOCK(xs_subctrl); | 760 XS_MUTEX_UNLOCK(xs_subctrl); |
761 } | 761 } |
762 | 762 |
763 | 763 |
764 gboolean xs_subctrl_keypress(GtkWidget * win, GdkEventKey * ev) | 764 gboolean xs_subctrl_keypress(GtkWidget * win, GdkEventKey * ev) |
765 { | 765 { |
766 (void) win; | 766 (void) win; |
767 | 767 |
768 if (ev->keyval == GDK_Escape) | 768 if (ev->keyval == GDK_Escape) |
769 xs_subctrl_close(); | 769 xs_subctrl_close(); |
770 | 770 |
771 return FALSE; | 771 return FALSE; |
772 } | 772 } |
773 | 773 |
774 | 774 |
775 void xs_subctrl_open(void) | 775 void xs_subctrl_open(void) |
776 { | 776 { |
777 GtkWidget *frame25, *hbox15, *subctrl_prev, *subctrl_current, *subctrl_next; | 777 GtkWidget *frame25, *hbox15, *subctrl_prev, *subctrl_current, *subctrl_next; |
778 | 778 |
779 XS_MUTEX_LOCK(xs_subctrl); | 779 XS_MUTEX_LOCK(xs_subctrl); |
780 if (!xs_status.tuneInfo || !xs_status.isPlaying || | 780 if (!xs_status.tuneInfo || !xs_status.isPlaying || |
781 xs_subctrl || (xs_status.tuneInfo->nsubTunes <= 1)) { | 781 xs_subctrl || (xs_status.tuneInfo->nsubTunes <= 1)) { |
782 XS_MUTEX_UNLOCK(xs_subctrl); | 782 XS_MUTEX_UNLOCK(xs_subctrl); |
783 return; | 783 return; |
784 } | 784 } |
785 | 785 |
786 /* Create the pop-up window */ | 786 /* Create the pop-up window */ |
787 xs_subctrl = gtk_window_new(GTK_WINDOW_DIALOG); | 787 xs_subctrl = gtk_window_new(GTK_WINDOW_DIALOG); |
788 gtk_widget_set_name(xs_subctrl, "xs_subctrl"); | 788 gtk_widget_set_name(xs_subctrl, "xs_subctrl"); |
789 gtk_object_set_data(GTK_OBJECT(xs_subctrl), "xs_subctrl", xs_subctrl); | 789 gtk_object_set_data(GTK_OBJECT(xs_subctrl), "xs_subctrl", xs_subctrl); |
790 | 790 |
791 gtk_window_set_title(GTK_WINDOW(xs_subctrl), _("Subtune Control")); | 791 gtk_window_set_title(GTK_WINDOW(xs_subctrl), _("Subtune Control")); |
792 gtk_window_set_position(GTK_WINDOW(xs_subctrl), GTK_WIN_POS_MOUSE); | 792 gtk_window_set_position(GTK_WINDOW(xs_subctrl), GTK_WIN_POS_MOUSE); |
793 gtk_container_set_border_width(GTK_CONTAINER(xs_subctrl), 0); | 793 gtk_container_set_border_width(GTK_CONTAINER(xs_subctrl), 0); |
794 gtk_window_set_policy(GTK_WINDOW(xs_subctrl), FALSE, FALSE, FALSE); | 794 gtk_window_set_policy(GTK_WINDOW(xs_subctrl), FALSE, FALSE, FALSE); |
795 | 795 |
796 XS_SIGNAL_CONNECT(xs_subctrl, "destroy", gtk_widget_destroyed, &xs_subctrl); | 796 XS_SIGNAL_CONNECT(xs_subctrl, "destroy", gtk_widget_destroyed, &xs_subctrl); |
797 XS_SIGNAL_CONNECT(xs_subctrl, "focus_out_event", xs_subctrl_close, NULL); | 797 XS_SIGNAL_CONNECT(xs_subctrl, "focus_out_event", xs_subctrl_close, NULL); |
798 | 798 |
799 gtk_widget_realize(xs_subctrl); | 799 gtk_widget_realize(xs_subctrl); |
800 gdk_window_set_decorations(xs_subctrl->window, (GdkWMDecoration) 0); | 800 gdk_window_set_decorations(xs_subctrl->window, (GdkWMDecoration) 0); |
801 | 801 |
802 | 802 |
803 /* Create the control widgets */ | 803 /* Create the control widgets */ |
804 frame25 = gtk_frame_new(NULL); | 804 frame25 = gtk_frame_new(NULL); |
805 gtk_container_add(GTK_CONTAINER(xs_subctrl), frame25); | 805 gtk_container_add(GTK_CONTAINER(xs_subctrl), frame25); |
806 gtk_container_set_border_width(GTK_CONTAINER(frame25), 2); | 806 gtk_container_set_border_width(GTK_CONTAINER(frame25), 2); |
807 gtk_frame_set_shadow_type(GTK_FRAME(frame25), GTK_SHADOW_OUT); | 807 gtk_frame_set_shadow_type(GTK_FRAME(frame25), GTK_SHADOW_OUT); |
808 | 808 |
809 hbox15 = gtk_hbox_new(FALSE, 4); | 809 hbox15 = gtk_hbox_new(FALSE, 4); |
810 gtk_container_add(GTK_CONTAINER(frame25), hbox15); | 810 gtk_container_add(GTK_CONTAINER(frame25), hbox15); |
811 | 811 |
812 subctrl_prev = gtk_button_new_with_label(" < "); | 812 subctrl_prev = gtk_button_new_with_label(" < "); |
813 gtk_widget_set_name(subctrl_prev, "subctrl_prev"); | 813 gtk_widget_set_name(subctrl_prev, "subctrl_prev"); |
814 gtk_box_pack_start(GTK_BOX(hbox15), subctrl_prev, FALSE, FALSE, 0); | 814 gtk_box_pack_start(GTK_BOX(hbox15), subctrl_prev, FALSE, FALSE, 0); |
815 | 815 |
816 xs_subctrl_adj = gtk_adjustment_new(xs_status.currSong, 1, xs_status.tuneInfo->nsubTunes, 1, 1, 0); | 816 xs_subctrl_adj = gtk_adjustment_new(xs_status.currSong, 1, xs_status.tuneInfo->nsubTunes, 1, 1, 0); |
817 XS_SIGNAL_CONNECT(xs_subctrl_adj, "value_changed", xs_subctrl_setsong, NULL); | 817 XS_SIGNAL_CONNECT(xs_subctrl_adj, "value_changed", xs_subctrl_setsong, NULL); |
818 | 818 |
819 subctrl_current = gtk_hscale_new(GTK_ADJUSTMENT(xs_subctrl_adj)); | 819 subctrl_current = gtk_hscale_new(GTK_ADJUSTMENT(xs_subctrl_adj)); |
820 gtk_widget_set_name(subctrl_current, "subctrl_current"); | 820 gtk_widget_set_name(subctrl_current, "subctrl_current"); |
821 gtk_box_pack_start(GTK_BOX(hbox15), subctrl_current, FALSE, TRUE, 0); | 821 gtk_box_pack_start(GTK_BOX(hbox15), subctrl_current, FALSE, TRUE, 0); |
822 gtk_scale_set_digits(GTK_SCALE(subctrl_current), 0); | 822 gtk_scale_set_digits(GTK_SCALE(subctrl_current), 0); |
823 gtk_range_set_update_policy(GTK_RANGE(subctrl_current), GTK_UPDATE_DELAYED); | 823 gtk_range_set_update_policy(GTK_RANGE(subctrl_current), GTK_UPDATE_DELAYED); |
824 gtk_widget_grab_focus(subctrl_current); | 824 gtk_widget_grab_focus(subctrl_current); |
825 | 825 |
826 subctrl_next = gtk_button_new_with_label(" > "); | 826 subctrl_next = gtk_button_new_with_label(" > "); |
827 gtk_widget_set_name(subctrl_next, "subctrl_next"); | 827 gtk_widget_set_name(subctrl_next, "subctrl_next"); |
828 gtk_box_pack_start(GTK_BOX(hbox15), subctrl_next, FALSE, FALSE, 0); | 828 gtk_box_pack_start(GTK_BOX(hbox15), subctrl_next, FALSE, FALSE, 0); |
829 | 829 |
830 XS_SIGNAL_CONNECT(subctrl_prev, "clicked", xs_subctrl_prevsong, NULL); | 830 XS_SIGNAL_CONNECT(subctrl_prev, "clicked", xs_subctrl_prevsong, NULL); |
831 XS_SIGNAL_CONNECT(subctrl_next, "clicked", xs_subctrl_nextsong, NULL); | 831 XS_SIGNAL_CONNECT(subctrl_next, "clicked", xs_subctrl_nextsong, NULL); |
832 XS_SIGNAL_CONNECT(xs_subctrl, "key_press_event", xs_subctrl_keypress, NULL); | 832 XS_SIGNAL_CONNECT(xs_subctrl, "key_press_event", xs_subctrl_keypress, NULL); |
833 | 833 |
834 gtk_widget_show_all(xs_subctrl); | 834 gtk_widget_show_all(xs_subctrl); |
835 | 835 |
836 XS_MUTEX_UNLOCK(xs_subctrl); | 836 XS_MUTEX_UNLOCK(xs_subctrl); |
837 } | 837 } |
838 | 838 |
839 | 839 |
840 /* | 840 /* |
841 * Set the time-seek position | 841 * Set the time-seek position |
846 * This function is called whenever position slider is clicked or | 846 * This function is called whenever position slider is clicked or |
847 * other method of seeking is used (keyboard, etc.) | 847 * other method of seeking is used (keyboard, etc.) |
848 */ | 848 */ |
849 void xs_seek(gint iTime) | 849 void xs_seek(gint iTime) |
850 { | 850 { |
851 /* Check status */ | 851 /* Check status */ |
852 XS_MUTEX_LOCK(xs_status); | 852 XS_MUTEX_LOCK(xs_status); |
853 if (!xs_status.tuneInfo || !xs_status.isPlaying) { | 853 if (!xs_status.tuneInfo || !xs_status.isPlaying) { |
854 XS_MUTEX_UNLOCK(xs_status); | 854 XS_MUTEX_UNLOCK(xs_status); |
855 return; | 855 return; |
856 } | 856 } |
857 | 857 |
858 /* Act according to settings */ | 858 /* Act according to settings */ |
859 switch (xs_cfg.subsongControl) { | 859 switch (xs_cfg.subsongControl) { |
860 case XS_SSC_SEEK: | 860 case XS_SSC_SEEK: |
861 if (iTime < xs_status.lastTime) { | 861 if (iTime < xs_status.lastTime) { |
862 if (xs_status.currSong > 1) | 862 if (xs_status.currSong > 1) |
863 xs_status.currSong--; | 863 xs_status.currSong--; |
864 } else if (iTime > xs_status.lastTime) { | 864 } else if (iTime > xs_status.lastTime) { |
865 if (xs_status.currSong < xs_status.tuneInfo->nsubTunes) | 865 if (xs_status.currSong < xs_status.tuneInfo->nsubTunes) |
866 xs_status.currSong++; | 866 xs_status.currSong++; |
867 } | 867 } |
868 break; | 868 break; |
869 | 869 |
870 case XS_SSC_POPUP: | 870 case XS_SSC_POPUP: |
871 xs_subctrl_open(); | 871 xs_subctrl_open(); |
872 break; | 872 break; |
873 | 873 |
874 /* If we have song-position patch, check settings */ | 874 /* If we have song-position patch, check settings */ |
875 #ifdef HAVE_SONG_POSITION | 875 #ifdef HAVE_SONG_POSITION |
876 case XS_SSC_PATCH: | 876 case XS_SSC_PATCH: |
877 if ((iTime > 0) && (iTime <= xs_status.tuneInfo->nsubTunes)) | 877 if ((iTime > 0) && (iTime <= xs_status.tuneInfo->nsubTunes)) |
878 xs_status.currSong = iTime; | 878 xs_status.currSong = iTime; |
879 break; | 879 break; |
880 #endif | 880 #endif |
881 } | 881 } |
882 | 882 |
883 XS_MUTEX_UNLOCK(xs_status); | 883 XS_MUTEX_UNLOCK(xs_status); |
884 } | 884 } |
885 | 885 |
886 | 886 |
887 /* | 887 /* |
888 * Return the playing "position/time" | 888 * Return the playing "position/time" |
891 * END OF SONG! Return value of -2 means error, XMMS opens an audio | 891 * END OF SONG! Return value of -2 means error, XMMS opens an audio |
892 * error dialog. -1 means end of song (if one was playing currently). | 892 * error dialog. -1 means end of song (if one was playing currently). |
893 */ | 893 */ |
894 gint xs_get_time(void) | 894 gint xs_get_time(void) |
895 { | 895 { |
896 /* If errorflag is set, return -2 to signal it to XMMS's idle callback */ | 896 /* If errorflag is set, return -2 to signal it to XMMS's idle callback */ |
897 XS_MUTEX_LOCK(xs_status); | 897 XS_MUTEX_LOCK(xs_status); |
898 if (xs_status.isError) { | 898 if (xs_status.isError) { |
899 XS_MUTEX_UNLOCK(xs_status); | 899 XS_MUTEX_UNLOCK(xs_status); |
900 return -2; | 900 return -2; |
901 } | 901 } |
902 | 902 |
903 /* If there is no tune, return -1 */ | 903 /* If there is no tune, return -1 */ |
904 if (!xs_status.tuneInfo) { | 904 if (!xs_status.tuneInfo) { |
905 XS_MUTEX_UNLOCK(xs_status); | 905 XS_MUTEX_UNLOCK(xs_status); |
906 return -1; | 906 return -1; |
907 } | 907 } |
908 | 908 |
909 /* If tune has ended, return -1 */ | 909 /* If tune has ended, return -1 */ |
910 if (!xs_status.isPlaying) { | 910 if (!xs_status.isPlaying) { |
911 XS_MUTEX_UNLOCK(xs_status); | 911 XS_MUTEX_UNLOCK(xs_status); |
912 return -1; | 912 return -1; |
913 } | 913 } |
914 | 914 |
915 /* Let's see what we do */ | 915 /* Let's see what we do */ |
916 switch (xs_cfg.subsongControl) { | 916 switch (xs_cfg.subsongControl) { |
917 case XS_SSC_SEEK: | 917 case XS_SSC_SEEK: |
918 xs_status.lastTime = (xs_plugin_ip.output->output_time() / 1000); | 918 xs_status.lastTime = (xs_plugin_ip.output->output_time() / 1000); |
919 break; | 919 break; |
920 | 920 |
921 #ifdef HAVE_SONG_POSITION | 921 #ifdef HAVE_SONG_POSITION |
922 case XS_SSC_PATCH: | 922 case XS_SSC_PATCH: |
923 set_song_position(xs_status.currSong, 1, xs_status.tuneInfo->nsubTunes); | 923 set_song_position(xs_status.currSong, 1, xs_status.tuneInfo->nsubTunes); |
924 break; | 924 break; |
925 #endif | 925 #endif |
926 } | 926 } |
927 | 927 |
928 XS_MUTEX_UNLOCK(xs_status); | 928 XS_MUTEX_UNLOCK(xs_status); |
929 | 929 |
930 /* Return output time reported by audio output plugin */ | 930 /* Return output time reported by audio output plugin */ |
931 return xs_plugin_ip.output->output_time(); | 931 return xs_plugin_ip.output->output_time(); |
932 } | 932 } |
933 | 933 |
934 | 934 |
935 /* Return song information: called by XMMS when initially loading the playlist. | 935 /* Return song information: called by XMMS when initially loading the playlist. |
936 * Subsequent changes to information are made by the player thread, | 936 * Subsequent changes to information are made by the player thread, |
937 * which uses xs_plugin_ip.set_info(); | 937 * which uses xs_plugin_ip.set_info(); |
938 */ | 938 */ |
939 void xs_get_song_info(gchar * songFilename, gchar ** songTitle, gint * songLength) | 939 void xs_get_song_info(gchar * songFilename, gchar ** songTitle, gint * songLength) |
940 { | 940 { |
941 xs_tuneinfo_t *pInfo; | 941 xs_tuneinfo_t *pInfo; |
942 | 942 |
943 XS_MUTEX_LOCK(xs_status); | 943 XS_MUTEX_LOCK(xs_status); |
944 | 944 |
945 /* Get tune information from emulation engine */ | 945 /* Get tune information from emulation engine */ |
946 pInfo = xs_status.sidPlayer->plrGetSIDInfo(songFilename); | 946 pInfo = xs_status.sidPlayer->plrGetSIDInfo(songFilename); |
947 if (!pInfo) { | 947 if (!pInfo) { |
948 XS_MUTEX_UNLOCK(xs_status); | 948 XS_MUTEX_UNLOCK(xs_status); |
949 return; | 949 return; |
950 } | 950 } |
951 | 951 |
952 /* Get sub-tune information, if available */ | 952 /* Get sub-tune information, if available */ |
953 if ((pInfo->startTune > 0) && (pInfo->startTune <= pInfo->nsubTunes)) { | 953 if ((pInfo->startTune > 0) && (pInfo->startTune <= pInfo->nsubTunes)) { |
954 gint tmpInt; | 954 gint tmpInt; |
955 | 955 |
956 (*songTitle) = xs_make_titlestring(pInfo, pInfo->startTune); | 956 (*songTitle) = xs_make_titlestring(pInfo, pInfo->startTune); |
957 | 957 |
958 tmpInt = pInfo->subTunes[pInfo->startTune-1].tuneLength; | 958 tmpInt = pInfo->subTunes[pInfo->startTune-1].tuneLength; |
959 if (tmpInt < 0) | 959 if (tmpInt < 0) |
960 (*songLength) = -1; | 960 (*songLength) = -1; |
961 else | 961 else |
962 (*songLength) = (tmpInt * 1000); | 962 (*songLength) = (tmpInt * 1000); |
963 } | 963 } |
964 | 964 |
965 /* Free tune information */ | 965 /* Free tune information */ |
966 xs_tuneinfo_free(pInfo); | 966 xs_tuneinfo_free(pInfo); |
967 XS_MUTEX_UNLOCK(xs_status); | 967 XS_MUTEX_UNLOCK(xs_status); |
968 } | 968 } |
969 | 969 |