Mercurial > audlegacy
annotate src/audacious/output.c @ 2394:e2aaa7dca389 trunk
[svn] - tuple->file_name coming from input plugins have a string with filename + extension, but tuple->file_name coming from input plugins without a get_song_tuple have a string with filename without extension; fix this incongruency, always pass tuple->filename with a string containing filename + extension
author | giacomo |
---|---|
date | Tue, 23 Jan 2007 16:37:13 -0800 |
parents | ad1d7687814c |
children | 719e0898ff3c |
rev | line source |
---|---|
2313 | 1 /* Audacious - Cross-platform multimedia player |
2 * Copyright (C) 2005-2007 Audacious team | |
3 * | |
4 * Based on BMP: | |
5 * Copyright (C) 2003-2004 BMP development team. | |
6 * | |
7 * Based on XMMS: | |
8 * Copyright (C) 1998-2003 XMMS development team. | |
9 * | |
10 * This program is free software; you can redistribute it and/or modify | |
11 * it under the terms of the GNU General Public License as published by | |
12 * the Free Software Foundation; under version 2 of the License. | |
13 * | |
14 * This program is distributed in the hope that it will be useful, | |
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 * GNU General Public License for more details. | |
18 * | |
19 * You should have received a copy of the GNU General Public License | |
20 * along with this program; if not, write to the Free Software | |
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
22 */ | |
23 | |
24 #ifdef HAVE_CONFIG_H | |
25 # include "config.h" | |
26 #endif | |
27 | |
28 #include "output.h" | |
29 #include "iir.h" | |
30 #include "main.h" | |
31 #include "input.h" | |
2328 | 32 #include "playback.h" |
2313 | 33 |
34 #include "playlist.h" | |
35 | |
36 OutputPluginData op_data = { | |
37 NULL, | |
38 NULL | |
39 }; | |
40 | |
41 OutputPluginState op_state = { | |
42 0, | |
43 0, | |
44 0 | |
45 }; | |
46 | |
47 OutputPlugin psuedo_output_plugin = { | |
48 NULL, | |
49 NULL, | |
50 "XMMS reverse compatibility output plugin", | |
51 NULL, | |
52 NULL, | |
53 NULL, | |
54 NULL, | |
55 output_get_volume, | |
56 output_set_volume, | |
57 output_open_audio, | |
58 output_write_audio, | |
59 output_close_audio, | |
60 | |
61 output_flush, | |
62 output_pause, | |
63 output_buffer_free, | |
64 output_buffer_playing, | |
65 get_output_time, | |
66 get_written_time, | |
67 NULL | |
68 }; | |
69 | |
70 OutputPlugin * | |
71 get_current_output_plugin(void) | |
72 { | |
73 return op_data.current_output_plugin; | |
74 } | |
75 | |
76 void | |
77 set_current_output_plugin(gint i) | |
78 { | |
79 gboolean playing; | |
80 OutputPlugin *op = get_current_output_plugin(); | |
81 | |
82 GList *node = g_list_nth(op_data.output_list, i); | |
83 if (!node) { | |
84 op_data.current_output_plugin = NULL; | |
85 return; | |
86 } | |
87 | |
88 op_data.current_output_plugin = node->data; | |
89 | |
90 playing = playback_get_playing(); | |
91 | |
92 if (playing == TRUE) | |
93 { | |
94 guint time, pos; | |
2373
ad1d7687814c
[svn] made strings.h for existing strings.c, cleanups
mf0102
parents:
2328
diff
changeset
|
95 PlaylistEntry *entry; |
2313 | 96 |
2373
ad1d7687814c
[svn] made strings.h for existing strings.c, cleanups
mf0102
parents:
2328
diff
changeset
|
97 /* don't stop yet, get the seek time and playlist position first */ |
2313 | 98 pos = playlist_get_position(playlist_get_active()); |
99 time = op->output_time(); | |
100 | |
2373
ad1d7687814c
[svn] made strings.h for existing strings.c, cleanups
mf0102
parents:
2328
diff
changeset
|
101 /* reset the audio system */ |
2313 | 102 mainwin_stop_pushed(); |
103 op->close_audio(); | |
104 | |
2373
ad1d7687814c
[svn] made strings.h for existing strings.c, cleanups
mf0102
parents:
2328
diff
changeset
|
105 g_usleep(300000); |
2313 | 106 |
2373
ad1d7687814c
[svn] made strings.h for existing strings.c, cleanups
mf0102
parents:
2328
diff
changeset
|
107 /* wait for the playback thread to come online */ |
2313 | 108 while (playback_get_playing()) |
109 g_message("waiting for audio system shutdown..."); | |
110 | |
2373
ad1d7687814c
[svn] made strings.h for existing strings.c, cleanups
mf0102
parents:
2328
diff
changeset
|
111 /* wait for the playback thread to come online */ |
2313 | 112 playlist_set_position(playlist_get_active(), pos); |
2373
ad1d7687814c
[svn] made strings.h for existing strings.c, cleanups
mf0102
parents:
2328
diff
changeset
|
113 entry = playlist_get_entry_to_play(playlist_get_active()); |
2313 | 114 playback_play_file(entry); |
115 | |
2373
ad1d7687814c
[svn] made strings.h for existing strings.c, cleanups
mf0102
parents:
2328
diff
changeset
|
116 while (!playback_get_playing()) |
ad1d7687814c
[svn] made strings.h for existing strings.c, cleanups
mf0102
parents:
2328
diff
changeset
|
117 { |
ad1d7687814c
[svn] made strings.h for existing strings.c, cleanups
mf0102
parents:
2328
diff
changeset
|
118 gtk_main_iteration(); |
ad1d7687814c
[svn] made strings.h for existing strings.c, cleanups
mf0102
parents:
2328
diff
changeset
|
119 g_message("waiting for audio system startup..."); |
ad1d7687814c
[svn] made strings.h for existing strings.c, cleanups
mf0102
parents:
2328
diff
changeset
|
120 } |
2313 | 121 |
2373
ad1d7687814c
[svn] made strings.h for existing strings.c, cleanups
mf0102
parents:
2328
diff
changeset
|
122 /* and signal a reseek */ |
2313 | 123 if (playlist_get_current_length(playlist_get_active()) > -1 && |
124 time <= (playlist_get_current_length(playlist_get_active()))) | |
125 playback_seek(time / 1000); | |
126 } | |
127 } | |
128 | |
129 GList * | |
130 get_output_list(void) | |
131 { | |
132 return op_data.output_list; | |
133 } | |
134 | |
135 void | |
136 output_about(gint i) | |
137 { | |
138 OutputPlugin *out = g_list_nth(op_data.output_list, i)->data; | |
139 if (out && out->about) | |
140 out->about(); | |
141 } | |
142 | |
143 void | |
144 output_configure(gint i) | |
145 { | |
146 OutputPlugin *out = g_list_nth(op_data.output_list, i)->data; | |
147 if (out && out->configure) | |
148 out->configure(); | |
149 } | |
150 | |
151 void | |
152 output_get_volume(gint * l, gint * r) | |
153 { | |
154 *l = *r = -1; | |
155 | |
156 if (!op_data.current_output_plugin) | |
157 return; | |
158 | |
159 if (!op_data.current_output_plugin->get_volume) | |
160 return; | |
161 | |
162 op_data.current_output_plugin->get_volume(l, r); | |
163 } | |
164 | |
165 void | |
166 output_set_volume(gint l, gint r) | |
167 { | |
168 if (!op_data.current_output_plugin) | |
169 return; | |
170 | |
171 if (!op_data.current_output_plugin->set_volume) | |
172 return; | |
173 | |
174 op_data.current_output_plugin->set_volume(l, r); | |
175 } | |
176 | |
177 void | |
178 output_set_eq(gboolean active, gfloat pre, gfloat * bands) | |
179 { | |
180 int i; | |
181 preamp[0] = 1.0 + 0.0932471 * pre + 0.00279033 * pre * pre; | |
182 preamp[1] = 1.0 + 0.0932471 * pre + 0.00279033 * pre * pre; | |
183 | |
184 for (i = 0; i < 10; ++i) | |
185 { | |
2373
ad1d7687814c
[svn] made strings.h for existing strings.c, cleanups
mf0102
parents:
2328
diff
changeset
|
186 set_gain(i, 0, 0.03 * bands[i] + 0.000999999 * bands[i] * bands[i]); |
ad1d7687814c
[svn] made strings.h for existing strings.c, cleanups
mf0102
parents:
2328
diff
changeset
|
187 set_gain(i, 1, 0.03 * bands[i] + 0.000999999 * bands[i] * bands[i]); |
2313 | 188 } |
189 } | |
190 | |
191 /* this should be in BYTES, NOT gint16s */ | |
192 static void | |
193 byteswap(size_t size, | |
194 gint16 * buf) | |
195 { | |
196 gint16 *it; | |
197 size &= ~1; /* must be multiple of 2 */ | |
198 for (it = buf; it < buf + size / 2; ++it) | |
199 *(guint16 *) it = GUINT16_SWAP_LE_BE(*(guint16 *) it); | |
200 } | |
201 | |
202 /* called by input plugin to peek at the output plugin's write progress */ | |
203 gint | |
204 get_written_time(void) | |
205 { | |
206 OutputPlugin *op = get_current_output_plugin(); | |
207 | |
208 return op->written_time(); | |
209 } | |
210 | |
211 /* called by input plugin to peek at the output plugin's output progress */ | |
212 gint | |
213 get_output_time(void) | |
214 { | |
215 OutputPlugin *op = get_current_output_plugin(); | |
216 | |
217 return op->output_time(); | |
218 } | |
219 | |
220 gint | |
221 output_open_audio(AFormat fmt, gint rate, gint nch) | |
222 { | |
223 gint ret; | |
224 OutputPlugin *op; | |
225 | |
226 op = get_current_output_plugin(); | |
227 | |
228 if (op == NULL) | |
229 return -1; | |
230 | |
231 /* Is our output port already open? */ | |
232 if ((op_state.rate != 0 && op_state.nch != 0) && | |
2373
ad1d7687814c
[svn] made strings.h for existing strings.c, cleanups
mf0102
parents:
2328
diff
changeset
|
233 (op_state.rate == rate && op_state.nch == nch && op_state.fmt == fmt)) |
2313 | 234 { |
2373
ad1d7687814c
[svn] made strings.h for existing strings.c, cleanups
mf0102
parents:
2328
diff
changeset
|
235 /* Yes, and it's the correct sampling rate. Reset the counter and go. */ |
ad1d7687814c
[svn] made strings.h for existing strings.c, cleanups
mf0102
parents:
2328
diff
changeset
|
236 op->flush(0); |
2313 | 237 return 1; |
238 } | |
239 else if (op_state.rate != 0 && op_state.nch != 0) | |
2373
ad1d7687814c
[svn] made strings.h for existing strings.c, cleanups
mf0102
parents:
2328
diff
changeset
|
240 op->close_audio(); |
2313 | 241 |
242 ret = op->open_audio(fmt, rate, nch); | |
243 | |
2373
ad1d7687814c
[svn] made strings.h for existing strings.c, cleanups
mf0102
parents:
2328
diff
changeset
|
244 if (ret == 1) /* Success? */ |
2313 | 245 { |
246 op_state.fmt = fmt; | |
247 op_state.rate = rate; | |
248 op_state.nch = nch; | |
249 } | |
250 | |
251 return ret; | |
252 } | |
253 | |
254 void | |
255 output_write_audio(gpointer ptr, gint length) | |
256 { | |
257 OutputPlugin *op = get_current_output_plugin(); | |
258 | |
259 /* Sanity check. */ | |
260 if (op == NULL) | |
261 return; | |
262 | |
263 op->write_audio(ptr, length); | |
264 } | |
265 | |
266 void | |
267 output_close_audio(void) | |
268 { | |
269 OutputPlugin *op = get_current_output_plugin(); | |
270 | |
271 /* Do not close if there are still songs to play and the user has | |
272 * not requested a stop. --nenolod | |
273 */ | |
274 if (ip_data.stop == FALSE && | |
2373
ad1d7687814c
[svn] made strings.h for existing strings.c, cleanups
mf0102
parents:
2328
diff
changeset
|
275 (playlist_get_position_nolock(playlist_get_active()) < playlist_get_length_nolock(playlist_get_active()) - 1)) |
2313 | 276 return; |
277 | |
278 /* Sanity check. */ | |
279 if (op == NULL) | |
280 return; | |
281 | |
282 op->close_audio(); | |
283 | |
284 /* Reset the op_state. */ | |
285 op_state.fmt = op_state.rate = op_state.nch = 0; | |
286 } | |
287 | |
288 void | |
289 output_flush(gint time) | |
290 { | |
291 OutputPlugin *op = get_current_output_plugin(); | |
292 | |
293 if (op == NULL) | |
294 return; | |
295 | |
296 op->flush(time); | |
297 } | |
298 | |
299 void | |
300 output_pause(gshort paused) | |
301 { | |
302 OutputPlugin *op = get_current_output_plugin(); | |
303 | |
304 if (op == NULL) | |
305 return; | |
306 | |
307 op->pause(paused); | |
308 } | |
309 | |
310 gint | |
311 output_buffer_free(void) | |
312 { | |
313 OutputPlugin *op = get_current_output_plugin(); | |
314 | |
315 if (op == NULL) | |
316 return 0; | |
317 | |
318 return op->buffer_free(); | |
319 } | |
320 | |
321 gint | |
322 output_buffer_playing(void) | |
323 { | |
324 OutputPlugin *op = get_current_output_plugin(); | |
325 | |
326 if (op == NULL) | |
327 return 0; | |
328 | |
329 return op->buffer_playing(); | |
330 } | |
331 | |
332 /* called by input plugin when data is ready */ | |
333 void | |
334 produce_audio(gint time, /* position */ | |
335 AFormat fmt, /* output format */ | |
336 gint nch, /* channels */ | |
337 gint length, /* length of sample */ | |
338 gpointer ptr, /* data */ | |
339 int *going /* 0 when time to stop */ | |
340 ) | |
341 { | |
342 static int init = 0; | |
343 int swapped = 0; | |
344 guint myorder = G_BYTE_ORDER == G_LITTLE_ENDIAN ? FMT_S16_LE : FMT_S16_BE; | |
345 int caneq = (fmt == FMT_S16_NE || fmt == myorder); | |
346 OutputPlugin *op = get_current_output_plugin(); | |
347 int writeoffs; | |
348 | |
2373
ad1d7687814c
[svn] made strings.h for existing strings.c, cleanups
mf0102
parents:
2328
diff
changeset
|
349 if (!caneq && cfg.equalizer_active) { /* wrong byte order */ |
ad1d7687814c
[svn] made strings.h for existing strings.c, cleanups
mf0102
parents:
2328
diff
changeset
|
350 byteswap(length, ptr); /* so convert */ |
2313 | 351 ++swapped; |
352 ++caneq; | |
2373
ad1d7687814c
[svn] made strings.h for existing strings.c, cleanups
mf0102
parents:
2328
diff
changeset
|
353 } /* can eq now, mark swapd */ |
ad1d7687814c
[svn] made strings.h for existing strings.c, cleanups
mf0102
parents:
2328
diff
changeset
|
354 else if (caneq && !cfg.equalizer_active) /* right order but no eq */ |
ad1d7687814c
[svn] made strings.h for existing strings.c, cleanups
mf0102
parents:
2328
diff
changeset
|
355 caneq = 0; /* so don't eq */ |
2313 | 356 |
2373
ad1d7687814c
[svn] made strings.h for existing strings.c, cleanups
mf0102
parents:
2328
diff
changeset
|
357 if (caneq) { /* if eq enab */ |
ad1d7687814c
[svn] made strings.h for existing strings.c, cleanups
mf0102
parents:
2328
diff
changeset
|
358 if (!init) { /* if first run */ |
ad1d7687814c
[svn] made strings.h for existing strings.c, cleanups
mf0102
parents:
2328
diff
changeset
|
359 init_iir(); /* then init eq */ |
2313 | 360 ++init; |
361 } | |
362 | |
363 iir(&ptr, length, nch); | |
364 | |
2373
ad1d7687814c
[svn] made strings.h for existing strings.c, cleanups
mf0102
parents:
2328
diff
changeset
|
365 if (swapped) /* if was swapped */ |
ad1d7687814c
[svn] made strings.h for existing strings.c, cleanups
mf0102
parents:
2328
diff
changeset
|
366 byteswap(length, ptr); /* swap back for output */ |
2313 | 367 } |
368 | |
369 /* do vis plugin(s) */ | |
370 input_add_vis_pcm(time, fmt, nch, length, ptr); | |
371 | |
372 writeoffs = 0; | |
2373
ad1d7687814c
[svn] made strings.h for existing strings.c, cleanups
mf0102
parents:
2328
diff
changeset
|
373 while (writeoffs < length) |
ad1d7687814c
[svn] made strings.h for existing strings.c, cleanups
mf0102
parents:
2328
diff
changeset
|
374 { |
ad1d7687814c
[svn] made strings.h for existing strings.c, cleanups
mf0102
parents:
2328
diff
changeset
|
375 int writable = length - writeoffs; |
2313 | 376 |
2373
ad1d7687814c
[svn] made strings.h for existing strings.c, cleanups
mf0102
parents:
2328
diff
changeset
|
377 if (writable > 2048) |
ad1d7687814c
[svn] made strings.h for existing strings.c, cleanups
mf0102
parents:
2328
diff
changeset
|
378 writable = 2048; |
2313 | 379 |
2373
ad1d7687814c
[svn] made strings.h for existing strings.c, cleanups
mf0102
parents:
2328
diff
changeset
|
380 if (writable == 0) |
ad1d7687814c
[svn] made strings.h for existing strings.c, cleanups
mf0102
parents:
2328
diff
changeset
|
381 return; |
2313 | 382 |
2373
ad1d7687814c
[svn] made strings.h for existing strings.c, cleanups
mf0102
parents:
2328
diff
changeset
|
383 while (op->buffer_free() < writable) { /* wait output buf */ |
ad1d7687814c
[svn] made strings.h for existing strings.c, cleanups
mf0102
parents:
2328
diff
changeset
|
384 if (going && !*going) /* thread stopped? */ |
ad1d7687814c
[svn] made strings.h for existing strings.c, cleanups
mf0102
parents:
2328
diff
changeset
|
385 return; /* so finish */ |
2313 | 386 |
2373
ad1d7687814c
[svn] made strings.h for existing strings.c, cleanups
mf0102
parents:
2328
diff
changeset
|
387 if (ip_data.stop) /* has a stop been requested? */ |
ad1d7687814c
[svn] made strings.h for existing strings.c, cleanups
mf0102
parents:
2328
diff
changeset
|
388 return; /* yes, so finish */ |
2313 | 389 |
2373
ad1d7687814c
[svn] made strings.h for existing strings.c, cleanups
mf0102
parents:
2328
diff
changeset
|
390 g_usleep(10000); /* else sleep for retry */ |
ad1d7687814c
[svn] made strings.h for existing strings.c, cleanups
mf0102
parents:
2328
diff
changeset
|
391 } |
2313 | 392 |
2373
ad1d7687814c
[svn] made strings.h for existing strings.c, cleanups
mf0102
parents:
2328
diff
changeset
|
393 if (ip_data.stop) |
ad1d7687814c
[svn] made strings.h for existing strings.c, cleanups
mf0102
parents:
2328
diff
changeset
|
394 return; |
2313 | 395 |
2373
ad1d7687814c
[svn] made strings.h for existing strings.c, cleanups
mf0102
parents:
2328
diff
changeset
|
396 if (going && !*going) /* thread stopped? */ |
ad1d7687814c
[svn] made strings.h for existing strings.c, cleanups
mf0102
parents:
2328
diff
changeset
|
397 return; /* so finish */ |
2313 | 398 |
2373
ad1d7687814c
[svn] made strings.h for existing strings.c, cleanups
mf0102
parents:
2328
diff
changeset
|
399 /* do output */ |
ad1d7687814c
[svn] made strings.h for existing strings.c, cleanups
mf0102
parents:
2328
diff
changeset
|
400 op->write_audio(((guint8 *) ptr) + writeoffs, writable); |
2313 | 401 |
2373
ad1d7687814c
[svn] made strings.h for existing strings.c, cleanups
mf0102
parents:
2328
diff
changeset
|
402 writeoffs += writable; |
2313 | 403 } |
404 } |