changeset 0:047192fef940

copy metro.c from jack example-clients
author paulo@localhost
date Sat, 16 May 2009 23:03:46 -0700
parents
children 46d4c88917a2
files metro.c
diffstat 1 files changed, 270 insertions(+), 0 deletions(-) [+]
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/metro.c	Sat May 16 23:03:46 2009 -0700
     1.3 @@ -0,0 +1,270 @@
     1.4 +/*
     1.5 +    Copyright (C) 2002 Anthony Van Groningen
     1.6 +    
     1.7 +    This program is free software; you can redistribute it and/or modify
     1.8 +    it under the terms of the GNU General Public License as published by
     1.9 +    the Free Software Foundation; either version 2 of the License, or
    1.10 +    (at your option) any later version.
    1.11 +
    1.12 +    This program is distributed in the hope that it will be useful,
    1.13 +    but WITHOUT ANY WARRANTY; without even the implied warranty of
    1.14 +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    1.15 +    GNU General Public License for more details.
    1.16 +
    1.17 +    You should have received a copy of the GNU General Public License
    1.18 +    along with this program; if not, write to the Free Software
    1.19 +    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
    1.20 +*/
    1.21 +
    1.22 +// 20090516 PBA: started modifying metro.c for lsonify 
    1.23 +
    1.24 +#include <stdlib.h>
    1.25 +#include <stdio.h>
    1.26 +#include <errno.h>
    1.27 +#include <unistd.h>
    1.28 +#include <math.h>
    1.29 +#include <getopt.h>
    1.30 +#include <string.h>
    1.31 +
    1.32 +#include <jack/jack.h>
    1.33 +#include <jack/transport.h>
    1.34 +
    1.35 +typedef jack_default_audio_sample_t sample_t;
    1.36 +
    1.37 +const double PI = 3.14;
    1.38 +
    1.39 +jack_client_t *client;
    1.40 +jack_port_t *output_port;
    1.41 +unsigned long sr;
    1.42 +int freq = 880;
    1.43 +int bpm;
    1.44 +jack_nframes_t tone_length, wave_length;
    1.45 +sample_t *wave;
    1.46 +long offset = 0;
    1.47 +int transport_aware = 0;
    1.48 +jack_transport_state_t transport_state;
    1.49 +
    1.50 +void
    1.51 +usage ()
    1.52 +
    1.53 +{
    1.54 +	fprintf (stderr, "\n"
    1.55 +"usage: jack_metro \n"
    1.56 +"              [ --frequency OR -f frequency (in Hz) ]\n"
    1.57 +"              [ --amplitude OR -A maximum amplitude (between 0 and 1) ]\n"
    1.58 +"              [ --duration OR -D duration (in ms) ]\n"
    1.59 +"              [ --attack OR -a attack (in percent of duration) ]\n"
    1.60 +"              [ --decay OR -d decay (in percent of duration) ]\n"
    1.61 +"              [ --name OR -n jack name for metronome client ]\n"
    1.62 +"              [ --transport OR -t transport aware ]\n"
    1.63 +"              --bpm OR -b beats per minute\n"
    1.64 +);
    1.65 +}
    1.66 +
    1.67 +void
    1.68 +process_silence (jack_nframes_t nframes) 
    1.69 +{
    1.70 +	sample_t *buffer = (sample_t *) jack_port_get_buffer (output_port, nframes);
    1.71 +	memset (buffer, 0, sizeof (jack_default_audio_sample_t) * nframes);
    1.72 +}
    1.73 +
    1.74 +void
    1.75 +process_audio (jack_nframes_t nframes) 
    1.76 +{
    1.77 +
    1.78 +	sample_t *buffer = (sample_t *) jack_port_get_buffer (output_port, nframes);
    1.79 +	jack_nframes_t frames_left = nframes;
    1.80 +		
    1.81 +	while (wave_length - offset < frames_left) {
    1.82 +		memcpy (buffer + (nframes - frames_left), wave + offset, sizeof (sample_t) * (wave_length - offset));
    1.83 +		frames_left -= wave_length - offset;
    1.84 +		offset = 0;
    1.85 +	}
    1.86 +	if (frames_left > 0) {
    1.87 +		memcpy (buffer + (nframes - frames_left), wave + offset, sizeof (sample_t) * frames_left);
    1.88 +		offset += frames_left;
    1.89 +	}
    1.90 +}
    1.91 +
    1.92 +int
    1.93 +process (jack_nframes_t nframes, void *arg)
    1.94 +{
    1.95 +	if (transport_aware) {
    1.96 +		jack_position_t pos;
    1.97 +
    1.98 +		if (jack_transport_query (client, &pos)
    1.99 +		    != JackTransportRolling) {
   1.100 +
   1.101 +			process_silence (nframes);
   1.102 +			return 0;
   1.103 +		}
   1.104 +		offset = pos.frame % wave_length;
   1.105 +	}
   1.106 +	process_audio (nframes);
   1.107 +	return 0;
   1.108 +}
   1.109 +
   1.110 +int
   1.111 +sample_rate_change () {
   1.112 +	printf("Sample rate has changed! Exiting...\n");
   1.113 +	exit(-1);
   1.114 +}
   1.115 +
   1.116 +int
   1.117 +main (int argc, char *argv[])
   1.118 +{
   1.119 +	
   1.120 +	sample_t scale;
   1.121 +	int i, attack_length, decay_length;
   1.122 +	double *amp;
   1.123 +	double max_amp = 0.5;
   1.124 +	int option_index;
   1.125 +	int opt;
   1.126 +	int got_bpm = 0;
   1.127 +	int attack_percent = 1, decay_percent = 10, dur_arg = 100;
   1.128 +	char *client_name = 0;
   1.129 +	char *bpm_string = "bpm";
   1.130 +	int verbose = 0;
   1.131 +	jack_status_t status;
   1.132 +
   1.133 +	const char *options = "f:A:D:a:d:b:n:thv";
   1.134 +	struct option long_options[] =
   1.135 +	{
   1.136 +		{"frequency", 1, 0, 'f'},
   1.137 +		{"amplitude", 1, 0, 'A'},
   1.138 +		{"duration", 1, 0, 'D'},
   1.139 +		{"attack", 1, 0, 'a'},
   1.140 +		{"decay", 1, 0, 'd'},
   1.141 +		{"bpm", 1, 0, 'b'},
   1.142 +		{"name", 1, 0, 'n'},
   1.143 +		{"transport", 0, 0, 't'},
   1.144 +		{"help", 0, 0, 'h'},
   1.145 +		{"verbose", 0, 0, 'v'},
   1.146 +		{0, 0, 0, 0}
   1.147 +	};
   1.148 +	
   1.149 +	while ((opt = getopt_long (argc, argv, options, long_options, &option_index)) != EOF) {
   1.150 +		switch (opt) {
   1.151 +		case 'f':
   1.152 +			if ((freq = atoi (optarg)) <= 0) {
   1.153 +				fprintf (stderr, "invalid frequency\n");
   1.154 +				return -1;
   1.155 +			}
   1.156 +			break;
   1.157 +		case 'A':
   1.158 +			if (((max_amp = atof (optarg)) <= 0)|| (max_amp > 1)) {
   1.159 +				fprintf (stderr, "invalid amplitude\n");
   1.160 +				return -1;
   1.161 +			}
   1.162 +			break;
   1.163 +		case 'D':
   1.164 +			dur_arg = atoi (optarg);
   1.165 +			fprintf (stderr, "durarg = %u\n", dur_arg);
   1.166 +			break;
   1.167 +		case 'a':
   1.168 +			if (((attack_percent = atoi (optarg)) < 0) || (attack_percent > 100)) {
   1.169 +				fprintf (stderr, "invalid attack percent\n");
   1.170 +				return -1;
   1.171 +			}
   1.172 +			break;
   1.173 +		case 'd':
   1.174 +			if (((decay_percent = atoi (optarg)) < 0) || (decay_percent > 100)) {
   1.175 +				fprintf (stderr, "invalid decay percent\n");
   1.176 +				return -1;
   1.177 +			}
   1.178 +			break;
   1.179 +		case 'b':
   1.180 +			got_bpm = 1;
   1.181 +			if ((bpm = atoi (optarg)) < 0) {
   1.182 +				fprintf (stderr, "invalid bpm\n");
   1.183 +				return -1;
   1.184 +			}
   1.185 +			bpm_string = (char *) malloc ((strlen (optarg) + 4) * sizeof (char));
   1.186 +			strcpy (bpm_string, optarg);
   1.187 +			strcat (bpm_string, "_bpm");
   1.188 +			break;
   1.189 +		case 'n':
   1.190 +			client_name = (char *) malloc (strlen (optarg) * sizeof (char));
   1.191 +			strcpy (client_name, optarg);
   1.192 +			break;
   1.193 +		case 'v':
   1.194 +			verbose = 1;
   1.195 +			break;
   1.196 +		case 't':
   1.197 +			transport_aware = 1;
   1.198 +			break;
   1.199 +		default:
   1.200 +			fprintf (stderr, "unknown option %c\n", opt); 
   1.201 +		case 'h':
   1.202 +			usage ();
   1.203 +			return -1;
   1.204 +		}
   1.205 +	}
   1.206 +	if (!got_bpm) {
   1.207 +		fprintf (stderr, "bpm not specified\n");
   1.208 +		usage ();
   1.209 +		return -1;
   1.210 +	}
   1.211 +
   1.212 +	/* Initial Jack setup, get sample rate */
   1.213 +	if (!client_name) {
   1.214 +		client_name = (char *) malloc (9 * sizeof (char));
   1.215 +		strcpy (client_name, "metro");
   1.216 +	}
   1.217 +	if ((client = jack_client_open (client_name, JackNoStartServer, &status)) == 0) {
   1.218 +		fprintf (stderr, "jack server not running?\n");
   1.219 +		return 1;
   1.220 +	}
   1.221 +	jack_set_process_callback (client, process, 0);
   1.222 +	output_port = jack_port_register (client, bpm_string, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
   1.223 +
   1.224 +	sr = jack_get_sample_rate (client);
   1.225 +
   1.226 +	/* setup wave table parameters */
   1.227 +	wave_length = 60 * sr / bpm;
   1.228 +	tone_length = sr * dur_arg / 1000;
   1.229 +	attack_length = tone_length * attack_percent / 100;
   1.230 +	decay_length = tone_length * decay_percent / 100;
   1.231 +	scale = 2 * PI * freq / sr;
   1.232 +
   1.233 +	if (tone_length >= wave_length) {
   1.234 +		fprintf (stderr, "invalid duration (tone length = %" PRIu32
   1.235 +			 ", wave length = %" PRIu32 "\n", tone_length,
   1.236 +			 wave_length);
   1.237 +		return -1;
   1.238 +	}
   1.239 +	if (attack_length + decay_length > (int)tone_length) {
   1.240 +		fprintf (stderr, "invalid attack/decay\n");
   1.241 +		return -1;
   1.242 +	}
   1.243 +
   1.244 +	/* Build the wave table */
   1.245 +	wave = (sample_t *) malloc (wave_length * sizeof(sample_t));
   1.246 +	amp = (double *) malloc (tone_length * sizeof(double));
   1.247 +
   1.248 +	for (i = 0; i < attack_length; i++) {
   1.249 +		amp[i] = max_amp * i / ((double) attack_length);
   1.250 +	}
   1.251 +	for (i = attack_length; i < (int)tone_length - decay_length; i++) {
   1.252 +		amp[i] = max_amp;
   1.253 +	}
   1.254 +	for (i = (int)tone_length - decay_length; i < (int)tone_length; i++) {
   1.255 +		amp[i] = - max_amp * (i - (double) tone_length) / ((double) decay_length);
   1.256 +	}
   1.257 +	for (i = 0; i < (int)tone_length; i++) {
   1.258 +		wave[i] = amp[i] * sin (scale * i);
   1.259 +	}
   1.260 +	for (i = tone_length; i < (int)wave_length; i++) {
   1.261 +		wave[i] = 0;
   1.262 +	}
   1.263 +
   1.264 +	if (jack_activate (client)) {
   1.265 +		fprintf (stderr, "cannot activate client");
   1.266 +		return 1;
   1.267 +	}
   1.268 +
   1.269 +	while (1) {
   1.270 +		sleep(1);
   1.271 +	};
   1.272 +	
   1.273 +}