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