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.
27 #include <jack/jack.h>
28 #include <jack/transport.h>
30 typedef jack_default_audio_sample_t sample_t
;
32 const double PI
= 3.14;
34 jack_client_t
*client
;
35 jack_port_t
*output_port
;
39 jack_nframes_t tone_length
, wave_length
;
42 int transport_aware
= 0;
43 jack_transport_state_t transport_state
;
50 "usage: jack_metro \n"
51 " [ --frequency OR -f frequency (in Hz) ]\n"
52 " [ --amplitude OR -A maximum amplitude (between 0 and 1) ]\n"
53 " [ --duration OR -D duration (in ms) ]\n"
54 " [ --attack OR -a attack (in percent of duration) ]\n"
55 " [ --decay OR -d decay (in percent of duration) ]\n"
56 " [ --name OR -n jack name for metronome client ]\n"
57 " [ --transport OR -t transport aware ]\n"
58 " --bpm OR -b beats per minute\n"
63 process_silence (jack_nframes_t nframes
)
65 sample_t
*buffer
= (sample_t
*) jack_port_get_buffer (output_port
, nframes
);
66 memset (buffer
, 0, sizeof (jack_default_audio_sample_t
) * nframes
);
70 process_audio (jack_nframes_t nframes
)
73 sample_t
*buffer
= (sample_t
*) jack_port_get_buffer (output_port
, nframes
);
74 jack_nframes_t frames_left
= nframes
;
76 while (wave_length
- offset
< frames_left
) {
77 memcpy (buffer
+ (nframes
- frames_left
), wave
+ offset
, sizeof (sample_t
) * (wave_length
- offset
));
78 frames_left
-= wave_length
- offset
;
81 if (frames_left
> 0) {
82 memcpy (buffer
+ (nframes
- frames_left
), wave
+ offset
, sizeof (sample_t
) * frames_left
);
83 offset
+= frames_left
;
88 process (jack_nframes_t nframes
, void *arg
)
90 if (transport_aware
) {
93 if (jack_transport_query (client
, &pos
)
94 != JackTransportRolling
) {
96 process_silence (nframes
);
99 offset
= pos
.frame
% wave_length
;
101 process_audio (nframes
);
106 sample_rate_change () {
107 printf("Sample rate has changed! Exiting...\n");
112 main (int argc
, char *argv
[])
116 int i
, attack_length
, decay_length
;
118 double max_amp
= 0.5;
122 int attack_percent
= 1, decay_percent
= 10, dur_arg
= 100;
123 char *client_name
= 0;
124 char *bpm_string
= "bpm";
126 jack_status_t status
;
128 const char *options
= "f:A:D:a:d:b:n:thv";
129 struct option long_options
[] =
131 {"frequency", 1, 0, 'f'},
132 {"amplitude", 1, 0, 'A'},
133 {"duration", 1, 0, 'D'},
134 {"attack", 1, 0, 'a'},
135 {"decay", 1, 0, 'd'},
138 {"transport", 0, 0, 't'},
140 {"verbose", 0, 0, 'v'},
144 while ((opt
= getopt_long (argc
, argv
, options
, long_options
, &option_index
)) != EOF
) {
147 if ((freq
= atoi (optarg
)) <= 0) {
148 fprintf (stderr
, "invalid frequency\n");
153 if (((max_amp
= atof (optarg
)) <= 0)|| (max_amp
> 1)) {
154 fprintf (stderr
, "invalid amplitude\n");
159 dur_arg
= atoi (optarg
);
160 fprintf (stderr
, "durarg = %u\n", dur_arg
);
163 if (((attack_percent
= atoi (optarg
)) < 0) || (attack_percent
> 100)) {
164 fprintf (stderr
, "invalid attack percent\n");
169 if (((decay_percent
= atoi (optarg
)) < 0) || (decay_percent
> 100)) {
170 fprintf (stderr
, "invalid decay percent\n");
176 if ((bpm
= atoi (optarg
)) < 0) {
177 fprintf (stderr
, "invalid bpm\n");
180 bpm_string
= (char *) malloc ((strlen (optarg
) + 4) * sizeof (char));
181 strcpy (bpm_string
, optarg
);
182 strcat (bpm_string
, "_bpm");
185 client_name
= (char *) malloc (strlen (optarg
) * sizeof (char));
186 strcpy (client_name
, optarg
);
195 fprintf (stderr
, "unknown option %c\n", opt
);
202 fprintf (stderr
, "bpm not specified\n");
207 /* Initial Jack setup, get sample rate */
209 client_name
= (char *) malloc (9 * sizeof (char));
210 strcpy (client_name
, "metro");
212 if ((client
= jack_client_open (client_name
, JackNoStartServer
, &status
)) == 0) {
213 fprintf (stderr
, "jack server not running?\n");
216 jack_set_process_callback (client
, process
, 0);
217 output_port
= jack_port_register (client
, bpm_string
, JACK_DEFAULT_AUDIO_TYPE
, JackPortIsOutput
, 0);
219 sr
= jack_get_sample_rate (client
);
221 /* setup wave table parameters */
222 wave_length
= 60 * sr
/ bpm
;
223 tone_length
= sr
* dur_arg
/ 1000;
224 attack_length
= tone_length
* attack_percent
/ 100;
225 decay_length
= tone_length
* decay_percent
/ 100;
226 scale
= 2 * PI
* freq
/ sr
;
228 if (tone_length
>= wave_length
) {
229 fprintf (stderr
, "invalid duration (tone length = %" PRIu32
230 ", wave length = %" PRIu32
"\n", tone_length
,
234 if (attack_length
+ decay_length
> (int)tone_length
) {
235 fprintf (stderr
, "invalid attack/decay\n");
239 /* Build the wave table */
240 wave
= (sample_t
*) malloc (wave_length
* sizeof(sample_t
));
241 amp
= (double *) malloc (tone_length
* sizeof(double));
243 for (i
= 0; i
< attack_length
; i
++) {
244 amp
[i
] = max_amp
* i
/ ((double) attack_length
);
246 for (i
= attack_length
; i
< (int)tone_length
- decay_length
; i
++) {
249 for (i
= (int)tone_length
- decay_length
; i
< (int)tone_length
; i
++) {
250 amp
[i
] = - max_amp
* (i
- (double) tone_length
) / ((double) decay_length
);
252 for (i
= 0; i
< (int)tone_length
; i
++) {
253 wave
[i
] = amp
[i
] * sin (scale
* i
);
255 for (i
= tone_length
; i
< (int)wave_length
; i
++) {
259 if (jack_activate (client
)) {
260 fprintf (stderr
, "cannot activate client");