# HG changeset patch # User paulo@localhost # Date 1242540226 25200 # Node ID 047192fef9402168efc780ffa4f75edd151f7745 copy metro.c from jack example-clients diff -r 000000000000 -r 047192fef940 metro.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/metro.c Sat May 16 23:03:46 2009 -0700 @@ -0,0 +1,270 @@ +/* + Copyright (C) 2002 Anthony Van Groningen + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +// 20090516 PBA: started modifying metro.c for lsonify + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +typedef jack_default_audio_sample_t sample_t; + +const double PI = 3.14; + +jack_client_t *client; +jack_port_t *output_port; +unsigned long sr; +int freq = 880; +int bpm; +jack_nframes_t tone_length, wave_length; +sample_t *wave; +long offset = 0; +int transport_aware = 0; +jack_transport_state_t transport_state; + +void +usage () + +{ + fprintf (stderr, "\n" +"usage: jack_metro \n" +" [ --frequency OR -f frequency (in Hz) ]\n" +" [ --amplitude OR -A maximum amplitude (between 0 and 1) ]\n" +" [ --duration OR -D duration (in ms) ]\n" +" [ --attack OR -a attack (in percent of duration) ]\n" +" [ --decay OR -d decay (in percent of duration) ]\n" +" [ --name OR -n jack name for metronome client ]\n" +" [ --transport OR -t transport aware ]\n" +" --bpm OR -b beats per minute\n" +); +} + +void +process_silence (jack_nframes_t nframes) +{ + sample_t *buffer = (sample_t *) jack_port_get_buffer (output_port, nframes); + memset (buffer, 0, sizeof (jack_default_audio_sample_t) * nframes); +} + +void +process_audio (jack_nframes_t nframes) +{ + + sample_t *buffer = (sample_t *) jack_port_get_buffer (output_port, nframes); + jack_nframes_t frames_left = nframes; + + while (wave_length - offset < frames_left) { + memcpy (buffer + (nframes - frames_left), wave + offset, sizeof (sample_t) * (wave_length - offset)); + frames_left -= wave_length - offset; + offset = 0; + } + if (frames_left > 0) { + memcpy (buffer + (nframes - frames_left), wave + offset, sizeof (sample_t) * frames_left); + offset += frames_left; + } +} + +int +process (jack_nframes_t nframes, void *arg) +{ + if (transport_aware) { + jack_position_t pos; + + if (jack_transport_query (client, &pos) + != JackTransportRolling) { + + process_silence (nframes); + return 0; + } + offset = pos.frame % wave_length; + } + process_audio (nframes); + return 0; +} + +int +sample_rate_change () { + printf("Sample rate has changed! Exiting...\n"); + exit(-1); +} + +int +main (int argc, char *argv[]) +{ + + sample_t scale; + int i, attack_length, decay_length; + double *amp; + double max_amp = 0.5; + int option_index; + int opt; + int got_bpm = 0; + int attack_percent = 1, decay_percent = 10, dur_arg = 100; + char *client_name = 0; + char *bpm_string = "bpm"; + int verbose = 0; + jack_status_t status; + + const char *options = "f:A:D:a:d:b:n:thv"; + struct option long_options[] = + { + {"frequency", 1, 0, 'f'}, + {"amplitude", 1, 0, 'A'}, + {"duration", 1, 0, 'D'}, + {"attack", 1, 0, 'a'}, + {"decay", 1, 0, 'd'}, + {"bpm", 1, 0, 'b'}, + {"name", 1, 0, 'n'}, + {"transport", 0, 0, 't'}, + {"help", 0, 0, 'h'}, + {"verbose", 0, 0, 'v'}, + {0, 0, 0, 0} + }; + + while ((opt = getopt_long (argc, argv, options, long_options, &option_index)) != EOF) { + switch (opt) { + case 'f': + if ((freq = atoi (optarg)) <= 0) { + fprintf (stderr, "invalid frequency\n"); + return -1; + } + break; + case 'A': + if (((max_amp = atof (optarg)) <= 0)|| (max_amp > 1)) { + fprintf (stderr, "invalid amplitude\n"); + return -1; + } + break; + case 'D': + dur_arg = atoi (optarg); + fprintf (stderr, "durarg = %u\n", dur_arg); + break; + case 'a': + if (((attack_percent = atoi (optarg)) < 0) || (attack_percent > 100)) { + fprintf (stderr, "invalid attack percent\n"); + return -1; + } + break; + case 'd': + if (((decay_percent = atoi (optarg)) < 0) || (decay_percent > 100)) { + fprintf (stderr, "invalid decay percent\n"); + return -1; + } + break; + case 'b': + got_bpm = 1; + if ((bpm = atoi (optarg)) < 0) { + fprintf (stderr, "invalid bpm\n"); + return -1; + } + bpm_string = (char *) malloc ((strlen (optarg) + 4) * sizeof (char)); + strcpy (bpm_string, optarg); + strcat (bpm_string, "_bpm"); + break; + case 'n': + client_name = (char *) malloc (strlen (optarg) * sizeof (char)); + strcpy (client_name, optarg); + break; + case 'v': + verbose = 1; + break; + case 't': + transport_aware = 1; + break; + default: + fprintf (stderr, "unknown option %c\n", opt); + case 'h': + usage (); + return -1; + } + } + if (!got_bpm) { + fprintf (stderr, "bpm not specified\n"); + usage (); + return -1; + } + + /* Initial Jack setup, get sample rate */ + if (!client_name) { + client_name = (char *) malloc (9 * sizeof (char)); + strcpy (client_name, "metro"); + } + if ((client = jack_client_open (client_name, JackNoStartServer, &status)) == 0) { + fprintf (stderr, "jack server not running?\n"); + return 1; + } + jack_set_process_callback (client, process, 0); + output_port = jack_port_register (client, bpm_string, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); + + sr = jack_get_sample_rate (client); + + /* setup wave table parameters */ + wave_length = 60 * sr / bpm; + tone_length = sr * dur_arg / 1000; + attack_length = tone_length * attack_percent / 100; + decay_length = tone_length * decay_percent / 100; + scale = 2 * PI * freq / sr; + + if (tone_length >= wave_length) { + fprintf (stderr, "invalid duration (tone length = %" PRIu32 + ", wave length = %" PRIu32 "\n", tone_length, + wave_length); + return -1; + } + if (attack_length + decay_length > (int)tone_length) { + fprintf (stderr, "invalid attack/decay\n"); + return -1; + } + + /* Build the wave table */ + wave = (sample_t *) malloc (wave_length * sizeof(sample_t)); + amp = (double *) malloc (tone_length * sizeof(double)); + + for (i = 0; i < attack_length; i++) { + amp[i] = max_amp * i / ((double) attack_length); + } + for (i = attack_length; i < (int)tone_length - decay_length; i++) { + amp[i] = max_amp; + } + for (i = (int)tone_length - decay_length; i < (int)tone_length; i++) { + amp[i] = - max_amp * (i - (double) tone_length) / ((double) decay_length); + } + for (i = 0; i < (int)tone_length; i++) { + wave[i] = amp[i] * sin (scale * i); + } + for (i = tone_length; i < (int)wave_length; i++) { + wave[i] = 0; + } + + if (jack_activate (client)) { + fprintf (stderr, "cannot activate client"); + return 1; + } + + while (1) { + sleep(1); + }; + +}