view metro.c @ 1:46d4c88917a2

add Makefile; rename string to refer to "lsonify" instead of jack_metro; connect to physical input ports on startup
author paulo@localhost
date Sun, 17 May 2009 02:32:01 -0700
parents 047192fef940
children
line source
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.
17 */
19 // 20090516 PBA: started modifying metro.c for lsonify
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <errno.h>
24 #include <unistd.h>
25 #include <math.h>
26 #include <getopt.h>
27 #include <string.h>
29 #include <jack/jack.h>
30 #include <jack/transport.h>
32 typedef jack_default_audio_sample_t sample_t;
34 const double PI = 3.14;
36 jack_client_t *client;
37 jack_port_t *output_port;
38 unsigned long sr;
39 int freq = 880;
40 int bpm;
41 jack_nframes_t tone_length, wave_length;
42 sample_t *wave;
43 long offset = 0;
44 int transport_aware = 0;
45 jack_transport_state_t transport_state;
47 void
48 usage ()
50 {
51 fprintf (stderr, "\n"
52 "usage: lsonify \n"
53 " [ --frequency OR -f frequency (in Hz) ]\n"
54 " [ --amplitude OR -A maximum amplitude (between 0 and 1) ]\n"
55 " [ --duration OR -D duration (in ms) ]\n"
56 " [ --attack OR -a attack (in percent of duration) ]\n"
57 " [ --decay OR -d decay (in percent of duration) ]\n"
58 " [ --name OR -n jack name for metronome client ]\n"
59 " [ --transport OR -t transport aware ]\n"
60 " [ --nophysical OR -p to prevent auto-connect to all physical ports]\n"
61 " --bpm OR -b beats per minute\n"
62 );
63 }
65 void
66 process_silence (jack_nframes_t nframes)
67 {
68 sample_t *buffer = (sample_t *) jack_port_get_buffer (output_port, nframes);
69 memset (buffer, 0, sizeof (jack_default_audio_sample_t) * nframes);
70 }
72 void
73 process_audio (jack_nframes_t nframes)
74 {
76 sample_t *buffer = (sample_t *) jack_port_get_buffer (output_port, nframes);
77 jack_nframes_t frames_left = nframes;
79 while (wave_length - offset < frames_left) {
80 memcpy (buffer + (nframes - frames_left), wave + offset, sizeof (sample_t) * (wave_length - offset));
81 frames_left -= wave_length - offset;
82 offset = 0;
83 }
84 if (frames_left > 0) {
85 memcpy (buffer + (nframes - frames_left), wave + offset, sizeof (sample_t) * frames_left);
86 offset += frames_left;
87 }
88 }
90 int
91 process (jack_nframes_t nframes, void *arg)
92 {
93 if (transport_aware) {
94 jack_position_t pos;
96 if (jack_transport_query (client, &pos)
97 != JackTransportRolling) {
99 process_silence (nframes);
100 return 0;
101 }
102 offset = pos.frame % wave_length;
103 }
104 process_audio (nframes);
105 return 0;
106 }
108 int
109 sample_rate_change () {
110 printf("Sample rate has changed! Exiting...\n");
111 exit(-1);
112 }
114 int
115 main (int argc, char *argv[])
116 {
118 sample_t scale;
119 int i, attack_length, decay_length;
120 double *amp;
121 double max_amp = 0.5;
122 int opt;
123 int got_bpm = 0;
124 int attack_percent = 1, decay_percent = 10, dur_arg = 100;
125 char *client_name = 0;
126 char *port_string = "out";
127 int verbose = 0;
128 int connect_physical_ports = 1;
129 jack_status_t status;
131 const char *options = "f:A:D:a:d:b:n:tphv";
132 struct option long_options[] =
133 {
134 {"frequency", 1, 0, 'f'},
135 {"amplitude", 1, 0, 'A'},
136 {"duration", 1, 0, 'D'},
137 {"attack", 1, 0, 'a'},
138 {"decay", 1, 0, 'd'},
139 {"bpm", 1, 0, 'b'},
140 {"name", 1, 0, 'n'},
141 {"transport", 0, 0, 't'},
142 {"nophysical", 0, 0, 'p'},
143 {"help", 0, 0, 'h'},
144 {"verbose", 0, 0, 'v'},
145 {0, 0, 0, 0}
146 };
148 while ((opt = getopt_long (argc, argv, options, long_options, NULL)) != EOF) {
149 switch (opt) {
150 case 'f':
151 if ((freq = atoi (optarg)) <= 0) {
152 fprintf (stderr, "invalid frequency\n");
153 return -1;
154 }
155 break;
156 case 'A':
157 if (((max_amp = atof (optarg)) <= 0)|| (max_amp > 1)) {
158 fprintf (stderr, "invalid amplitude\n");
159 return -1;
160 }
161 break;
162 case 'D':
163 dur_arg = atoi (optarg);
164 fprintf (stderr, "durarg = %u\n", dur_arg);
165 break;
166 case 'a':
167 if (((attack_percent = atoi (optarg)) < 0) || (attack_percent > 100)) {
168 fprintf (stderr, "invalid attack percent\n");
169 return -1;
170 }
171 break;
172 case 'd':
173 if (((decay_percent = atoi (optarg)) < 0) || (decay_percent > 100)) {
174 fprintf (stderr, "invalid decay percent\n");
175 return -1;
176 }
177 break;
178 case 'b':
179 got_bpm = 1;
180 if ((bpm = atoi (optarg)) < 0) {
181 fprintf (stderr, "invalid bpm\n");
182 return -1;
183 }
184 break;
185 case 'n':
186 client_name = (char *) malloc (strlen (optarg) * sizeof (char));
187 strcpy (client_name, optarg);
188 break;
189 case 'v':
190 verbose = 1;
191 break;
192 case 't':
193 transport_aware = 1;
194 break;
195 case 'p':
196 connect_physical_ports = 0;
197 break;
198 default:
199 fprintf (stderr, "unknown option %c\n", opt);
200 case 'h':
201 usage ();
202 return -1;
203 }
204 }
205 if (!got_bpm) {
206 fprintf (stderr, "bpm not specified\n");
207 usage ();
208 return -1;
209 }
211 /* Initial Jack setup, get sample rate */
212 if (!client_name) {
213 pid_t pid = getpid();
214 client_name = (char *) malloc (32 * sizeof (char));
215 snprintf (client_name, 32, "metro_%d", pid);
216 }
217 if ((client = jack_client_open (client_name, JackNoStartServer, &status)) == 0) {
218 fprintf (stderr, "jack server not running?\n");
219 return 1;
220 }
221 jack_set_process_callback (client, process, 0);
222 output_port = jack_port_register (client, port_string, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
224 sr = jack_get_sample_rate (client);
226 /* setup wave table parameters */
227 wave_length = 60 * sr / bpm;
228 tone_length = sr * dur_arg / 1000;
229 attack_length = tone_length * attack_percent / 100;
230 decay_length = tone_length * decay_percent / 100;
231 scale = 2 * PI * freq / sr;
233 if (tone_length >= wave_length) {
234 fprintf (stderr, "invalid duration (tone length = %" PRIu32
235 ", wave length = %" PRIu32 "\n", tone_length,
236 wave_length);
237 return -1;
238 }
239 if (attack_length + decay_length > (int)tone_length) {
240 fprintf (stderr, "invalid attack/decay\n");
241 return -1;
242 }
244 /* Build the wave table */
245 wave = (sample_t *) malloc (wave_length * sizeof(sample_t));
246 amp = (double *) malloc (tone_length * sizeof(double));
248 for (i = 0; i < attack_length; i++) {
249 amp[i] = max_amp * i / ((double) attack_length);
250 }
251 for (i = attack_length; i < (int)tone_length - decay_length; i++) {
252 amp[i] = max_amp;
253 }
254 for (i = (int)tone_length - decay_length; i < (int)tone_length; i++) {
255 amp[i] = - max_amp * (i - (double) tone_length) / ((double) decay_length);
256 }
257 for (i = 0; i < (int)tone_length; i++) {
258 wave[i] = amp[i] * sin (scale * i);
259 }
260 for (i = tone_length; i < (int)wave_length; i++) {
261 wave[i] = 0;
262 }
264 if (jack_activate (client)) {
265 fprintf (stderr, "cannot activate client");
266 return 1;
267 }
269 /* connect to physical ports */
270 if (connect_physical_ports) {
271 const char **ports = jack_get_ports (client, NULL, NULL, JackPortIsPhysical | JackPortIsInput);
272 const char **c;
273 for (c = ports; c && *c; c++)
274 jack_connect (client, jack_port_name(output_port), *c);
275 }
277 while (1) {
278 sleep(1);
279 };
281 }