Mercurial > audlegacy-plugins
comparison src/metronom/metronom.c @ 315:2294f3a6f136 trunk
[svn] Metronom (a.k.a. tact generator) input plugin, ported from XMMS.
author | chainsaw |
---|---|
date | Wed, 29 Nov 2006 14:42:11 -0800 |
parents | |
children | 7385182ae4b8 |
comparison
equal
deleted
inserted
replaced
314:29e5e3b6f1b6 | 315:2294f3a6f136 |
---|---|
1 /* | |
2 * Copyright 2000 Martin Strauß <mys@faveve.uni-stuttgart.de> | |
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 "audacious/util.h" | |
22 #include <glib.h> | |
23 #include <string.h> | |
24 | |
25 #define MIN_BPM 1 | |
26 #define MAX_BPM 512 | |
27 | |
28 static InputPlugin metronom_ip; | |
29 | |
30 static gboolean going; | |
31 static gboolean audio_error; | |
32 static GThread *play_thread; | |
33 | |
34 struct metronom_struct { | |
35 gint bpm; | |
36 gint num; | |
37 gint den; | |
38 gint id; | |
39 }; | |
40 typedef struct metronom_struct metronom_t; | |
41 | |
42 #define tact_id_max 12 | |
43 gint tact_id[tact_id_max][2]= | |
44 { | |
45 {1,1}, | |
46 {2,2}, | |
47 {3,2}, | |
48 {4,2}, | |
49 {2,4}, | |
50 {3,4}, | |
51 {4,4}, | |
52 {6,4}, | |
53 {2,8}, | |
54 {3,8}, | |
55 {4,8}, | |
56 {6,8} | |
57 }; | |
58 #define tact_form_max 8 | |
59 gdouble tact_form[tact_id_max][tact_form_max]= | |
60 { | |
61 {1.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0}, | |
62 {1.0,0.5,0.0,0.0,0.0,0.0,0.0,0.0}, | |
63 {1.0,0.5,0.5,0.0,0.0,0.0,0.0,0.0}, | |
64 {1.0,0.5,0.6,0.5,0.0,0.0,0.0,0.0}, | |
65 {1.0,0.5,0.0,0.0,0.0,0.0,0.0,0.0}, | |
66 {1.0,0.5,0.5,0.0,0.0,0.0,0.0,0.0}, | |
67 {1.0,0.5,0.6,0.5,0.0,0.0,0.0,0.0}, | |
68 {1.0,0.5,0.5,0.6,0.5,0.5,0.0,0.0}, | |
69 {1.0,0.5,0.0,0.0,0.0,0.0,0.0,0.0}, | |
70 {1.0,0.5,0.5,0.0,0.0,0.0,0.0,0.0}, | |
71 {1.0,0.5,0.6,0.5,0.0,0.0,0.0,0.0}, | |
72 {1.0,0.5,0.5,0.6,0.5,0.5,0.0,0.0} | |
73 }; | |
74 | |
75 static void metronom_about(void) | |
76 { | |
77 static GtkWidget *box; | |
78 box = xmms_show_message( | |
79 "About Metronom", | |
80 "A Tact Generator by Martin Strauß <mys@faveve.uni-stuttgart.de>\n\nTo use it, add a URL: tact://beats*num/den\ne.g. tact://77 to play 77 beats per minute\nor tact://60*3/4 to play 60 bpm in 3/4 tacts", "Ok", | |
81 FALSE, NULL, NULL); | |
82 gtk_signal_connect(GTK_OBJECT(box), "destroy", | |
83 GTK_SIGNAL_FUNC(gtk_widget_destroyed), &box); | |
84 } | |
85 | |
86 static int metronom_is_our_file(char *filename) | |
87 { | |
88 if (!strncmp(filename, "tact://", 7)) | |
89 return TRUE; | |
90 return FALSE; | |
91 } | |
92 | |
93 #define BUF_SAMPLES 512 | |
94 #define BUF_BYTES BUF_SAMPLES * 2 | |
95 #define MAX_AMPL (GINT16_TO_LE((1<<15) - 1)) | |
96 | |
97 static void* play_loop(void *arg) | |
98 { | |
99 gint16 data[BUF_SAMPLES]; | |
100 metronom_t *pmetronom=(metronom_t *)arg; | |
101 gint i; | |
102 | |
103 gint16 t = 0,tact; | |
104 gint16 datagoal = 0; | |
105 gint16 datamiddle = 0; | |
106 gint16 datacurrent = datamiddle; | |
107 gint16 datalast = datamiddle; | |
108 gint16 data_form[tact_form_max]; | |
109 gint num; | |
110 | |
111 tact = 60*44100/pmetronom->bpm; | |
112 /* prepare weighted amplitudes */ | |
113 for(num=0;num<pmetronom->num;num++){ | |
114 data_form[num]=MAX_AMPL*tact_form[pmetronom->id][num]; | |
115 } | |
116 | |
117 num=0; | |
118 while (going) | |
119 { | |
120 for (i = 0; i < BUF_SAMPLES; i++){ | |
121 if(t==tact){ | |
122 t=0; | |
123 datagoal = data_form[num]; | |
124 } | |
125 else if(t==10) { | |
126 datagoal = -data_form[num]; | |
127 } | |
128 else if(t==25) { | |
129 datagoal = data_form[num]; | |
130 /* circle through weighted amplitudes */ | |
131 num++; | |
132 if(num==pmetronom->num)num=0; | |
133 } | |
134 /* makes curve a little bit smoother */ | |
135 data[i]=(datalast+datacurrent+datagoal)/3; | |
136 datalast=datacurrent; | |
137 datacurrent=data[i]; | |
138 if(t > 35) | |
139 datagoal=(datamiddle+7*datagoal)/8; | |
140 t++; | |
141 } | |
142 while(metronom_ip.output->buffer_free() < BUF_BYTES && going) | |
143 xmms_usleep(30000); | |
144 if (going) | |
145 produce_audio(metronom_ip.output->written_time(), FMT_S16_LE, 1, BUF_BYTES, data, &going); | |
146 } | |
147 /* Make sure the output plugin stops prebuffering */ | |
148 free(arg); | |
149 metronom_ip.output->buffer_free(); | |
150 metronom_ip.output->buffer_free(); | |
151 g_thread_exit(NULL); | |
152 } | |
153 | |
154 static void metronom_play(char *filename) | |
155 { | |
156 gchar *name; | |
157 size_t count; | |
158 metronom_t *pmetronom; | |
159 gint flag,id; | |
160 | |
161 pmetronom=(metronom_t *)malloc(sizeof(metronom_t)); | |
162 if(!pmetronom)return; | |
163 | |
164 count=sscanf(filename, "tact://%d*%d/%d", &pmetronom->bpm,&pmetronom->num,&pmetronom->den); | |
165 if (count != 1 && count !=3)return; | |
166 if(!(pmetronom->bpm >= MIN_BPM && pmetronom->bpm <= MAX_BPM))return; | |
167 pmetronom->id=0; | |
168 if(count==1){ | |
169 pmetronom->num=1; | |
170 pmetronom->den=1; | |
171 } else { | |
172 if(pmetronom->num==0 || pmetronom->den==0)return; | |
173 flag=FALSE; | |
174 for(id=0;(id<tact_id_max && (!flag));id++){ | |
175 if(pmetronom->num==tact_id[id][0] && pmetronom->den==tact_id[id][1]){ | |
176 flag=TRUE; | |
177 pmetronom->id=id; | |
178 } | |
179 } | |
180 if(!flag)return; | |
181 } | |
182 | |
183 going = TRUE; | |
184 audio_error = FALSE; | |
185 if (metronom_ip.output->open_audio(FMT_S16_LE, 44100, 1) == 0) | |
186 { | |
187 audio_error = TRUE; | |
188 going = FALSE; | |
189 return; | |
190 } | |
191 if(pmetronom->num==1 && pmetronom->den==1){ | |
192 name = g_strdup_printf("Tact generator: %d bpm", pmetronom->bpm); | |
193 } else { | |
194 name = g_strdup_printf("Tact generator: %d bpm %d/%d", pmetronom->bpm,pmetronom->num,pmetronom->den); | |
195 } | |
196 metronom_ip.set_info(name, -1, 16 * 44100, 44100, 1); | |
197 g_free(name); | |
198 play_thread = g_thread_create((GThreadFunc)play_loop, pmetronom, TRUE, NULL); | |
199 } | |
200 | |
201 static void metronom_stop(void) | |
202 { | |
203 if (going) | |
204 { | |
205 going = FALSE; | |
206 g_thread_join(play_thread); | |
207 metronom_ip.output->close_audio(); | |
208 } | |
209 } | |
210 | |
211 static void metronom_pause(short paused) | |
212 { | |
213 metronom_ip.output->pause(paused); | |
214 } | |
215 | |
216 static int metronom_get_time(void) | |
217 { | |
218 if (audio_error) | |
219 return -2; | |
220 if (!going && !metronom_ip.output->buffer_playing()) | |
221 return -1; | |
222 return metronom_ip.output->output_time(); | |
223 } | |
224 | |
225 static void metronom_song_info(char *filename, char **title, int *length) | |
226 { | |
227 metronom_t metronom; | |
228 metronom_t *pmetronom=&metronom; | |
229 size_t count; | |
230 gint flag,id; | |
231 *length = -1; | |
232 *title = NULL; | |
233 | |
234 count=sscanf(filename, "tact://%d*%d/%d", &pmetronom->bpm,&pmetronom->num,&pmetronom->den); | |
235 if (count != 1 && count !=3)return; | |
236 if(!(pmetronom->bpm >= MIN_BPM && pmetronom->bpm <= MAX_BPM))return; | |
237 | |
238 if (count == 1) { | |
239 pmetronom->num=1; | |
240 pmetronom->den=1; | |
241 pmetronom->id=0; | |
242 } else { | |
243 if(pmetronom->num==0 || pmetronom->den==0)return; | |
244 flag=FALSE; | |
245 for(id=0;(id<tact_id_max && (!flag));id++){ | |
246 if(pmetronom->num==tact_id[id][0] && pmetronom->den==tact_id[id][1])flag=TRUE; | |
247 } | |
248 if(!flag)return; | |
249 else pmetronom->id=id; | |
250 } | |
251 | |
252 if(pmetronom->num==1 && pmetronom->den==1){ | |
253 *title = g_strdup_printf("Tact generator: %d bpm", pmetronom->bpm); | |
254 } else { | |
255 *title = g_strdup_printf("Tact generator: %d bpm %d/%d", pmetronom->bpm,pmetronom->num,pmetronom->den); | |
256 } | |
257 } | |
258 | |
259 | |
260 | |
261 static InputPlugin metronom_ip = | |
262 { | |
263 NULL, | |
264 NULL, | |
265 "Tact Generator " VERSION, | |
266 NULL, | |
267 metronom_about, | |
268 NULL, | |
269 metronom_is_our_file, | |
270 NULL, | |
271 metronom_play, | |
272 metronom_stop, | |
273 metronom_pause, | |
274 NULL, | |
275 NULL, | |
276 metronom_get_time, | |
277 NULL, | |
278 NULL, | |
279 NULL, | |
280 NULL, | |
281 NULL, | |
282 NULL, | |
283 NULL, | |
284 metronom_song_info, | |
285 NULL, | |
286 NULL, | |
287 NULL, | |
288 NULL, | |
289 NULL, | |
290 NULL, | |
291 }; | |
292 | |
293 InputPlugin *get_iplugin_info(void) | |
294 { | |
295 return &metronom_ip; | |
296 } |