diff --git a/jack_meter.c b/jack_meter.c index 6a67748..87a3b01 100644 --- a/jack_meter.c +++ b/jack_meter.c @@ -3,23 +3,27 @@ jackmeter.c Simple console based Digital Peak Meter for JACK Copyright (C) 2005 Nicholas J. Humfrey - + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ + */ +//for sigalrm catching +#include + +#include #include #include #include @@ -31,53 +35,73 @@ #include #include "config.h" +extern int errno; +#define WAITING_SLEEP_TIME 999999 //999 ms steps +#define MAX_CHANNELS 16 + +unsigned int sleepTimeUs = 0; +unsigned int slept = 0; +volatile unsigned char time_to_print=0; +int verbosity = 1; +//printed info rows before drawing first scale +unsigned int printed_info_rows = 0; + +//default 1 channel +unsigned int channels = 1; float bias = 1.0f; -float peak = 0.0f; +float peak[MAX_CHANNELS];// = 0.0f; -int dpeak = 0; -int dtime = 0; -int decay_len; +int dpeak[MAX_CHANNELS]; +int dtime[MAX_CHANNELS]; +long int decay_len; +int rate = 8; +int userRate = 8; char *server_name = NULL; -jack_port_t *input_port = NULL; +jack_port_t *input_port[MAX_CHANNELS]; jack_client_t *client = NULL; jack_options_t options = JackNoStartServer; /* Read and reset the recent peak sample */ -static float read_peak() +static float read_peak(unsigned int inPortNumber) { - float tmp = peak; - peak = 0.0f; - + if (inPortNumber>=MAX_CHANNELS) return 0; + float tmp = peak[inPortNumber]; + peak[inPortNumber] = 0.0f; return tmp; } /* Callback called by JACK when audio is available. - Stores value of peak sample */ + Stores value of peak sample + Common callback for all the ports + */ static int process_peak(jack_nframes_t nframes, void *arg) { jack_default_audio_sample_t *in; unsigned int i; - - /* just incase the port isn't registered yet */ - if (input_port == NULL) { - return 0; - } - - /* get the audio samples, and find the peak sample */ - in = (jack_default_audio_sample_t *) jack_port_get_buffer(input_port, nframes); - for (i = 0; i < nframes; i++) { - const float s = fabs(in[i]); - if (s > peak) { - peak = s; + unsigned int inPortNumber = 0; + + // check all ports, but skip those with NULL pointer + for (;inPortNumber peak[inPortNumber]) { + peak[inPortNumber] = s; + } } } - return 0; } @@ -85,10 +109,10 @@ static int process_peak(jack_nframes_t nframes, void *arg) /* db: the signal stength in db width: the size of the meter -*/ + */ static int iec_scale(float db, int size) { float def = 0.0f; /* Meter deflection %age */ - + if (db < -70.0f) { def = 0.0f; } else if (db < -60.0f) { @@ -106,7 +130,7 @@ static int iec_scale(float db, int size) { } else { def = 100.0f; } - + return (int)( (def / 100.0f) * ((float) size) ); } @@ -117,14 +141,19 @@ static void cleanup() const char **all_ports; unsigned int i; - fprintf(stderr,"cleanup()\n"); - - if (input_port != NULL ) { + if (verbosity>0){ + fprintf(stderr,"cleanup()\n"); + printed_info_rows++; + } + int inPortNumber=0; + for (;inPortNumber=channels) inPortNumber=channels-1; jack_port_t *port; // Get the port we are connecting to @@ -147,73 +177,95 @@ static void connect_port(jack_client_t *client, char *port_name) } // Connect the port to our input port - fprintf(stderr,"Connecting '%s' to '%s'...\n", jack_port_name(port), jack_port_name(input_port)); - if (jack_connect(client, jack_port_name(port), jack_port_name(input_port))) { - fprintf(stderr, "Cannot connect port '%s' to '%s'\n", jack_port_name(port), jack_port_name(input_port)); + if (verbosity>0){ + fprintf(stderr,"Connecting '%s' to '%s'...\n", jack_port_name(port), jack_port_name(input_port[inPortNumber])); + printed_info_rows++; + } + if (jack_connect(client, jack_port_name(port), jack_port_name(input_port[inPortNumber]))) { + if (verbosity>0){ + fprintf(stderr, "Cannot connect port '%s' to '%s'\n", jack_port_name(port), jack_port_name(input_port[inPortNumber])); + } exit(1); } } - -/* Sleep for a fraction of a second */ -static int fsleep( float secs ) -{ - -//#ifdef HAVE_USLEEP - return usleep( secs * 1000000 ); -//#endif -} - - /* Display how to use this program */ static int usage( const char * progname ) { fprintf(stderr, "jackmeter version %s\n\n", VERSION); - fprintf(stderr, "Usage %s [-f freqency] [-r ref-level] [-w width] [-s servername] [-n] [, ...]\n\n", progname); + fprintf(stderr, "Usage %s [-f freqency] [-r ref-level] [-w width] [-s servername] [-n] [-p ports] [-v verbositylevel] [, ...]\n\n", progname); fprintf(stderr, "where -f is how often to update the meter per second [8]\n"); fprintf(stderr, " -r is the reference signal level for 0dB on the meter\n"); fprintf(stderr, " -w is how wide to make the meter [79]\n"); fprintf(stderr, " -s is the [optional] name given the jack server when it was started\n"); fprintf(stderr, " -n changes mode to output meter level as number in decibels\n"); - fprintf(stderr, " the port(s) to monitor (multiple ports are mixed)\n"); + fprintf(stderr, " -p amount of ports [1], max %u\n", MAX_CHANNELS); + fprintf(stderr, " -v sets level of verbosity [1], max 10\n"); + fprintf(stderr, " the port(s) to monitor (rest ports are mixed to last meter port)\n"); exit(1); } +void display_connected_ports( unsigned int inPortNumber ) +{ + const char **all_ports; + unsigned int j; + + if (input_port[inPortNumber] != NULL ) { + + all_ports = jack_port_get_all_connections(client, input_port[inPortNumber]); + printf("\33[2K"); + for (j=0; all_ports && all_ports[j]; j++) { + fprintf(stderr, "%s, ",all_ports[j]); + } + + if (j==0){ + fprintf(stderr, "not connected"); + } + + fprintf(stderr, "\n"); + printed_info_rows++; + + } else { + if (verbosity>0){ + fprintf(stderr, "error\n"); + printed_info_rows++; + } + } +} + void display_scale( int width ) { int i=0; const int marks[11] = { 0, -5, -10, -15, -20, -25, -30, -35, -40, -50, -60 }; char *scale = malloc( width+1 ); char *line = malloc( width+1 ); - - + // Initialise the scale for(i=0; iwidth) spos=width-slen; memcpy( scale+spos, mark, slen ); - + // Position little marker line[pos] = '|'; } - + // Print it to screen printf("%s\n", scale); printf("%s\n", line); @@ -222,31 +274,52 @@ void display_scale( int width ) } -void display_meter( int db, int width ) +void display_meter( int db, int width, unsigned int inPortNumber ) { + if (inPortNumber>=MAX_CHANNELS) return; int size = iec_scale( db, width ); int i; - - if (size > dpeak) { - dpeak = size; - dtime = 0; - } else if (dtime++ > decay_len) { - dpeak = size; + + if (size > dpeak[inPortNumber]) { + dpeak[inPortNumber] = size; + dtime[inPortNumber] = 0; + } else if (dtime[inPortNumber]++ > decay_len) { + dpeak[inPortNumber] = size; } - + printf("\r"); - + for(i=0; i0){ fprintf(stderr,"Reference level: %.1fdB\n", ref_lev); - bias = powf(10.0f, ref_lev * -0.05f); - break; - case 'f': - rate = atoi(optarg); + printed_info_rows++; + } + bias = powf(10.0f, ref_lev * -0.05f); + break; + case 'f': + userRate = atoi(optarg); + rate = userRate; + if (verbosity>0){ fprintf(stderr,"Updates per second: %d\n", rate); - break; - case 'w': - console_width = atoi(optarg); + printed_info_rows++; + } + break; + case 'w': + console_width = atoi(optarg); + if (verbosity>0){ fprintf(stderr,"Console Width: %d\n", console_width); - break; - case 'n': - decibels_mode = 1; - break; - case 'h': - case 'v': - default: - /* Show usage/version information */ - usage( argv[0] ); - break; + printed_info_rows++; + } + break; + case 'n': + decibels_mode = 1; + break; + case 'p': + channels = atoi(optarg); + if (channels>MAX_CHANNELS) channels = MAX_CHANNELS; + break; + case 'v': + verbosity = atoi(optarg); + break; + case 'h': + default: + /* Show usage/version information */ + usage( argv[0] ); + break; } } + // set callback function for timer + signal( SIGALRM, time_handler ); + sleepTimeUs = 1000000.0f/rate; + + //usleep works with max 999999 us + if (sleepTimeUs>=1000000) sleepTimeUs = 999999; + ualarm( sleepTimeUs, sleepTimeUs ); - // Register with Jack + // Register client with Jack if ((client = jack_client_open("meter", options, &status, server_name)) == 0) { - fprintf(stderr, "Failed to start jack client: %d\n", status); + if (verbosity>0){ + fprintf(stderr, "Failed to start jack client: %d\n", status); + } exit(1); } - fprintf(stderr,"Registering as '%s'.\n", jack_get_client_name( client ) ); + if (verbosity>0){ + fprintf(stderr,"Registering as '%s'.\n", jack_get_client_name( client ) ); + printed_info_rows++; + } - // Create our input port - if (!(input_port = jack_port_register(client, "in", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0))) { - fprintf(stderr, "Cannot register input port 'meter'.\n"); - exit(1); + //register port(s) with jack + unsigned int i = 0; + char portname[7]; + for (;i0){ + fprintf(stderr, "Cannot register input port '%s'.\n", portname); + } + exit(1); + } } - + // Register the cleanup function to be called when program exits atexit( cleanup ); - // Register the peak signal callback + // Register the peak signal callback, common for all ports on this client jack_set_process_callback(client, process_peak, 0); - if (jack_activate(client)) { fprintf(stderr, "Cannot activate client.\n"); exit(1); } - - // Connect our port to specified port(s) + //on which port to connect, overflow will be handled inside connect_port function + unsigned int portTo=0; + // Connect our port(s) to specified port(s) if (argc > optind) { while (argc > optind) { - connect_port( client, argv[ optind ] ); + connect_port( client, argv[ optind ], portTo ); optind++; + portTo++; } } else { - fprintf(stderr,"Meter is not connected to a port.\n"); + if (verbosity>0){ + fprintf(stderr,"Meter is not connected to a port.\n"); + printed_info_rows++; + } } - // Calculate the decay length (should be 1600ms) - decay_len = (int)(1.6f / (1.0f/rate)); - + decay_len = (long int)(1.6f / (1.0f/rate)); - // Display the scale - if (decibels_mode==0) { - display_scale( console_width ); - } + //where to print first meter with scales. Row from up to down. + unsigned int startRow = 1+printed_info_rows; + //connections rows + unsigned int connectionRows = 1; + //rows reserved for meter bar + unsigned int meterRows = 1; + //rows reserved for scale bar + unsigned int scaleRows = 2; + //rows reserved for scale bar + + //just sum + unsigned int totalRows = scaleRows+meterRows+connectionRows; while (running) { - float db = 20.0f * log10f(read_peak() * bias); - - if (decibels_mode==1) { - printf("%1.1f\n", db); - } else { - display_meter( db, console_width ); + slept = 0; + unsigned int inPortNumber=0; + for (;inPortNumber1){ + fprintf(stderr, "SleepTime %u ms, rate = %d \n",sleepTimeUs/1000, rate); + } + } return 0; }