Mercurial > hg > xmms-sid
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 |