waf: configure option for enforcing autostart method
[jack2.git] / example-clients / metro.c
blob1742a5990a5939647ca39275ef525cd4f1a0e10d
1 /*
2 Copyright (C) 2002 Anthony Van Groningen
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <errno.h>
22 #ifndef WIN32
23 #include <unistd.h>
24 #endif
25 #include <math.h>
26 #include <signal.h>
27 #include <getopt.h>
28 #include <string.h>
30 #include <jack/jack.h>
31 #include <jack/transport.h>
33 typedef jack_default_audio_sample_t sample_t;
35 const double PI = 3.14;
37 jack_client_t *client;
38 jack_port_t *output_port;
39 unsigned long sr;
40 int freq = 880;
41 int bpm;
42 jack_nframes_t tone_length, wave_length;
43 sample_t *wave;
44 long offset = 0;
45 int transport_aware = 0;
46 jack_transport_state_t transport_state;
48 static void signal_handler(int sig)
50 jack_client_close(client);
51 fprintf(stderr, "signal received, exiting ...\n");
52 exit(0);
55 static void
56 usage ()
58 fprintf (stderr, "\n"
59 "usage: jack_metro \n"
60 " [ --frequency OR -f frequency (in Hz) ]\n"
61 " [ --amplitude OR -A maximum amplitude (between 0 and 1) ]\n"
62 " [ --duration OR -D duration (in ms) ]\n"
63 " [ --attack OR -a attack (in percent of duration) ]\n"
64 " [ --decay OR -d decay (in percent of duration) ]\n"
65 " [ --name OR -n jack name for metronome client ]\n"
66 " [ --transport OR -t transport aware ]\n"
67 " --bpm OR -b beats per minute\n"
71 static void
72 process_silence (jack_nframes_t nframes)
74 sample_t *buffer = (sample_t *) jack_port_get_buffer (output_port, nframes);
75 memset (buffer, 0, sizeof (jack_default_audio_sample_t) * nframes);
78 jack_nframes_t last_time;
79 jack_time_t last_micro_time;
81 static void
82 process_audio (jack_nframes_t nframes)
84 sample_t *buffer = (sample_t *) jack_port_get_buffer (output_port, nframes);
85 jack_nframes_t frames_left = nframes;
87 while (wave_length - offset < frames_left) {
88 memcpy (buffer + (nframes - frames_left), wave + offset, sizeof (sample_t) * (wave_length - offset));
89 frames_left -= wave_length - offset;
90 offset = 0;
92 if (frames_left > 0) {
93 memcpy (buffer + (nframes - frames_left), wave + offset, sizeof (sample_t) * frames_left);
94 offset += frames_left;
98 jack_nframes_t cur_time = jack_frame_time(client);
99 jack_time_t cur_micro_time = jack_get_time();
101 printf("jack_frame_timed %lld micro %lld delta %d\n", cur_time, (cur_micro_time - last_micro_time), cur_time - last_time);
102 last_time = cur_time;
103 last_micro_time = cur_micro_time;
107 static int
108 process (jack_nframes_t nframes, void *arg)
110 if (transport_aware) {
111 jack_position_t pos;
113 if (jack_transport_query (client, &pos)
114 != JackTransportRolling) {
116 process_silence (nframes);
117 return 0;
119 offset = pos.frame % wave_length;
121 process_audio (nframes);
122 return 0;
126 main (int argc, char *argv[])
128 sample_t scale;
129 int i, attack_length, decay_length;
130 double *amp;
131 double max_amp = 0.5;
132 int option_index;
133 int opt;
134 int got_bpm = 0;
135 int attack_percent = 1, decay_percent = 10, dur_arg = 100;
136 char *client_name = 0;
137 char *bpm_string = "bpm";
138 int verbose = 0;
139 jack_status_t status;
141 const char *options = "f:A:D:a:d:b:n:thv";
142 struct option long_options[] =
144 {"frequency", 1, 0, 'f'},
145 {"amplitude", 1, 0, 'A'},
146 {"duration", 1, 0, 'D'},
147 {"attack", 1, 0, 'a'},
148 {"decay", 1, 0, 'd'},
149 {"bpm", 1, 0, 'b'},
150 {"name", 1, 0, 'n'},
151 {"transport", 0, 0, 't'},
152 {"help", 0, 0, 'h'},
153 {"verbose", 0, 0, 'v'},
154 {0, 0, 0, 0}
157 while ((opt = getopt_long (argc, argv, options, long_options, &option_index)) != -1) {
158 switch (opt) {
159 case 'f':
160 if ((freq = atoi (optarg)) <= 0) {
161 fprintf (stderr, "invalid frequency\n");
162 return -1;
164 break;
165 case 'A':
166 if (((max_amp = atof (optarg)) <= 0)|| (max_amp > 1)) {
167 fprintf (stderr, "invalid amplitude\n");
168 return -1;
170 break;
171 case 'D':
172 dur_arg = atoi (optarg);
173 fprintf (stderr, "durarg = %u\n", dur_arg);
174 break;
175 case 'a':
176 if (((attack_percent = atoi (optarg)) < 0) || (attack_percent > 100)) {
177 fprintf (stderr, "invalid attack percent\n");
178 return -1;
180 break;
181 case 'd':
182 if (((decay_percent = atoi (optarg)) < 0) || (decay_percent > 100)) {
183 fprintf (stderr, "invalid decay percent\n");
184 return -1;
186 break;
187 case 'b':
188 got_bpm = 1;
189 if ((bpm = atoi (optarg)) < 0) {
190 fprintf (stderr, "invalid bpm\n");
191 return -1;
193 bpm_string = (char *) malloc ((strlen (optarg) + 5) * sizeof (char));
194 strcpy (bpm_string, optarg);
195 strcat (bpm_string, "_bpm");
196 break;
197 case 'n':
198 client_name = (char *) malloc ((strlen (optarg) + 1) * sizeof (char));
199 strcpy (client_name, optarg);
200 break;
201 case 'v':
202 verbose = 1;
203 break;
204 case 't':
205 transport_aware = 1;
206 break;
207 default:
208 fprintf (stderr, "unknown option %c\n", opt);
209 case 'h':
210 usage ();
211 return -1;
214 if (!got_bpm) {
215 fprintf (stderr, "bpm not specified\n");
216 usage ();
217 return -1;
220 /* Initial Jack setup, get sample rate */
221 if (!client_name) {
222 client_name = (char *) malloc (9 * sizeof (char));
223 strcpy (client_name, "metro");
225 if ((client = jack_client_open (client_name, JackNoStartServer, &status)) == 0) {
226 fprintf (stderr, "JACK server not running?\n");
227 return 1;
229 jack_set_process_callback (client, process, 0);
230 output_port = jack_port_register (client, bpm_string, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
232 sr = jack_get_sample_rate (client);
234 /* setup wave table parameters */
235 wave_length = 60 * sr / bpm;
236 tone_length = sr * dur_arg / 1000;
237 attack_length = tone_length * attack_percent / 100;
238 decay_length = tone_length * decay_percent / 100;
239 scale = 2 * PI * freq / sr;
241 if (tone_length >= wave_length) {
242 fprintf (stderr, "invalid duration (tone length = %u, wave length = %u\n", tone_length, wave_length);
243 return -1;
245 if (attack_length + decay_length > (int)tone_length) {
246 fprintf (stderr, "invalid attack/decay\n");
247 return -1;
250 /* Build the wave table */
251 wave = (sample_t *) malloc (wave_length * sizeof(sample_t));
252 amp = (double *) malloc (tone_length * sizeof(double));
254 for (i = 0; i < attack_length; i++) {
255 amp[i] = max_amp * i / ((double) attack_length);
257 for (i = attack_length; i < (int)tone_length - decay_length; i++) {
258 amp[i] = max_amp;
260 for (i = (int)tone_length - decay_length; i < (int)tone_length; i++) {
261 amp[i] = - max_amp * (i - (double) tone_length) / ((double) decay_length);
263 for (i = 0; i < (int)tone_length; i++) {
264 wave[i] = amp[i] * sin (scale * i);
266 for (i = tone_length; i < (int)wave_length; i++) {
267 wave[i] = 0;
270 if (jack_activate (client)) {
271 fprintf (stderr, "cannot activate client\n");
272 goto error;
275 /* install a signal handler to properly quits jack client */
276 #ifdef WIN32
277 signal(SIGINT, signal_handler);
278 signal(SIGABRT, signal_handler);
279 signal(SIGTERM, signal_handler);
280 #else
281 signal(SIGQUIT, signal_handler);
282 signal(SIGTERM, signal_handler);
283 signal(SIGHUP, signal_handler);
284 signal(SIGINT, signal_handler);
285 #endif
287 /* run until interrupted */
288 while (1) {
289 #ifdef WIN32
290 Sleep(1000);
291 #else
292 sleep(1);
293 #endif
296 jack_client_close(client);
298 error:
299 free(amp);
300 free(wave);
301 exit (0);