From c4dca01342677116bbdc3713cb2c16ceadadbbcf Mon Sep 17 00:00:00 2001 From: ltmakela Date: Thu, 11 Feb 2016 11:06:15 +0200 Subject: [PATCH 1/4] Update jack_meter.c Made multi port implementation. Changed delay based timing between draws to interval based. Some printing verbosity. First clear console, then starting to print and after init lines draw first scale with meter. --- jack_meter.c | 408 ++++++++++++++++++++++++++++++++++----------------- 1 file changed, 277 insertions(+), 131 deletions(-) diff --git a/jack_meter.c b/jack_meter.c index 6a67748..8f9dd91 100644 --- a/jack_meter.c +++ b/jack_meter.c @@ -3,22 +3,25 @@ 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 @@ -31,53 +34,72 @@ #include #include "config.h" +#define WAITING_SLEEP_TIME 1000 //1 ms steps +#define MAX_CHANNELS 16 + +unsigned long sleepTimeUs = 0; +unsigned long 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]; +unsigned 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 +107,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 +128,7 @@ static int iec_scale(float db, int size) { } else { def = 100.0f; } - + return (int)( (def / 100.0f) * ((float) size) ); } @@ -117,14 +139,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 +175,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] [-c channels] [-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 +272,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)); - - // 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 (;inPortNumber=part) slept+=(WAITING_SLEEP_TIME-part); + if (part!=0) break; + } + time_to_print=0; + + fprintf(stderr, "\n"); + printed_info_rows++; + if (verbosity>1){ + fprintf(stderr, "SleepTime %lu ms, rate = %d \n",sleepTimeUs/1000, rate); + fprintf(stderr, "Slept after drawing: %lu ms \n",slept/1000); + fprintf(stderr, "Drawing and others took: %lu ms \n", ((sleepTimeUs)-(slept))/1000); + printed_info_rows+=2; } - - fsleep( 1.0f/rate ); } - return 0; } From a70cb83336d1f73e075f73b4d3e1363b8aea8862 Mon Sep 17 00:00:00 2001 From: ltmakela Date: Fri, 12 Feb 2016 10:49:23 +0200 Subject: [PATCH 2/4] Fix for sleep time Fixed sleep time to maximum. Sleep will be interrupted by ualarm. Max sleep time causes cpu load minimizing. Usleep doesn't return remaining sleep time as sleep() does. --- jack_meter.c | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/jack_meter.c b/jack_meter.c index 8f9dd91..4dc8c34 100644 --- a/jack_meter.c +++ b/jack_meter.c @@ -23,6 +23,7 @@ //for sigalrm catching #include +#include #include #include #include @@ -34,11 +35,12 @@ #include #include "config.h" -#define WAITING_SLEEP_TIME 1000 //1 ms steps +extern int errno; +#define WAITING_SLEEP_TIME 999999 //999 ms steps #define MAX_CHANNELS 16 -unsigned long sleepTimeUs = 0; -unsigned long slept = 0; +unsigned int sleepTimeUs = 0; +unsigned int slept = 0; volatile unsigned char time_to_print=0; int verbosity = 1; @@ -52,7 +54,7 @@ float peak[MAX_CHANNELS];// = 0.0f; int dpeak[MAX_CHANNELS]; int dtime[MAX_CHANNELS]; -unsigned long int decay_len; +long int decay_len; int rate = 8; int userRate = 8; char *server_name = NULL; @@ -309,7 +311,7 @@ void time_handler( int sig ){ slept-=sleepTimeUs;//WAITING_SLEEP_TIME; rate--; if (rate<=0) rate = 1; - decay_len = (unsigned long int)(1.6f / (1.0f/rate)); + decay_len = (long int)(1.6f / (1.0f/rate)); sleepTimeUs = 1000000.0f/rate; //renew ualarm with new sleepTime ualarm( sleepTimeUs, sleepTimeUs ); @@ -448,7 +450,7 @@ int main(int argc, char *argv[]) } } // Calculate the decay length (should be 1600ms) - decay_len = (int)(1.6f / (1.0f/rate)); + decay_len = (long int)(1.6f / (1.0f/rate)); //where to print first meter with scales. Row from up to down. unsigned int startRow = 1+printed_info_rows; @@ -485,19 +487,25 @@ int main(int argc, char *argv[]) * waiting here while it is time to print again */ while (time_to_print==0){ - unsigned int part = usleep(WAITING_SLEEP_TIME); - if (WAITING_SLEEP_TIME>=part) slept+=(WAITING_SLEEP_TIME-part); - if (part!=0) break; + if (usleep(WAITING_SLEEP_TIME)==-1){ + //catch reason to be awaken + int errsv = errno; + if (errsv==EINTR){ + //awaken by interval timer + break; + } else if (errsv==EINVAL) { + //unsupported sleep time + exit(1); + } + } } time_to_print=0; fprintf(stderr, "\n"); printed_info_rows++; + if (verbosity>1){ fprintf(stderr, "SleepTime %lu ms, rate = %d \n",sleepTimeUs/1000, rate); - fprintf(stderr, "Slept after drawing: %lu ms \n",slept/1000); - fprintf(stderr, "Drawing and others took: %lu ms \n", ((sleepTimeUs)-(slept))/1000); - printed_info_rows+=2; } } return 0; From dd98f4e4c6e029f4934637dcaf82837fe25f5099 Mon Sep 17 00:00:00 2001 From: ltmakela Date: Mon, 28 Mar 2016 16:33:26 +0300 Subject: [PATCH 3/4] Usage help line, repaired -p ports -p argument will be the amount of ports to be set up. --- jack_meter.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jack_meter.c b/jack_meter.c index 4dc8c34..265e7a5 100644 --- a/jack_meter.c +++ b/jack_meter.c @@ -193,7 +193,7 @@ static void connect_port(jack_client_t *client, char *port_name, unsigned int in 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] [-c channels] [-v verbositylevel] [, ...]\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"); From e09227733b48175fdc5d61a86089d3b0f0b4fd7f Mon Sep 17 00:00:00 2001 From: ltmakela Date: Fri, 13 May 2016 10:27:11 +0300 Subject: [PATCH 4/4] Fixed warning Fixed warning caused by wrong argument type: unsigned long vs. unsigned int --- jack_meter.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jack_meter.c b/jack_meter.c index 265e7a5..87a3b01 100644 --- a/jack_meter.c +++ b/jack_meter.c @@ -505,7 +505,7 @@ int main(int argc, char *argv[]) printed_info_rows++; if (verbosity>1){ - fprintf(stderr, "SleepTime %lu ms, rate = %d \n",sleepTimeUs/1000, rate); + fprintf(stderr, "SleepTime %u ms, rate = %d \n",sleepTimeUs/1000, rate); } } return 0;