comparison src/xmms-sid.c @ 71:2b32c75729ce

Started modularizing, separated sidplay1 things into a "wrapper" module. Removed non-generic stuff from xmms-sid.cc, removed C++ references and renamed to xmms-sid.c
author Matti Hamalainen <ccr@tnsp.org>
date Wed, 10 Sep 2003 06:21:04 +0000
parents
children e3b205a6bc7e
comparison
equal deleted inserted replaced
70:ec31a68bbc2c 71:2b32c75729ce
1 /*
2 XMMS-SID - SIDPlay input plugin for X MultiMedia System (XMMS)
3
4 Main source file
5
6 Written by Matti "ccr" Hamalainen <ccr@tnsp.org>
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 */
22 #include <pthread.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <stdio.h>
26 #include <errno.h>
27
28 #include <xmms/plugin.h>
29
30 #include "xmms-sid.h"
31 #include "xs_support.h"
32 #include "xs_config.h"
33 #include "xs_length.h"
34 #include "xs_interface.h"
35 #include "xs_glade.h"
36
37 /*
38 * Include player engines
39 */
40 #include "xs_sidplay1.h"
41 #include "xs_sidplay2.h"
42
43
44 /*
45 * Global variables
46 */
47 static GtkWidget *xs_ctrlwin = NULL;
48 static pthread_t xs_decode_thread;
49 static pthread_mutex_t xs_mutex = PTHREAD_MUTEX_INITIALIZER;
50 struct t_xs_cfg xs_cfg;
51
52
53 /*
54 * Create sub-song control window
55 */
56 void xs_ctrlwin_open(void)
57 {
58 /* Create sub-song control window */
59 if (xs_ctrlwin != NULL)
60 {
61 if (xs_cfg.alwaysRaise)
62 gdk_window_raise(xs_ctrlwin->window);
63 return;
64 }
65
66 xs_ctrlwin = create_xs_ctrlwin();
67 gtk_widget_show(xs_ctrlwin);
68 }
69
70
71 /*
72 * Initialize XMMS-SID
73 */
74 void xs_init(void)
75 {
76 XSDEBUG("xs_init()\n");
77
78 /* Initialize and get configuration */
79 memset(&xs_cfg, 0, sizeof(xs_cfg));
80
81 xs_read_configuration();
82
83 /* Initialize status */
84 memset(&xs_status, 0, sizeof(xs_status));
85 xs_status.allowNext = TRUE; // Initialize to TRUE to allow first song
86
87 /* Try to initialize emulator engine(s) */
88 XSDEBUG("initializing emulator engine(s)...\n");
89
90
91
92
93 /* Read song-length database */
94 if (xs_cfg.songlenDBEnable && (xs_songlen_init() < 0))
95 {
96 XSERR("Error initializing song-length database!\n");
97 }
98
99 /* Initialize STIL structures */
100
101 // xs_ctrlwin_open();
102
103 // FIXME FIXME FIx ME
104
105 XSDEBUG("OK\n");
106 }
107
108
109 /*
110 * Shut down XMMS-SID
111 */
112 void xs_close(void)
113 {
114 XSDEBUG("xs_close(): shutting down...\n");
115
116 /* Stop playing */
117 xs_stop();
118
119 /* Shutdown libSIDPlay(s) */
120
121
122
123
124
125
126 /* Close sub-song control window */
127
128 /* Free allocated memory */
129 xs_songlen_close();
130
131 // FIXME FIXME: STIL-entries
132 XSDEBUG("shutdown finished.\n");
133 }
134
135
136 /*
137 * Main playing thread loop
138 */
139 void *xs_play_loop(void *argPointer)
140 {
141 t_xs_status myStatus;
142 t_xs_tuneinfo tuneInfo;
143 gboolean audioOpen;
144 gint audioFreq, audioChannels, songLength;
145 enum AFormat audioFmt;
146 gchar audioBuffer[XS_BUFSIZE];
147 gchar *tmpStr;
148
149
150 pthread_mutex_lock(&xs_mutex);
151 XSDEBUG("entering play thread\n");
152
153 /* No idea, if this is really required here, but better be
154 * careful since we're dealing with EVIL threads ...
155 */
156 if (!xs_status.allowNext)
157 {
158 pthread_mutex_unlock(&xs_mutex);
159 pthread_exit(NULL);
160 }
161
162 /* Don't allow next song to be set yet */
163 xs_status.allowNext = FALSE;
164 xs_status.isPlaying = TRUE;
165 memcpy(&myStatus, &xs_status, sizeof(t_xs_status));
166 pthread_mutex_unlock(&xs_mutex);
167
168
169 /* Copy and check audio options here (they might change in config while running) */
170 #ifdef HAVE_UNSIGNEDPCM
171 audioFmt = (xs_cfg.fmtBitsPerSample == XS_RES_16BIT) ? FMT_U16_NE : FMT_U8;
172 #else
173 audioFmt = (xs_cfg.fmtBitsPerSample == XS_RES_16BIT) ? FMT_S16_NE : FMT_S8;
174 #endif
175 audioFreq = xs_cfg.fmtFrequency;
176 audioChannels = (xs_cfg.fmtChannels == XS_CHN_MONO) ? 1 : 2;
177 audioOpen = FALSE;
178
179 /*
180 * Main player loop: while not stopped, loop here - play subtunes
181 */
182 while (xs_status.isPlaying)
183 {
184 pthread_mutex_lock(&xs_mutex);
185 myStatus.currSong = xs_status.currSong;
186 myStatus.isPlaying = TRUE;
187 pthread_mutex_unlock(&xs_mutex);
188
189 XSDEBUG("subtune #%i selected, initializing...\n", myStatus.currSong);
190
191
192 /* Get song length for current subtune */
193 songLength = xs_songlen_get(myStatus.currFileName, myStatus.currSong);
194
195 /* Initialize song */
196 #ifdef HAVE_SIDPLAY1
197 if ((myStatus.currTune == NULL) || !myStatus.currTune->getStatus() ||
198 !sidEmuInitializeSong(xs_emuEngine, *myStatus.currTune, myStatus.currSong))
199 #endif
200 #ifdef HAVE_SIDPLAY2
201 if ()
202 #endif
203 {
204 XSERR("Couldn't initialize SID-tune '%s' (sub-tune #%i)!\n",
205 myStatus.currFileName, myStatus.currSong);
206 goto err_exit;
207 }
208
209 myStatus.currTune->getInfo(tuneInfo);
210
211
212 /* Set information for current sub-tune */
213 tmpStr = xs_filetitle_get(myStatus.currFileName, &tuneInfo, myStatus.currSong);
214
215 xs_plugin_ip.set_info(tmpStr, (songLength > 0) ? songLength * 1000 : -1,
216 1000 * (tuneInfo.songSpeed ? tuneInfo.songSpeed : (tuneInfo.clockSpeed == SIDTUNE_CLOCK_NTSC) ? 60 : 50),
217 audioFreq, audioChannels);
218 g_free(tmpStr);
219
220 /* Open the audio output */
221 if (!xs_plugin_ip.output->open_audio(audioFmt, audioFreq, audioChannels))
222 {
223 XSERR("Couldn't open XMMS audio output!\n");
224 pthread_mutex_lock(&xs_mutex);
225 xs_status.isError = TRUE;
226 pthread_mutex_unlock(&xs_mutex);
227 goto err_exit;
228 }
229
230 audioOpen = TRUE;
231
232 /*
233 * Play the subtune
234 */
235 while (xs_status.isPlaying && myStatus.isPlaying && (xs_status.currSong == myStatus.currSong))
236 {
237 /* Render audio data */
238 #ifdef HAVE_SIDPLAY1
239 sidEmuFillBuffer(xs_emuEngine, *myStatus.currTune, audioBuffer, XS_BUFSIZE);
240 #endif
241 #ifdef HAVE_SIDPLAY2
242 #endif
243
244 /* I <3 visualice/haujobb */
245 xs_plugin_ip.add_vis_pcm(
246 xs_plugin_ip.output->written_time(),
247 audioFmt, audioChannels, XS_BUFSIZE, audioBuffer);
248
249 /* Wait a little */
250 while (xs_status.isPlaying &&
251 (xs_status.currSong == myStatus.currSong) &&
252 (xs_plugin_ip.output->buffer_free() < XS_BUFSIZE))
253 xmms_usleep(10000);
254
255 /* Output audio */
256 if (xs_status.isPlaying && (xs_status.currSong == myStatus.currSong))
257 xs_plugin_ip.output->write_audio(audioBuffer, XS_BUFSIZE);
258
259 /* Check if we have played enough */
260 if (xs_cfg.playMaxTimeEnable)
261 {
262 if (xs_cfg.playMaxTimeUnknown)
263 {
264 if ((songLength == -1) &&
265 (xs_plugin_ip.output->output_time() >= (xs_cfg.playMaxTime * 1000)))
266 myStatus.isPlaying = FALSE;
267 } else {
268 if (xs_plugin_ip.output->output_time() >= (xs_cfg.playMaxTime * 1000))
269 myStatus.isPlaying = FALSE;
270 }
271 }
272
273 if (songLength > 0)
274 {
275 if (xs_plugin_ip.output->output_time() >= (songLength * 1000))
276 myStatus.isPlaying = FALSE;
277 }
278 }
279
280 XSDEBUG("subtune ended/stopped\n");
281
282 /* Close audio */
283 if (audioOpen)
284 {
285 XSDEBUG("close audio #1\n");
286 xs_plugin_ip.output->close_audio();
287 audioOpen = FALSE;
288 }
289
290 /* Now determine if we continue by selecting other subtune or something */
291 if (!myStatus.isPlaying) xs_status.isPlaying = FALSE;
292 }
293
294 /* When exiting, delete data */
295 err_exit:
296 pthread_mutex_lock(&xs_mutex);
297 xs_status.isPlaying = FALSE;
298 pthread_mutex_unlock(&xs_mutex);
299
300 if (audioOpen)
301 {
302 XSDEBUG("close audio #2\n");
303 xs_plugin_ip.output->close_audio();
304 }
305
306 if (myStatus.currTune != NULL)
307 {
308 delete myStatus.currTune;
309 myStatus.currTune = NULL;
310 }
311
312 g_free(myStatus.currFileName);
313
314 /* Exit the playing thread */
315 XSDEBUG("exiting thread, bye.\n");
316
317 /* Last thing we do is set allowNext to TRUE to flag
318 * that we have ended all action in the thread
319 */
320 pthread_mutex_lock(&xs_mutex);
321 xs_status.allowNext = TRUE;
322 pthread_mutex_unlock(&xs_mutex);
323
324 pthread_exit(NULL);
325 }
326
327
328 /*
329 * Start playing the given file
330 */
331 void xs_play_file(char *pcFileName)
332 {
333 }
334
335
336 /*
337 * Stop playing
338 */
339 void xs_stop(void)
340 {
341 /* If playing, stop. */
342 XSDEBUG("STOP_REQ\n");
343 if (xs_status.isPlaying || !xs_status.allowNext)
344 {
345 XSDEBUG("stopping...\n");
346 pthread_mutex_lock(&xs_mutex);
347 xs_status.isPlaying = FALSE;
348 pthread_mutex_unlock(&xs_mutex);
349 pthread_join(xs_decode_thread, NULL);
350 }
351 }
352
353
354 /*
355 * Pause the playing
356 */
357 void xs_pause(short pauseState)
358 {
359 xs_plugin_ip.output->pause(pauseState);
360 }
361
362
363 /*
364 * Set the time-seek position
365 * (the playing thread will do the "seeking" aka song-change)
366 */
367 void xs_seek(gint iTime)
368 {
369 /* If we have song-position patch, check settings */
370 #ifdef HAVE_SONG_POSITION
371 pthread_mutex_lock(&xs_mutex);
372
373 if ((iTime > 0) && (iTime <= xs_status.nSongs) && xs_status.isPlaying)
374 xs_status.currSong = iTime;
375
376 pthread_mutex_unlock(&xs_mutex);
377 #endif
378 }
379
380
381 /*
382 * Return the playing "position/time"
383 */
384 gint xs_get_time(void)
385 {
386 /* If errorflag is set, return -2 to signal it to XMMS's idle callback */
387 if (xs_status.isError)
388 return -2;
389
390 /* If tune has ended, return -1 */
391 if (xs_status.allowNext && !xs_status.isPlaying)
392 return -1;
393
394 /* Obsolete? */
395 #ifdef HAVE_SONG_POSITION
396 pthread_mutex_lock(&xs_mutex);
397 set_song_position(xs_status.currSong, 1, xs_status.nSongs);
398 pthread_mutex_unlock(&xs_mutex);
399 #endif
400
401 /* Else, return output time reported by audio output plugin */
402 return xs_plugin_ip.output->output_time();
403 }
404
405