annotate lsonify.c @ 3:3dd48f06493e

add sample rate change callback
author paulo@localhost
date Thu, 21 May 2009 00:56:16 -0700
parents ff028323c114
children
rev   line source
paulo@0 1 /*
paulo@0 2 Copyright (C) 2002 Anthony Van Groningen
paulo@0 3
paulo@0 4 This program is free software; you can redistribute it and/or modify
paulo@0 5 it under the terms of the GNU General Public License as published by
paulo@0 6 the Free Software Foundation; either version 2 of the License, or
paulo@0 7 (at your option) any later version.
paulo@0 8
paulo@0 9 This program is distributed in the hope that it will be useful,
paulo@0 10 but WITHOUT ANY WARRANTY; without even the implied warranty of
paulo@0 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
paulo@0 12 GNU General Public License for more details.
paulo@0 13
paulo@0 14 You should have received a copy of the GNU General Public License
paulo@0 15 along with this program; if not, write to the Free Software
paulo@0 16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
paulo@0 17 */
paulo@0 18
paulo@0 19 // 20090516 PBA: started modifying metro.c for lsonify
paulo@0 20
paulo@0 21 #include <stdlib.h>
paulo@0 22 #include <stdio.h>
paulo@0 23 #include <errno.h>
paulo@0 24 #include <unistd.h>
paulo@0 25 #include <math.h>
paulo@0 26 #include <getopt.h>
paulo@0 27 #include <string.h>
paulo@0 28
paulo@0 29 #include <jack/jack.h>
paulo@0 30 #include <jack/transport.h>
paulo@0 31
paulo@0 32 typedef jack_default_audio_sample_t sample_t;
paulo@0 33
paulo@0 34 const double PI = 3.14;
paulo@0 35
paulo@0 36 jack_client_t *client;
paulo@0 37 jack_port_t *output_port;
paulo@0 38 unsigned long sr;
paulo@0 39 int freq = 880;
paulo@0 40 int bpm;
paulo@0 41 jack_nframes_t tone_length, wave_length;
paulo@0 42 sample_t *wave;
paulo@0 43 long offset = 0;
paulo@0 44 int transport_aware = 0;
paulo@0 45 jack_transport_state_t transport_state;
paulo@0 46
paulo@0 47 void
paulo@0 48 usage ()
paulo@0 49
paulo@0 50 {
paulo@0 51 fprintf (stderr, "\n"
paulo@1 52 "usage: lsonify \n"
paulo@0 53 " [ --frequency OR -f frequency (in Hz) ]\n"
paulo@0 54 " [ --amplitude OR -A maximum amplitude (between 0 and 1) ]\n"
paulo@0 55 " [ --duration OR -D duration (in ms) ]\n"
paulo@0 56 " [ --attack OR -a attack (in percent of duration) ]\n"
paulo@0 57 " [ --decay OR -d decay (in percent of duration) ]\n"
paulo@0 58 " [ --name OR -n jack name for metronome client ]\n"
paulo@0 59 " [ --transport OR -t transport aware ]\n"
paulo@1 60 " [ --nophysical OR -p to prevent auto-connect to all physical ports]\n"
paulo@0 61 " --bpm OR -b beats per minute\n"
paulo@0 62 );
paulo@0 63 }
paulo@0 64
paulo@0 65 void
paulo@0 66 process_silence (jack_nframes_t nframes)
paulo@0 67 {
paulo@0 68 sample_t *buffer = (sample_t *) jack_port_get_buffer (output_port, nframes);
paulo@0 69 memset (buffer, 0, sizeof (jack_default_audio_sample_t) * nframes);
paulo@0 70 }
paulo@0 71
paulo@0 72 void
paulo@0 73 process_audio (jack_nframes_t nframes)
paulo@0 74 {
paulo@0 75
paulo@0 76 sample_t *buffer = (sample_t *) jack_port_get_buffer (output_port, nframes);
paulo@0 77 jack_nframes_t frames_left = nframes;
paulo@0 78
paulo@0 79 while (wave_length - offset < frames_left) {
paulo@0 80 memcpy (buffer + (nframes - frames_left), wave + offset, sizeof (sample_t) * (wave_length - offset));
paulo@0 81 frames_left -= wave_length - offset;
paulo@0 82 offset = 0;
paulo@0 83 }
paulo@0 84 if (frames_left > 0) {
paulo@0 85 memcpy (buffer + (nframes - frames_left), wave + offset, sizeof (sample_t) * frames_left);
paulo@0 86 offset += frames_left;
paulo@0 87 }
paulo@0 88 }
paulo@0 89
paulo@0 90 int
paulo@0 91 process (jack_nframes_t nframes, void *arg)
paulo@0 92 {
paulo@0 93 if (transport_aware) {
paulo@0 94 jack_position_t pos;
paulo@0 95
paulo@0 96 if (jack_transport_query (client, &pos)
paulo@0 97 != JackTransportRolling) {
paulo@0 98
paulo@0 99 process_silence (nframes);
paulo@0 100 return 0;
paulo@0 101 }
paulo@0 102 offset = pos.frame % wave_length;
paulo@0 103 }
paulo@0 104 process_audio (nframes);
paulo@0 105 return 0;
paulo@0 106 }
paulo@0 107
paulo@0 108 int
paulo@3 109 sample_rate_change (jack_nframes_t nframes, void *arg) {
paulo@3 110 if (nframes != sr) {
paulo@3 111 printf("Sample rate has changed! Exiting...\n");
paulo@3 112 exit(-1);
paulo@3 113 }
paulo@3 114 return 0;
paulo@0 115 }
paulo@0 116
paulo@0 117 int
paulo@0 118 main (int argc, char *argv[])
paulo@0 119 {
paulo@0 120
paulo@0 121 sample_t scale;
paulo@0 122 int i, attack_length, decay_length;
paulo@0 123 double *amp;
paulo@0 124 double max_amp = 0.5;
paulo@0 125 int opt;
paulo@0 126 int got_bpm = 0;
paulo@0 127 int attack_percent = 1, decay_percent = 10, dur_arg = 100;
paulo@0 128 char *client_name = 0;
paulo@1 129 char *port_string = "out";
paulo@0 130 int verbose = 0;
paulo@1 131 int connect_physical_ports = 1;
paulo@0 132 jack_status_t status;
paulo@0 133
paulo@1 134 const char *options = "f:A:D:a:d:b:n:tphv";
paulo@0 135 struct option long_options[] =
paulo@0 136 {
paulo@0 137 {"frequency", 1, 0, 'f'},
paulo@0 138 {"amplitude", 1, 0, 'A'},
paulo@0 139 {"duration", 1, 0, 'D'},
paulo@0 140 {"attack", 1, 0, 'a'},
paulo@0 141 {"decay", 1, 0, 'd'},
paulo@0 142 {"bpm", 1, 0, 'b'},
paulo@0 143 {"name", 1, 0, 'n'},
paulo@0 144 {"transport", 0, 0, 't'},
paulo@1 145 {"nophysical", 0, 0, 'p'},
paulo@0 146 {"help", 0, 0, 'h'},
paulo@0 147 {"verbose", 0, 0, 'v'},
paulo@0 148 {0, 0, 0, 0}
paulo@0 149 };
paulo@0 150
paulo@1 151 while ((opt = getopt_long (argc, argv, options, long_options, NULL)) != EOF) {
paulo@0 152 switch (opt) {
paulo@0 153 case 'f':
paulo@0 154 if ((freq = atoi (optarg)) <= 0) {
paulo@0 155 fprintf (stderr, "invalid frequency\n");
paulo@0 156 return -1;
paulo@0 157 }
paulo@0 158 break;
paulo@0 159 case 'A':
paulo@0 160 if (((max_amp = atof (optarg)) <= 0)|| (max_amp > 1)) {
paulo@0 161 fprintf (stderr, "invalid amplitude\n");
paulo@0 162 return -1;
paulo@0 163 }
paulo@0 164 break;
paulo@0 165 case 'D':
paulo@0 166 dur_arg = atoi (optarg);
paulo@0 167 fprintf (stderr, "durarg = %u\n", dur_arg);
paulo@0 168 break;
paulo@0 169 case 'a':
paulo@0 170 if (((attack_percent = atoi (optarg)) < 0) || (attack_percent > 100)) {
paulo@0 171 fprintf (stderr, "invalid attack percent\n");
paulo@0 172 return -1;
paulo@0 173 }
paulo@0 174 break;
paulo@0 175 case 'd':
paulo@0 176 if (((decay_percent = atoi (optarg)) < 0) || (decay_percent > 100)) {
paulo@0 177 fprintf (stderr, "invalid decay percent\n");
paulo@0 178 return -1;
paulo@0 179 }
paulo@0 180 break;
paulo@0 181 case 'b':
paulo@0 182 got_bpm = 1;
paulo@0 183 if ((bpm = atoi (optarg)) < 0) {
paulo@0 184 fprintf (stderr, "invalid bpm\n");
paulo@0 185 return -1;
paulo@0 186 }
paulo@0 187 break;
paulo@0 188 case 'n':
paulo@0 189 client_name = (char *) malloc (strlen (optarg) * sizeof (char));
paulo@0 190 strcpy (client_name, optarg);
paulo@0 191 break;
paulo@0 192 case 'v':
paulo@0 193 verbose = 1;
paulo@0 194 break;
paulo@0 195 case 't':
paulo@0 196 transport_aware = 1;
paulo@0 197 break;
paulo@1 198 case 'p':
paulo@1 199 connect_physical_ports = 0;
paulo@1 200 break;
paulo@0 201 default:
paulo@0 202 fprintf (stderr, "unknown option %c\n", opt);
paulo@0 203 case 'h':
paulo@0 204 usage ();
paulo@0 205 return -1;
paulo@0 206 }
paulo@0 207 }
paulo@0 208 if (!got_bpm) {
paulo@0 209 fprintf (stderr, "bpm not specified\n");
paulo@0 210 usage ();
paulo@0 211 return -1;
paulo@0 212 }
paulo@0 213
paulo@0 214 /* Initial Jack setup, get sample rate */
paulo@0 215 if (!client_name) {
paulo@1 216 pid_t pid = getpid();
paulo@1 217 client_name = (char *) malloc (32 * sizeof (char));
paulo@1 218 snprintf (client_name, 32, "metro_%d", pid);
paulo@0 219 }
paulo@0 220 if ((client = jack_client_open (client_name, JackNoStartServer, &status)) == 0) {
paulo@0 221 fprintf (stderr, "jack server not running?\n");
paulo@0 222 return 1;
paulo@0 223 }
paulo@0 224 jack_set_process_callback (client, process, 0);
paulo@1 225 output_port = jack_port_register (client, port_string, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
paulo@0 226
paulo@0 227 sr = jack_get_sample_rate (client);
paulo@3 228 jack_set_sample_rate_callback (client, sample_rate_change, 0);
paulo@0 229
paulo@0 230 /* setup wave table parameters */
paulo@0 231 wave_length = 60 * sr / bpm;
paulo@0 232 tone_length = sr * dur_arg / 1000;
paulo@0 233 attack_length = tone_length * attack_percent / 100;
paulo@0 234 decay_length = tone_length * decay_percent / 100;
paulo@0 235 scale = 2 * PI * freq / sr;
paulo@0 236
paulo@0 237 if (tone_length >= wave_length) {
paulo@0 238 fprintf (stderr, "invalid duration (tone length = %" PRIu32
paulo@0 239 ", wave length = %" PRIu32 "\n", tone_length,
paulo@0 240 wave_length);
paulo@0 241 return -1;
paulo@0 242 }
paulo@0 243 if (attack_length + decay_length > (int)tone_length) {
paulo@0 244 fprintf (stderr, "invalid attack/decay\n");
paulo@0 245 return -1;
paulo@0 246 }
paulo@0 247
paulo@0 248 /* Build the wave table */
paulo@0 249 wave = (sample_t *) malloc (wave_length * sizeof(sample_t));
paulo@0 250 amp = (double *) malloc (tone_length * sizeof(double));
paulo@0 251
paulo@0 252 for (i = 0; i < attack_length; i++) {
paulo@0 253 amp[i] = max_amp * i / ((double) attack_length);
paulo@0 254 }
paulo@0 255 for (i = attack_length; i < (int)tone_length - decay_length; i++) {
paulo@0 256 amp[i] = max_amp;
paulo@0 257 }
paulo@0 258 for (i = (int)tone_length - decay_length; i < (int)tone_length; i++) {
paulo@0 259 amp[i] = - max_amp * (i - (double) tone_length) / ((double) decay_length);
paulo@0 260 }
paulo@0 261 for (i = 0; i < (int)tone_length; i++) {
paulo@0 262 wave[i] = amp[i] * sin (scale * i);
paulo@0 263 }
paulo@0 264 for (i = tone_length; i < (int)wave_length; i++) {
paulo@0 265 wave[i] = 0;
paulo@0 266 }
paulo@0 267
paulo@0 268 if (jack_activate (client)) {
paulo@0 269 fprintf (stderr, "cannot activate client");
paulo@0 270 return 1;
paulo@0 271 }
paulo@0 272
paulo@1 273 /* connect to physical ports */
paulo@1 274 if (connect_physical_ports) {
paulo@1 275 const char **ports = jack_get_ports (client, NULL, NULL, JackPortIsPhysical | JackPortIsInput);
paulo@1 276 const char **c;
paulo@1 277 for (c = ports; c && *c; c++)
paulo@1 278 jack_connect (client, jack_port_name(output_port), *c);
paulo@1 279 }
paulo@1 280
paulo@0 281 while (1) {
paulo@0 282 sleep(1);
paulo@0 283 };
paulo@0 284
paulo@0 285 }