Mercurial > audlegacy
annotate Plugins/Input/tonegen/tonegen.c @ 334:0daaddb10914 trunk
[svn] Implement GYM playback.
author | chainsaw |
---|---|
date | Sun, 25 Dec 2005 13:31:46 -0800 |
parents | bd8457b077cf |
children | 7fa1738514d5 |
rev | line source |
---|---|
61 | 1 /* |
2 * Copyright 2000,2001 Haavard Kvaalen <havardk@sol.no> | |
3 * | |
4 * | |
5 * This program is free software; you can redistribute it and/or modify | |
6 * it under the terms of the GNU General Public License as published by | |
7 * the Free Software Foundation; either version 2 of the License, or | |
8 * (at your option) any later version. | |
9 * | |
10 * This program is distributed in the hope that it will be useful, | |
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 * GNU General Public License for more details. | |
14 * | |
15 * You should have received a copy of the GNU General Public License | |
16 * along with this program; if not, write to the Free Software | |
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
18 */ | |
19 | |
20 #include "audacious/plugin.h" | |
21 #include "libaudacious/util.h" | |
22 #include "config.h" | |
23 #include <glib.h> | |
24 #include <stdlib.h> | |
25 #include <string.h> | |
26 #include <math.h> | |
27 #include <stdio.h> | |
28 #include <glib/gi18n.h> | |
29 | |
30 #define MIN_FREQ 10 | |
31 #define MAX_FREQ 20000 | |
32 #define OUTPUT_FREQ 44100 | |
33 | |
34 #ifndef PI | |
35 #define PI 3.14159265358979323846 | |
36 #endif | |
37 | |
38 static InputPlugin tone_ip; | |
39 | |
40 static gboolean going; | |
41 static gboolean audio_error; | |
172 | 42 static GThread *play_thread; |
61 | 43 |
44 static void tone_about(void) | |
45 { | |
46 static GtkWidget *box; | |
47 box = xmms_show_message( | |
48 _("About Tone Generator"), | |
49 /* I18N: UTF-8 Translation: "Haavard Kvaalen" -> "H\303\245vard Kv\303\245len" */ | |
50 _("Sinus tone generator by Haavard Kvaalen <havardk@xmms.org>\n" | |
51 "Modified by Daniel J. Peng <danielpeng@bigfoot.com>\n\n" | |
52 "To use it, add a URL: tone://frequency1;frequency2;frequency3;...\n" | |
53 "e.g. tone://2000;2005 to play a 2000Hz tone and a 2005Hz tone"), | |
54 _("Ok"), FALSE, NULL, NULL); | |
209
bd8457b077cf
[svn] Add casts to callbacks in signal handlers to avoid warning. Remove stale pause handler declaration from wav-sndfile.h
chainsaw
parents:
190
diff
changeset
|
55 g_signal_connect(GTK_OBJECT(box), "destroy", |
bd8457b077cf
[svn] Add casts to callbacks in signal handlers to avoid warning. Remove stale pause handler declaration from wav-sndfile.h
chainsaw
parents:
190
diff
changeset
|
56 (GCallback)gtk_widget_destroyed, &box); |
61 | 57 } |
58 | |
59 static int tone_is_our_file(char *filename) | |
60 { | |
61 if (!strncmp(filename, "tone://", 7)) | |
62 return TRUE; | |
63 return FALSE; | |
64 } | |
65 | |
66 #define BUF_SAMPLES 512 | |
67 #define BUF_BYTES BUF_SAMPLES * 2 | |
68 | |
69 static void* play_loop(void *arg) | |
70 { | |
71 GArray* frequencies = arg; | |
72 gint16 data[BUF_SAMPLES]; | |
73 int i; | |
74 struct { | |
75 double wd; | |
76 unsigned int period, t; | |
77 } *tone; | |
78 | |
79 tone = g_malloc(frequencies->len * sizeof(*tone)); | |
80 | |
81 for (i = 0; i < frequencies->len; i++) | |
82 { | |
83 double f = g_array_index(frequencies, double, i); | |
84 tone[i].wd = 2 * PI * f / OUTPUT_FREQ; | |
85 tone[i].period = (G_MAXINT * 2U / OUTPUT_FREQ) * | |
86 (OUTPUT_FREQ / f); | |
87 tone[i].t = 0; | |
88 } | |
89 | |
90 while (going) | |
91 { | |
92 for (i = 0; i < BUF_SAMPLES; i++) | |
93 { | |
94 int j; | |
95 double sum_sines; | |
96 | |
97 for (sum_sines = 0, j = 0; j < frequencies->len; j++) | |
98 { | |
99 sum_sines += sin(tone[j].wd * tone[j].t); | |
100 if (tone[j].t > tone[j].period) | |
101 tone[j].t -= tone[j].period; | |
102 tone[j].t++; | |
103 } | |
104 data[i] = rint(((1 << 15) - 1) * | |
105 (sum_sines / frequencies->len)); | |
106 } | |
107 tone_ip.add_vis_pcm(tone_ip.output->written_time(), | |
108 FMT_S16_NE, 1, BUF_BYTES, data); | |
109 while (tone_ip.output->buffer_free() < BUF_BYTES && going) | |
110 xmms_usleep(30000); | |
111 if (going) | |
112 tone_ip.output->write_audio(data, BUF_BYTES); | |
113 } | |
114 | |
115 g_array_free(frequencies, TRUE); | |
116 g_free(tone); | |
117 | |
118 /* Make sure the output plugin stops prebuffering */ | |
119 tone_ip.output->buffer_free(); | |
120 tone_ip.output->buffer_free(); | |
121 | |
172 | 122 g_thread_exit(NULL); |
190 | 123 return(NULL); |
61 | 124 } |
125 | |
126 static GArray* tone_filename_parse(const char* filename) | |
127 { | |
128 GArray *frequencies = g_array_new(FALSE, FALSE, sizeof(double)); | |
129 char **strings, **ptr; | |
130 | |
131 if (strncmp(filename,"tone://", 7)) | |
132 return NULL; | |
133 | |
134 filename += 7; | |
135 strings = g_strsplit(filename, ";", 100); | |
136 | |
137 for (ptr = strings; *ptr != NULL; ptr++) | |
138 { | |
139 double freq = strtod(*ptr, NULL); | |
140 if (freq >= MIN_FREQ && freq <= MAX_FREQ) | |
141 g_array_append_val(frequencies, freq); | |
142 } | |
143 g_strfreev(strings); | |
144 | |
145 if (frequencies->len == 0) | |
146 { | |
147 g_array_free(frequencies, TRUE); | |
148 frequencies = NULL; | |
149 } | |
150 | |
151 return frequencies; | |
152 } | |
153 | |
154 static char* tone_title(char *filename) | |
155 { | |
156 GArray *freqs; | |
157 char* title; | |
158 int i; | |
159 | |
160 freqs = tone_filename_parse(filename); | |
161 if (freqs == NULL) | |
162 return NULL; | |
163 | |
164 title = g_strdup_printf("%s %.1f Hz", _("Tone Generator: "), | |
165 g_array_index(freqs, double, 0)); | |
166 for (i = 1; i < freqs->len; i++) | |
167 { | |
168 char *old_title; | |
169 old_title = title; | |
170 title = g_strdup_printf("%s;%.1f Hz", old_title, | |
171 g_array_index(freqs, double, i)); | |
172 g_free(old_title); | |
173 } | |
174 g_array_free(freqs, TRUE); | |
175 | |
176 return title; | |
177 } | |
178 | |
179 | |
180 static void tone_play(char *filename) | |
181 { | |
182 GArray* frequencies; | |
183 char *name; | |
184 | |
185 frequencies = tone_filename_parse(filename); | |
186 if (frequencies == NULL) | |
187 return; | |
188 | |
189 going = TRUE; | |
190 audio_error = FALSE; | |
191 if (tone_ip.output->open_audio(FMT_S16_NE, OUTPUT_FREQ, 1) == 0) | |
192 { | |
193 audio_error = TRUE; | |
194 going = FALSE; | |
195 return; | |
196 } | |
197 | |
198 name = tone_title(filename); | |
199 tone_ip.set_info(name, -1, 16 * OUTPUT_FREQ, OUTPUT_FREQ, 1); | |
200 g_free(name); | |
172 | 201 play_thread = g_thread_create((GThreadFunc)play_loop, frequencies, TRUE, NULL); |
61 | 202 } |
203 | |
204 static void tone_stop(void) | |
205 { | |
206 if (going) | |
207 { | |
208 going = FALSE; | |
172 | 209 g_thread_join(play_thread); |
61 | 210 tone_ip.output->close_audio(); |
211 } | |
212 } | |
213 | |
214 static void tone_pause(short paused) | |
215 { | |
216 tone_ip.output->pause(paused); | |
217 } | |
218 | |
219 static int tone_get_time(void) | |
220 { | |
221 if (audio_error) | |
222 return -2; | |
223 if (!going && !tone_ip.output->buffer_playing()) | |
224 return -1; | |
225 return tone_ip.output->output_time(); | |
226 } | |
227 | |
228 static void tone_song_info(char *filename, char **title, int *length) | |
229 { | |
230 *length = -1; | |
231 *title = tone_title(filename); | |
232 } | |
233 | |
234 static InputPlugin tone_ip = | |
235 { | |
236 NULL, | |
237 NULL, | |
238 NULL, /* Description */ | |
239 NULL, | |
240 tone_about, | |
241 NULL, | |
242 tone_is_our_file, | |
243 NULL, | |
244 tone_play, | |
245 tone_stop, | |
246 tone_pause, | |
247 NULL, | |
248 NULL, | |
249 tone_get_time, | |
250 NULL, | |
251 NULL, | |
252 NULL, | |
253 NULL, | |
254 NULL, | |
255 NULL, | |
256 NULL, | |
257 tone_song_info, | |
258 NULL, | |
259 NULL | |
260 }; | |
261 | |
262 InputPlugin *get_iplugin_info(void) | |
263 { | |
264 tone_ip.description = g_strdup_printf(_("Tone Generator %s"), VERSION); | |
265 return &tone_ip; | |
266 } |