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");