comparison src/Input/tonegen/tonegen.c @ 0:13389e613d67 trunk

[svn] - initial import of audacious-plugins tree (lots to do)
author nenolod
date Mon, 18 Sep 2006 01:11:49 -0700
parents
children 088092a52fea
comparison
equal deleted inserted replaced
-1:000000000000 0:13389e613d67
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
19
20 #include "audacious/plugin.h"
21 #include "audacious/output.h"
22 #include "libaudacious/util.h"
23 #include "config.h"
24 #include <glib.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <math.h>
28 #include <stdio.h>
29 #include <glib/gi18n.h>
30
31 #define MIN_FREQ 10
32 #define MAX_FREQ 20000
33 #define OUTPUT_FREQ 44100
34
35 #ifndef PI
36 #define PI 3.14159265358979323846
37 #endif
38
39 static InputPlugin tone_ip;
40
41 static gboolean going;
42 static gboolean audio_error;
43 static GThread *play_thread;
44
45 static void tone_about(void)
46 {
47 static GtkWidget *box;
48 if (!box)
49 {
50 box = xmms_show_message(
51 _("About Tone Generator"),
52 /* I18N: UTF-8 Translation: "Haavard Kvaalen" -> "H\303\245vard Kv\303\245len" */
53 _("Sinus tone generator by Haavard Kvaalen <havardk@xmms.org>\n"
54 "Modified by Daniel J. Peng <danielpeng@bigfoot.com>\n\n"
55 "To use it, add a URL: tone://frequency1;frequency2;frequency3;...\n"
56 "e.g. tone://2000;2005 to play a 2000Hz tone and a 2005Hz tone"),
57 _("Ok"), FALSE, NULL, NULL);
58 g_signal_connect(GTK_OBJECT(box), "destroy",
59 (GCallback)gtk_widget_destroyed, &box);
60 }
61 }
62
63 static int tone_is_our_file(char *filename)
64 {
65 if (!strncmp(filename, "tone://", 7))
66 return TRUE;
67 return FALSE;
68 }
69
70 #define BUF_SAMPLES 512
71 #define BUF_BYTES BUF_SAMPLES * 2
72
73 static void* play_loop(void *arg)
74 {
75 GArray* frequencies = arg;
76 gint16 data[BUF_SAMPLES];
77 gsize i;
78 struct {
79 double wd;
80 unsigned int period, t;
81 } *tone;
82
83 tone = g_malloc(frequencies->len * sizeof(*tone));
84
85 for (i = 0; i < frequencies->len; i++)
86 {
87 double f = g_array_index(frequencies, double, i);
88 tone[i].wd = 2 * PI * f / OUTPUT_FREQ;
89 tone[i].period = (G_MAXINT * 2U / OUTPUT_FREQ) *
90 (OUTPUT_FREQ / f);
91 tone[i].t = 0;
92 }
93
94 while (going)
95 {
96 for (i = 0; i < BUF_SAMPLES; i++)
97 {
98 gsize j;
99 double sum_sines;
100
101 for (sum_sines = 0, j = 0; j < frequencies->len; j++)
102 {
103 sum_sines += sin(tone[j].wd * tone[j].t);
104 if (tone[j].t > tone[j].period)
105 tone[j].t -= tone[j].period;
106 tone[j].t++;
107 }
108 data[i] = rint(((1 << 15) - 1) *
109 (sum_sines / frequencies->len));
110 }
111 while (tone_ip.output->buffer_free() < BUF_BYTES && going)
112 xmms_usleep(30000);
113 produce_audio(tone_ip.output->written_time(), FMT_S16_NE, 1, BUF_BYTES, data, &going);
114 }
115
116 g_array_free(frequencies, TRUE);
117 g_free(tone);
118
119 /* Make sure the output plugin stops prebuffering */
120 tone_ip.output->buffer_free();
121 tone_ip.output->buffer_free();
122
123 g_thread_exit(NULL);
124 return(NULL);
125 }
126
127 static GArray* tone_filename_parse(const char* filename)
128 {
129 GArray *frequencies = g_array_new(FALSE, FALSE, sizeof(double));
130 char **strings, **ptr;
131
132 if (strncmp(filename,"tone://", 7))
133 return NULL;
134
135 filename += 7;
136 strings = g_strsplit(filename, ";", 100);
137
138 for (ptr = strings; *ptr != NULL; ptr++)
139 {
140 double freq = strtod(*ptr, NULL);
141 if (freq >= MIN_FREQ && freq <= MAX_FREQ)
142 g_array_append_val(frequencies, freq);
143 }
144 g_strfreev(strings);
145
146 if (frequencies->len == 0)
147 {
148 g_array_free(frequencies, TRUE);
149 frequencies = NULL;
150 }
151
152 return frequencies;
153 }
154
155 static char* tone_title(char *filename)
156 {
157 GArray *freqs;
158 char* title;
159 gsize i;
160
161 freqs = tone_filename_parse(filename);
162 if (freqs == NULL)
163 return NULL;
164
165 title = g_strdup_printf("%s %.1f Hz", _("Tone Generator: "),
166 g_array_index(freqs, double, 0));
167 for (i = 1; i < freqs->len; i++)
168 {
169 char *old_title;
170 old_title = title;
171 title = g_strdup_printf("%s;%.1f Hz", old_title,
172 g_array_index(freqs, double, i));
173 g_free(old_title);
174 }
175 g_array_free(freqs, TRUE);
176
177 return title;
178 }
179
180
181 static void tone_play(char *filename)
182 {
183 GArray* frequencies;
184 char *name;
185
186 frequencies = tone_filename_parse(filename);
187 if (frequencies == NULL)
188 return;
189
190 going = TRUE;
191 audio_error = FALSE;
192 if (tone_ip.output->open_audio(FMT_S16_NE, OUTPUT_FREQ, 1) == 0)
193 {
194 audio_error = TRUE;
195 going = FALSE;
196 return;
197 }
198
199 name = tone_title(filename);
200 tone_ip.set_info(name, -1, 16 * OUTPUT_FREQ, OUTPUT_FREQ, 1);
201 g_free(name);
202 play_thread = g_thread_create((GThreadFunc)play_loop, frequencies, TRUE, NULL);
203 }
204
205 static void tone_stop(void)
206 {
207 if (going)
208 {
209 going = FALSE;
210 g_thread_join(play_thread);
211 tone_ip.output->close_audio();
212 }
213 }
214
215 static void tone_pause(short paused)
216 {
217 tone_ip.output->pause(paused);
218 }
219
220 static int tone_get_time(void)
221 {
222 if (audio_error)
223 return -2;
224 if (!going && !tone_ip.output->buffer_playing())
225 return -1;
226 return tone_ip.output->output_time();
227 }
228
229 static void tone_song_info(char *filename, char **title, int *length)
230 {
231 *length = -1;
232 *title = tone_title(filename);
233 }
234
235 static InputPlugin tone_ip =
236 {
237 NULL,
238 NULL,
239 NULL, /* Description */
240 NULL,
241 tone_about,
242 NULL,
243 tone_is_our_file,
244 NULL,
245 tone_play,
246 tone_stop,
247 tone_pause,
248 NULL,
249 NULL,
250 tone_get_time,
251 NULL,
252 NULL,
253 NULL,
254 NULL,
255 NULL,
256 NULL,
257 NULL,
258 tone_song_info,
259 NULL,
260 NULL
261 };
262
263 InputPlugin *get_iplugin_info(void)
264 {
265 tone_ip.description = g_strdup_printf(_("Tone Generator %s"), PACKAGE_VERSION);
266 return &tone_ip;
267 }