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.
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
;
42 jack_nframes_t tone_length
, wave_length
;
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");
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"
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
;
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
;
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;
108 process (jack_nframes_t nframes
, void *arg
)
110 if (transport_aware
) {
113 if (jack_transport_query (client
, &pos
)
114 != JackTransportRolling
) {
116 process_silence (nframes
);
119 offset
= pos
.frame
% wave_length
;
121 process_audio (nframes
);
126 main (int argc
, char *argv
[])
129 int i
, attack_length
, decay_length
;
131 double max_amp
= 0.5;
135 int attack_percent
= 1, decay_percent
= 10, dur_arg
= 100;
136 char *client_name
= 0;
137 char *bpm_string
= "bpm";
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'},
151 {"transport", 0, 0, 't'},
153 {"verbose", 0, 0, 'v'},
157 while ((opt
= getopt_long (argc
, argv
, options
, long_options
, &option_index
)) != -1) {
160 if ((freq
= atoi (optarg
)) <= 0) {
161 fprintf (stderr
, "invalid frequency\n");
166 if (((max_amp
= atof (optarg
)) <= 0)|| (max_amp
> 1)) {
167 fprintf (stderr
, "invalid amplitude\n");
172 dur_arg
= atoi (optarg
);
173 fprintf (stderr
, "durarg = %u\n", dur_arg
);
176 if (((attack_percent
= atoi (optarg
)) < 0) || (attack_percent
> 100)) {
177 fprintf (stderr
, "invalid attack percent\n");
182 if (((decay_percent
= atoi (optarg
)) < 0) || (decay_percent
> 100)) {
183 fprintf (stderr
, "invalid decay percent\n");
189 if ((bpm
= atoi (optarg
)) < 0) {
190 fprintf (stderr
, "invalid bpm\n");
193 bpm_string
= (char *) malloc ((strlen (optarg
) + 5) * sizeof (char));
194 strcpy (bpm_string
, optarg
);
195 strcat (bpm_string
, "_bpm");
198 client_name
= (char *) malloc ((strlen (optarg
) + 1) * sizeof (char));
199 strcpy (client_name
, optarg
);
208 fprintf (stderr
, "unknown option %c\n", opt
);
215 fprintf (stderr
, "bpm not specified\n");
220 /* Initial Jack setup, get sample rate */
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");
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
);
245 if (attack_length
+ decay_length
> (int)tone_length
) {
246 fprintf (stderr
, "invalid attack/decay\n");
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
++) {
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
++) {
270 if (jack_activate (client
)) {
271 fprintf (stderr
, "cannot activate client\n");
275 /* install a signal handler to properly quits jack client */
277 signal(SIGINT
, signal_handler
);
278 signal(SIGABRT
, signal_handler
);
279 signal(SIGTERM
, signal_handler
);
281 signal(SIGQUIT
, signal_handler
);
282 signal(SIGTERM
, signal_handler
);
283 signal(SIGHUP
, signal_handler
);
284 signal(SIGINT
, signal_handler
);
287 /* run until interrupted */
296 jack_client_close(client
);