Mercurial > audlegacy
annotate Plugins/Input/console/Audacious_Driver.cpp @ 213:ab8ce2fb05d0 trunk
[svn] Implement NSF playback.
author | chainsaw |
---|---|
date | Sun, 20 Nov 2005 10:57:10 -0800 |
parents | 1997ecd9dcb1 |
children | 03d9180e3c87 |
rev | line source |
---|---|
90
252843aac42f
[svn] Import the initial sources for console music support.
nenolod
parents:
diff
changeset
|
1 /* |
252843aac42f
[svn] Import the initial sources for console music support.
nenolod
parents:
diff
changeset
|
2 * Audacious: Cross platform multimedia player |
252843aac42f
[svn] Import the initial sources for console music support.
nenolod
parents:
diff
changeset
|
3 * Copyright (c) 2005 Audacious Team |
252843aac42f
[svn] Import the initial sources for console music support.
nenolod
parents:
diff
changeset
|
4 * |
252843aac42f
[svn] Import the initial sources for console music support.
nenolod
parents:
diff
changeset
|
5 * Driver for Game_Music_Emu library. See details at: |
252843aac42f
[svn] Import the initial sources for console music support.
nenolod
parents:
diff
changeset
|
6 * http://www.slack.net/~ant/libs/ |
252843aac42f
[svn] Import the initial sources for console music support.
nenolod
parents:
diff
changeset
|
7 */ |
252843aac42f
[svn] Import the initial sources for console music support.
nenolod
parents:
diff
changeset
|
8 |
94 | 9 #include "Audacious_Driver.h" |
90
252843aac42f
[svn] Import the initial sources for console music support.
nenolod
parents:
diff
changeset
|
10 |
98
e42694a28331
[svn] More progress -- now loads as an audacious module. :)
nenolod
parents:
96
diff
changeset
|
11 extern "C" { |
e42694a28331
[svn] More progress -- now loads as an audacious module. :)
nenolod
parents:
96
diff
changeset
|
12 |
109 | 13 #include <glib.h> |
96 | 14 #include <glib/gi18n.h> |
109 | 15 #include <gtk/gtk.h> |
94 | 16 #include "libaudacious/configfile.h" |
17 #include "libaudacious/util.h" | |
18 #include "libaudacious/titlestring.h" | |
145 | 19 #include "audacious/input.h" |
95 | 20 #include "audacious/output.h" |
145 | 21 #include "audacious/playback.h" |
94 | 22 |
98
e42694a28331
[svn] More progress -- now loads as an audacious module. :)
nenolod
parents:
96
diff
changeset
|
23 }; |
e42694a28331
[svn] More progress -- now loads as an audacious module. :)
nenolod
parents:
96
diff
changeset
|
24 |
145 | 25 struct AudaciousConsoleConfig audcfg = { 180, FALSE, 32000 }; |
26 | |
94 | 27 #include <cstring> |
213 | 28 #include <stdio.h> |
94 | 29 |
101
59ba6595fdf1
[svn] More accurate sound reproduction, but there is warbling. Still locks up player on completion.
nenolod
parents:
100
diff
changeset
|
30 #ifdef WORDS_BIGENDIAN |
59ba6595fdf1
[svn] More accurate sound reproduction, but there is warbling. Still locks up player on completion.
nenolod
parents:
100
diff
changeset
|
31 # define MY_FMT FMT_S16_BE |
59ba6595fdf1
[svn] More accurate sound reproduction, but there is warbling. Still locks up player on completion.
nenolod
parents:
100
diff
changeset
|
32 #else |
59ba6595fdf1
[svn] More accurate sound reproduction, but there is warbling. Still locks up player on completion.
nenolod
parents:
100
diff
changeset
|
33 # define MY_FMT FMT_S16_LE |
59ba6595fdf1
[svn] More accurate sound reproduction, but there is warbling. Still locks up player on completion.
nenolod
parents:
100
diff
changeset
|
34 #endif |
59ba6595fdf1
[svn] More accurate sound reproduction, but there is warbling. Still locks up player on completion.
nenolod
parents:
100
diff
changeset
|
35 |
94 | 36 static Spc_Emu *spc = NULL; |
213 | 37 static Nsf_Emu *nsf = NULL; |
95 | 38 static GThread *decode_thread; |
213 | 39 GStaticMutex playback_mutex = G_STATIC_MUTEX_INIT; |
95 | 40 |
147
6fe2bfbe6fc2
[svn] Move SPC-specific code into SPC-specific routines.
nenolod
parents:
146
diff
changeset
|
41 static void *play_loop_spc(gpointer arg); |
213 | 42 static void *play_loop_nsf(gpointer arg); |
100 | 43 static void console_init(void); |
109 | 44 extern "C" void console_aboutbox(void); |
96 | 45 static void console_stop(void); |
46 static void console_pause(gshort p); | |
47 static int get_time(void); | |
103 | 48 static gboolean console_ip_is_going; |
100 | 49 extern InputPlugin console_ip; |
147
6fe2bfbe6fc2
[svn] Move SPC-specific code into SPC-specific routines.
nenolod
parents:
146
diff
changeset
|
50 static int playing_type; |
100 | 51 |
94 | 52 static int is_our_file(gchar *filename) |
53 { | |
54 gchar *ext; | |
55 | |
56 ext = strrchr(filename, '.'); | |
57 | |
58 if (ext) | |
59 { | |
60 if (!strcasecmp(ext, ".spc")) | |
213 | 61 return PLAY_TYPE_SPC; |
62 if (!strcasecmp(ext, ".nsf")) | |
63 return PLAY_TYPE_NSF; | |
94 | 64 } |
65 | |
66 return 0; | |
67 } | |
68 | |
148 | 69 static gchar *get_title_spc(gchar *filename) |
94 | 70 { |
71 gchar *title; | |
72 Emu_Std_Reader reader; | |
73 Spc_Emu::header_t header; | |
74 | |
75 reader.open(filename); | |
76 reader.read(&header, sizeof(header)); | |
77 | |
104 | 78 if (header.song) |
79 { | |
80 TitleInput *tinput; | |
81 | |
82 tinput = bmp_title_input_new(); | |
83 | |
105
18fe59468510
[svn] Use header.game, over header.author, as most SPC files do not contain the composer information.
nenolod
parents:
104
diff
changeset
|
84 tinput->performer = g_strdup(header.game); |
104 | 85 tinput->album_name = g_strdup(header.game); |
86 tinput->track_name = g_strdup(header.song); | |
94 | 87 |
104 | 88 tinput->file_name = g_path_get_basename(filename); |
89 tinput->file_path = g_path_get_dirname(filename); | |
90 | |
91 title = xmms_get_titlestring(xmms_get_gentitle_format(), | |
92 tinput); | |
93 | |
94 g_free(tinput); | |
95 } | |
96 else | |
213 | 97 title = g_path_get_basename(filename); |
98 | |
99 return title; | |
100 } | |
99 | 101 |
213 | 102 static gchar *get_title_nsf(gchar *filename) |
103 { | |
104 gchar *title; | |
105 title = g_path_get_basename(filename); | |
94 | 106 return title; |
107 } | |
95 | 108 |
148 | 109 static gchar *get_title(gchar *filename) |
110 { | |
213 | 111 switch (is_our_file(filename)) |
148 | 112 { |
213 | 113 case PLAY_TYPE_SPC: |
148 | 114 return get_title_spc(filename); |
213 | 115 break; |
116 case PLAY_TYPE_NSF: | |
117 return get_title_nsf(filename); | |
118 break; | |
148 | 119 } |
120 | |
121 return NULL; | |
122 } | |
123 | |
95 | 124 static void get_song_info(char *filename, char **title, int *length) |
125 { | |
126 (*title) = get_title(filename); | |
145 | 127 |
128 if (audcfg.loop_length) | |
129 (*length) = audcfg.loop_length; | |
130 else | |
131 (*length) = -1; | |
95 | 132 } |
133 | |
147
6fe2bfbe6fc2
[svn] Move SPC-specific code into SPC-specific routines.
nenolod
parents:
146
diff
changeset
|
134 static void play_file_spc(char *filename) |
95 | 135 { |
106
d2b88d78ccd7
[svn] Tell the player that the decoder has fired up :)
nenolod
parents:
105
diff
changeset
|
136 gchar *name; |
95 | 137 Emu_Std_Reader reader; |
138 Spc_Emu::header_t header; | |
149 | 139 gint samplerate; |
140 | |
141 if (audcfg.resample == TRUE) | |
142 samplerate = audcfg.resample_rate; | |
143 else | |
144 samplerate = Spc_Emu::native_sample_rate; | |
95 | 145 |
146 reader.open(filename); | |
147 reader.read(&header, sizeof(header)); | |
148 | |
149 spc = new Spc_Emu; | |
149 | 150 spc->init(samplerate); |
95 | 151 spc->load(header, reader); |
152 spc->start_track(0); | |
153 | |
103 | 154 console_ip_is_going = TRUE; |
155 | |
106
d2b88d78ccd7
[svn] Tell the player that the decoder has fired up :)
nenolod
parents:
105
diff
changeset
|
156 name = get_title(filename); |
d2b88d78ccd7
[svn] Tell the player that the decoder has fired up :)
nenolod
parents:
105
diff
changeset
|
157 |
145 | 158 if (audcfg.loop_length) |
159 console_ip.set_info(name, audcfg.loop_length * 1000, | |
149 | 160 spc->voice_count() * 1000, samplerate, 2); |
145 | 161 else |
149 | 162 console_ip.set_info(name, -1, spc->voice_count() * 1000, |
163 samplerate, 2); | |
106
d2b88d78ccd7
[svn] Tell the player that the decoder has fired up :)
nenolod
parents:
105
diff
changeset
|
164 |
d2b88d78ccd7
[svn] Tell the player that the decoder has fired up :)
nenolod
parents:
105
diff
changeset
|
165 g_free(name); |
d2b88d78ccd7
[svn] Tell the player that the decoder has fired up :)
nenolod
parents:
105
diff
changeset
|
166 |
149 | 167 if (!console_ip.output->open_audio(MY_FMT, samplerate, 2)) |
100 | 168 return; |
133
3fb426494de8
[svn] Open the output channel before firing up the thread.
nenolod
parents:
109
diff
changeset
|
169 |
147
6fe2bfbe6fc2
[svn] Move SPC-specific code into SPC-specific routines.
nenolod
parents:
146
diff
changeset
|
170 playing_type = PLAY_TYPE_SPC; |
6fe2bfbe6fc2
[svn] Move SPC-specific code into SPC-specific routines.
nenolod
parents:
146
diff
changeset
|
171 |
6fe2bfbe6fc2
[svn] Move SPC-specific code into SPC-specific routines.
nenolod
parents:
146
diff
changeset
|
172 decode_thread = g_thread_create(play_loop_spc, spc, TRUE, NULL); |
6fe2bfbe6fc2
[svn] Move SPC-specific code into SPC-specific routines.
nenolod
parents:
146
diff
changeset
|
173 } |
6fe2bfbe6fc2
[svn] Move SPC-specific code into SPC-specific routines.
nenolod
parents:
146
diff
changeset
|
174 |
213 | 175 static void play_file_nsf(char *filename) |
176 { | |
177 gchar *name; | |
178 Emu_Std_Reader reader; | |
179 Nsf_Emu::header_t header; | |
180 gint samplerate; | |
181 | |
182 if (audcfg.resample == TRUE) | |
183 samplerate = audcfg.resample_rate; | |
184 else | |
185 samplerate = 44100; | |
186 | |
187 reader.open(filename); | |
188 reader.read(&header, sizeof(header)); | |
189 | |
190 nsf = new Nsf_Emu; | |
191 nsf->init(samplerate); | |
192 nsf->load(header, reader); | |
193 nsf->start_track(0); | |
194 | |
195 console_ip_is_going = TRUE; | |
196 | |
197 name = get_title(filename); | |
198 | |
199 if (audcfg.loop_length) | |
200 console_ip.set_info(name, audcfg.loop_length * 1000, | |
201 nsf->voice_count() * 1000, samplerate, 2); | |
202 else | |
203 console_ip.set_info(name, -1, nsf->voice_count() * 1000, | |
204 samplerate, 2); | |
205 | |
206 g_free(name); | |
207 | |
208 if (!console_ip.output->open_audio(MY_FMT, samplerate, 2)) | |
209 return; | |
210 | |
211 playing_type = PLAY_TYPE_NSF; | |
212 | |
213 decode_thread = g_thread_create(play_loop_nsf, nsf, TRUE, NULL); | |
214 } | |
215 | |
147
6fe2bfbe6fc2
[svn] Move SPC-specific code into SPC-specific routines.
nenolod
parents:
146
diff
changeset
|
216 static void play_file(char *filename) |
6fe2bfbe6fc2
[svn] Move SPC-specific code into SPC-specific routines.
nenolod
parents:
146
diff
changeset
|
217 { |
213 | 218 switch (is_our_file(filename)) |
147
6fe2bfbe6fc2
[svn] Move SPC-specific code into SPC-specific routines.
nenolod
parents:
146
diff
changeset
|
219 { |
213 | 220 case PLAY_TYPE_SPC: |
147
6fe2bfbe6fc2
[svn] Move SPC-specific code into SPC-specific routines.
nenolod
parents:
146
diff
changeset
|
221 play_file_spc(filename); |
213 | 222 break; |
223 case PLAY_TYPE_NSF: | |
224 play_file_nsf(filename); | |
225 break; | |
147
6fe2bfbe6fc2
[svn] Move SPC-specific code into SPC-specific routines.
nenolod
parents:
146
diff
changeset
|
226 } |
95 | 227 } |
228 | |
96 | 229 static void seek(gint time) |
230 { | |
231 // XXX: Not yet implemented | |
232 } | |
233 | |
234 InputPlugin console_ip = { | |
235 NULL, | |
236 NULL, | |
237 NULL, | |
238 console_init, | |
109 | 239 console_aboutbox, |
96 | 240 NULL, |
241 is_our_file, | |
242 NULL, | |
243 play_file, | |
244 console_stop, | |
245 console_pause, | |
246 seek, | |
247 NULL, | |
248 get_time, | |
249 NULL, | |
250 NULL, | |
251 NULL, | |
252 NULL, | |
253 NULL, | |
254 NULL, | |
255 NULL, | |
104 | 256 get_song_info, |
96 | 257 NULL, |
258 NULL | |
259 }; | |
260 | |
261 static void console_stop(void) | |
262 { | |
103 | 263 console_ip_is_going = FALSE; |
96 | 264 g_thread_join(decode_thread); |
265 console_ip.output->close_audio(); | |
266 } | |
267 | |
98
e42694a28331
[svn] More progress -- now loads as an audacious module. :)
nenolod
parents:
96
diff
changeset
|
268 extern "C" InputPlugin *get_iplugin_info(void) |
96 | 269 { |
109 | 270 console_ip.description = g_strdup_printf(_("SPC, GYM, NSF, VGM and GBS module decoder")); |
96 | 271 return &console_ip; |
272 } | |
273 | |
274 static void console_pause(gshort p) | |
275 { | |
276 console_ip.output->pause(p); | |
277 } | |
278 | |
147
6fe2bfbe6fc2
[svn] Move SPC-specific code into SPC-specific routines.
nenolod
parents:
146
diff
changeset
|
279 static void *play_loop_spc(gpointer arg) |
95 | 280 { |
213 | 281 g_static_mutex_lock(&playback_mutex); |
99 | 282 Spc_Emu *my_spc = (Spc_Emu *) arg; |
213 | 283 Music_Emu::sample_t buf[1024]; |
95 | 284 |
145 | 285 for (;;) |
286 { | |
287 if (!console_ip_is_going) | |
288 break; | |
289 | |
290 my_spc->play(1024, buf); | |
291 | |
292 if ((console_ip.output->output_time() / 1000) > | |
293 audcfg.loop_length && audcfg.loop_length != 0) | |
294 break; | |
100 | 295 console_ip.add_vis_pcm(console_ip.output->written_time(), |
108 | 296 MY_FMT, 1, 2048, buf); |
297 while(console_ip.output->buffer_free() < 2048) | |
101
59ba6595fdf1
[svn] More accurate sound reproduction, but there is warbling. Still locks up player on completion.
nenolod
parents:
100
diff
changeset
|
298 xmms_usleep(10000); |
108 | 299 console_ip.output->write_audio(buf, 2048); |
100 | 300 } |
95 | 301 |
96 | 302 delete spc; |
145 | 303 console_ip.output->close_audio(); |
304 console_ip_is_going = FALSE; | |
147
6fe2bfbe6fc2
[svn] Move SPC-specific code into SPC-specific routines.
nenolod
parents:
146
diff
changeset
|
305 playing_type = PLAY_TYPE_NONE; |
213 | 306 g_static_mutex_unlock(&playback_mutex); |
307 g_thread_exit(NULL); | |
308 | |
309 return NULL; | |
310 } | |
311 | |
312 static void *play_loop_nsf(gpointer arg) | |
313 { | |
314 g_static_mutex_lock(&playback_mutex); | |
315 Nsf_Emu *my_nsf = (Nsf_Emu *) arg; | |
316 Music_Emu::sample_t buf[1024]; | |
317 | |
318 for (;;) | |
319 { | |
320 if (!console_ip_is_going) | |
321 break; | |
322 | |
323 my_nsf->play(1024, buf); | |
324 | |
325 if ((console_ip.output->output_time() / 1000) > | |
326 audcfg.loop_length && audcfg.loop_length != 0) | |
327 break; | |
328 console_ip.add_vis_pcm(console_ip.output->written_time(), | |
329 MY_FMT, 1, 2048, buf); | |
330 while(console_ip.output->buffer_free() < 2048) | |
331 xmms_usleep(10000); | |
332 console_ip.output->write_audio(buf, 2048); | |
333 } | |
334 | |
335 delete nsf; | |
336 console_ip.output->close_audio(); | |
337 console_ip_is_going = FALSE; | |
338 playing_type = PLAY_TYPE_NONE; | |
339 g_static_mutex_unlock(&playback_mutex); | |
96 | 340 g_thread_exit(NULL); |
95 | 341 |
96 | 342 return NULL; |
95 | 343 } |
344 | |
96 | 345 static int get_time(void) |
346 { | |
145 | 347 if (console_ip_is_going == TRUE) |
348 return console_ip.output->output_time(); | |
349 else | |
350 return -1; | |
96 | 351 } |
95 | 352 |
100 | 353 static void console_init(void) |
354 { | |
150
1997ecd9dcb1
[svn] Add ability to override defaults via .audacious/config until we can get a GUI.
nenolod
parents:
149
diff
changeset
|
355 ConfigFile *cfg; |
100 | 356 |
150
1997ecd9dcb1
[svn] Add ability to override defaults via .audacious/config until we can get a GUI.
nenolod
parents:
149
diff
changeset
|
357 cfg = xmms_cfg_open_default_file(); |
1997ecd9dcb1
[svn] Add ability to override defaults via .audacious/config until we can get a GUI.
nenolod
parents:
149
diff
changeset
|
358 |
1997ecd9dcb1
[svn] Add ability to override defaults via .audacious/config until we can get a GUI.
nenolod
parents:
149
diff
changeset
|
359 xmms_cfg_read_int(cfg, "console", "loop_length", &audcfg.loop_length); |
1997ecd9dcb1
[svn] Add ability to override defaults via .audacious/config until we can get a GUI.
nenolod
parents:
149
diff
changeset
|
360 xmms_cfg_read_boolean(cfg, "console", "resample", &audcfg.resample); |
1997ecd9dcb1
[svn] Add ability to override defaults via .audacious/config until we can get a GUI.
nenolod
parents:
149
diff
changeset
|
361 xmms_cfg_read_int(cfg, "console", "resample_rate", &audcfg.resample_rate); |
1997ecd9dcb1
[svn] Add ability to override defaults via .audacious/config until we can get a GUI.
nenolod
parents:
149
diff
changeset
|
362 |
1997ecd9dcb1
[svn] Add ability to override defaults via .audacious/config until we can get a GUI.
nenolod
parents:
149
diff
changeset
|
363 xmms_cfg_free(cfg); |
100 | 364 } |
365 | |
109 | 366 extern "C" void console_aboutbox(void) |
367 { | |
368 xmms_show_message(_("About the Console Music Decoder"), | |
369 _("Console music decoder engine based on Game_Music_Emu 0.2.4.\n" | |
370 "Audacious implementation by: William Pitcock <nenolod@nenolod.net>"), | |
371 _("Ok"), | |
372 FALSE, NULL, NULL); | |
373 } |