comparison src/sexypsf/plugin.c @ 1203:6eef4486e481

Fixed hangs when outputting to FileWriter and improved readability in general
author michi@tux.homenetwork
date Mon, 02 Jul 2007 23:02:43 +0200
parents
children e9f10dac2f63
comparison
equal deleted inserted replaced
1202:82ef51e8934a 1203:6eef4486e481
1 /* sexyPSF - PSF1 player
2 * Copyright (C) 2002-2004 xodnizel
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19 #include "audacious/output.h"
20 #include "audacious/plugin.h"
21 #include "audacious/titlestring.h"
22 #include "audacious/util.h"
23 #include "audacious/vfs.h"
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <unistd.h>
28 #include "driver.h"
29
30 static volatile int seek = 0;
31 static volatile gboolean playing = FALSE;
32 static volatile gboolean paused = FALSE;
33 static volatile gboolean stop = FALSE;
34 static volatile gboolean nextsong = FALSE;
35
36 extern InputPlugin sexypsf_ip;
37 static gboolean audio_error = FALSE;
38
39 static PSFINFO *PSFInfo = NULL;
40 static gchar *fnsave = NULL;
41 static GThread *dethread = NULL;
42 static InputPlayback *playback = NULL;
43
44 static gchar *get_title_psf(gchar *fn);
45
46 static int is_our_fd(gchar *filename, VFSFile *file) {
47 gchar magic[4];
48 vfs_fread(magic, 1, 4, file);
49
50 // only allow PSF1 for now
51 if (!memcmp(magic, "PSF\x01", 4))
52 return 1;
53 return 0;
54 }
55
56
57 void sexypsf_update(unsigned char *buffer, long count)
58 {
59 const int mask = ~((((16 / 8) * 2)) - 1);
60
61 while (count > 0)
62 {
63 int t = playback->output->buffer_free() & mask;
64 if (t > count)
65 produce_audio(playback->output->written_time(), FMT_S16_NE, 2, count, buffer, NULL);
66 else
67 {
68 if (t)
69 produce_audio(playback->output->written_time(), FMT_S16_NE, 2, t, buffer, NULL);
70 g_usleep((count-t)*1000*5/441/2);
71 }
72 count -= t;
73 buffer += t;
74 }
75 if (seek)
76 {
77 if(sexypsf_seek(seek))
78 {
79 playback->output->flush(seek);
80 seek = 0;
81 }
82 else // negative time - must make a C time machine
83 {
84 sexypsf_stop();
85 return;
86 }
87 }
88 if (stop)
89 sexypsf_stop();
90 }
91
92 static gpointer sexypsf_playloop(gpointer arg)
93 {
94 while (TRUE)
95 {
96 sexypsf_execute();
97
98 /* we have reached the end of the song or a command was issued */
99
100 playback->output->buffer_free();
101 playback->output->buffer_free();
102
103 if (stop)
104 break;
105
106 if (seek)
107 {
108 playback->output->flush(seek);
109 if(!(PSFInfo = sexypsf_load(fnsave)))
110 break;
111 sexypsf_seek(seek);
112 seek = 0;
113 continue;
114 }
115
116 break;
117 }
118
119 playback->output->close_audio();
120 if (!(stop)) nextsong = TRUE;
121 g_thread_exit(NULL);
122 return NULL;
123 }
124
125 static void sexypsf_xmms_play(InputPlayback *data)
126 {
127 if (playing)
128 return;
129
130 playback = data;
131 nextsong = FALSE;
132 paused = FALSE;
133
134 if (!playback->output->open_audio(FMT_S16_NE, 44100, 2))
135 {
136 audio_error = TRUE;
137 return;
138 }
139
140 fnsave = malloc(strlen(data->filename)+1);
141 strcpy(fnsave, data->filename);
142 if(!(PSFInfo=sexypsf_load(data->filename)))
143 {
144 playback->output->close_audio();
145 nextsong = 1;
146 }
147 else
148 {
149 stop = seek = 0;
150
151 gchar *name = get_title_psf(data->filename);
152 sexypsf_ip.set_info(name, PSFInfo->length, 44100*2*2*8, 44100, 2);
153 g_free(name);
154
155 playing = 1;
156 dethread = g_thread_create((GThreadFunc)sexypsf_playloop,
157 NULL, TRUE, NULL);
158 }
159 }
160
161 static void sexypsf_xmms_stop(InputPlayback * playback)
162 {
163 if (!playing) return;
164
165 if (paused)
166 playback->output->pause(0);
167 paused = FALSE;
168
169 stop = TRUE;
170 g_thread_join(dethread);
171 playing = FALSE;
172
173 if (fnsave)
174 {
175 free(fnsave);
176 fnsave = NULL;
177 }
178 sexypsf_freepsfinfo(PSFInfo);
179 PSFInfo = NULL;
180 }
181
182 static void sexypsf_xmms_pause(InputPlayback *playback, short p)
183 {
184 if (!playing) return;
185 playback->output->pause(p);
186 paused = p;
187 }
188
189 static void sexypsf_xmms_seek(InputPlayback * data, int time)
190 {
191 if (!playing) return;
192 seek = time * 1000;
193 }
194
195 static int sexypsf_xmms_gettime(InputPlayback *playback)
196 {
197 if (audio_error)
198 return -2;
199 if (nextsong)
200 return -1;
201 if (!playing)
202 return 0;
203 return playback->output->output_time();
204 }
205
206 static void sexypsf_xmms_getsonginfo(char *fn, char **title, int *length)
207 {
208 PSFINFO *tmp;
209
210 if((tmp = sexypsf_getpsfinfo(fn))) {
211 *length = tmp->length;
212 *title = get_title_psf(fn);
213 sexypsf_freepsfinfo(tmp);
214 }
215 }
216
217 static TitleInput *get_tuple_psf(gchar *fn) {
218 TitleInput *tuple = NULL;
219 PSFINFO *tmp = sexypsf_getpsfinfo(fn);
220
221 if (tmp->length) {
222 tuple = bmp_title_input_new();
223 tuple->length = tmp->length;
224 tuple->performer = g_strdup(tmp->artist);
225 tuple->album_name = g_strdup(tmp->game);
226 tuple->track_name = g_strdup(tmp->title);
227 tuple->file_name = g_path_get_basename(fn);
228 tuple->file_path = g_path_get_dirname(fn);
229 sexypsf_freepsfinfo(tmp);
230 }
231
232 return tuple;
233 }
234
235 static gchar *get_title_psf(gchar *fn) {
236 gchar *title = NULL;
237 TitleInput *tinput = get_tuple_psf(fn);
238
239 if (tinput != NULL) {
240 title = xmms_get_titlestring(xmms_get_gentitle_format(),
241 tinput);
242 bmp_title_input_free(tinput);
243 }
244 else
245 title = g_path_get_basename(fn);
246
247 return title;
248 }
249
250 gchar *sexypsf_fmts[] = { "psf", "minipsf", NULL };
251
252 InputPlugin sexypsf_ip =
253 {
254 NULL,
255 NULL,
256 "PSF Audio Plugin",
257 NULL,
258 NULL,
259 NULL,
260 NULL,
261 NULL,
262 sexypsf_xmms_play,
263 sexypsf_xmms_stop,
264 sexypsf_xmms_pause,
265 sexypsf_xmms_seek,
266 NULL,
267 sexypsf_xmms_gettime,
268 NULL,
269 NULL,
270 NULL,
271 NULL,
272 NULL,
273 NULL,
274 NULL,
275 sexypsf_xmms_getsonginfo,
276 NULL,
277 NULL,
278 get_tuple_psf,
279 NULL,
280 NULL,
281 is_our_fd,
282 sexypsf_fmts,
283 };
284
285 InputPlugin *sexypsf_iplist[] = { &sexypsf_ip, NULL };
286
287 DECLARE_PLUGIN(sexypsf, NULL, NULL, sexypsf_iplist, NULL, NULL, NULL, NULL);