Fix for building with newer versions of the GNU linker
[jackmeter.git] / jack_meter.c
blob23843e35c1b50c6e82f2e333a8f53e79cfb37aba
1 /*
3 jackmeter.c
4 Simple console based Digital Peak Meter for JACK
5 Copyright (C) 2005 Nicholas J. Humfrey
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License
9 as published by the Free Software Foundation; either version 2
10 of the License, or (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <math.h>
26 #include <string.h>
27 #include <sys/types.h>
28 #include <unistd.h>
30 #include <jack/jack.h>
31 #include <getopt.h>
32 #include "config.h"
35 float bias = 1.0f;
36 float peak = 0.0f;
38 int dpeak = 0;
39 int dtime = 0;
40 int decay_len;
42 jack_port_t *input_port = NULL;
43 jack_client_t *client = NULL;
47 /* Read and reset the recent peak sample */
48 static float read_peak()
50 float tmp = peak;
51 peak = 0.0f;
53 return tmp;
57 /* Callback called by JACK when audio is available.
58 Stores value of peak sample */
59 static int process_peak(jack_nframes_t nframes, void *arg)
61 jack_default_audio_sample_t *in;
62 unsigned int i;
65 /* just incase the port isn't registered yet */
66 if (input_port == NULL) {
67 return 0;
71 /* get the audio samples, and find the peak sample */
72 in = (jack_default_audio_sample_t *) jack_port_get_buffer(input_port, nframes);
73 for (i = 0; i < nframes; i++) {
74 const float s = fabs(in[i]);
75 if (s > peak) {
76 peak = s;
81 return 0;
86 db: the signal stength in db
87 width: the size of the meter
89 static int iec_scale(float db, int size) {
90 float def = 0.0f; /* Meter deflection %age */
92 if (db < -70.0f) {
93 def = 0.0f;
94 } else if (db < -60.0f) {
95 def = (db + 70.0f) * 0.25f;
96 } else if (db < -50.0f) {
97 def = (db + 60.0f) * 0.5f + 2.5f;
98 } else if (db < -40.0f) {
99 def = (db + 50.0f) * 0.75f + 7.5;
100 } else if (db < -30.0f) {
101 def = (db + 40.0f) * 1.5f + 15.0f;
102 } else if (db < -20.0f) {
103 def = (db + 30.0f) * 2.0f + 30.0f;
104 } else if (db < 0.0f) {
105 def = (db + 20.0f) * 2.5f + 50.0f;
106 } else {
107 def = 100.0f;
110 return (int)( (def / 100.0f) * ((float) size) );
114 /* Close down JACK when exiting */
115 static void cleanup()
117 const char **all_ports;
118 unsigned int i;
120 fprintf(stderr,"cleanup()\n");
122 if (input_port != NULL ) {
124 all_ports = jack_port_get_all_connections(client, input_port);
126 for (i=0; all_ports && all_ports[i]; i++) {
127 jack_disconnect(client, all_ports[i], jack_port_name(input_port));
131 /* Leave the jack graph */
132 jack_client_close(client);
137 /* Connect the chosen port to ours */
138 static void connect_port(jack_client_t *client, char *port_name)
140 jack_port_t *port;
142 // Get the port we are connecting to
143 port = jack_port_by_name(client, port_name);
144 if (port == NULL) {
145 fprintf(stderr, "Can't find port '%s'\n", port_name);
146 exit(1);
149 // Connect the port to our input port
150 fprintf(stderr,"Connecting '%s' to '%s'...\n", jack_port_name(port), jack_port_name(input_port));
151 if (jack_connect(client, jack_port_name(port), jack_port_name(input_port))) {
152 fprintf(stderr, "Cannot connect port '%s' to '%s'\n", jack_port_name(port), jack_port_name(input_port));
153 exit(1);
158 /* Sleep for a fraction of a second */
159 static int fsleep( float secs )
162 //#ifdef HAVE_USLEEP
163 return usleep( secs * 1000000 );
164 //#endif
168 /* Display how to use this program */
169 static int usage( const char * progname )
171 fprintf(stderr, "jackmeter version %s\n\n", VERSION);
172 fprintf(stderr, "Usage %s [-f freqency] [-r ref-level] [-w width] [-n] [<port>, ...]\n\n", progname);
173 fprintf(stderr, "where -f is how often to update the meter per second [8]\n");
174 fprintf(stderr, " -r is the reference signal level for 0dB on the meter\n");
175 fprintf(stderr, " -w is how wide to make the meter [79]\n");
176 fprintf(stderr, " -n changes mode to output meter level as number in decibels\n");
177 fprintf(stderr, " <port> the port(s) to monitor (multiple ports are mixed)\n");
178 exit(1);
182 void display_scale( int width )
184 int i=0;
185 const int marks[11] = { 0, -5, -10, -15, -20, -25, -30, -35, -40, -50, -60 };
186 char *scale = malloc( width+1 );
187 char *line = malloc( width+1 );
190 // Initialise the scale
191 for(i=0; i<width; i++) { scale[i] = ' '; line[i]='_'; }
192 scale[width] = 0;
193 line[width] = 0;
196 // 'draw' on each of the db marks
197 for(i=0; i < 11; i++) {
198 char mark[5];
199 int pos = iec_scale( marks[i], width )-1;
200 int spos, slen;
202 // Create string of the db value
203 snprintf(mark, 4, "%d", marks[i]);
205 // Position the label string
206 slen = strlen(mark);
207 spos = pos-(slen/2);
208 if (spos<0) spos=0;
209 if (spos+strlen(mark)>width) spos=width-slen;
210 memcpy( scale+spos, mark, slen );
212 // Position little marker
213 line[pos] = '|';
216 // Print it to screen
217 printf("%s\n", scale);
218 printf("%s\n", line);
219 free(scale);
220 free(line);
224 void display_meter( int db, int width )
226 int size = iec_scale( db, width );
227 int i;
229 if (size > dpeak) {
230 dpeak = size;
231 dtime = 0;
232 } else if (dtime++ > decay_len) {
233 dpeak = size;
236 printf("\r");
238 for(i=0; i<size-1; i++) { printf("#"); }
240 if (dpeak==size) {
241 printf("I");
242 } else {
243 printf("#");
244 for(i=0; i<dpeak-size-1; i++) { printf(" "); }
245 printf("I");
248 for(i=0; i<width-dpeak; i++) { printf(" "); }
252 int main(int argc, char *argv[])
254 int console_width = 79;
255 jack_status_t status;
256 int running = 1;
257 float ref_lev;
258 int decibels_mode = 0;
259 int rate = 8;
260 int opt;
262 // Make STDOUT unbuffered
263 setbuf(stdout, NULL);
265 while ((opt = getopt(argc, argv, "w:f:r:nhv")) != -1) {
266 switch (opt) {
267 case 'r':
268 ref_lev = atof(optarg);
269 fprintf(stderr,"Reference level: %.1fdB\n", ref_lev);
270 bias = powf(10.0f, ref_lev * -0.05f);
271 break;
272 case 'f':
273 rate = atoi(optarg);
274 fprintf(stderr,"Updates per second: %d\n", rate);
275 break;
276 case 'w':
277 console_width = atoi(optarg);
278 fprintf(stderr,"Console Width: %d\n", console_width);
279 break;
280 case 'n':
281 decibels_mode = 1;
282 break;
283 case 'h':
284 case 'v':
285 default:
286 /* Show usage/version information */
287 usage( argv[0] );
288 break;
294 // Register with Jack
295 if ((client = jack_client_open("meter", JackNullOption, &status)) == 0) {
296 fprintf(stderr, "Failed to start jack client: %d\n", status);
297 exit(1);
299 fprintf(stderr,"Registering as '%s'.\n", jack_get_client_name( client ) );
301 // Create our input port
302 if (!(input_port = jack_port_register(client, "in", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0))) {
303 fprintf(stderr, "Cannot register input port 'meter'.\n");
304 exit(1);
307 // Register the cleanup function to be called when program exits
308 atexit( cleanup );
310 // Register the peak signal callback
311 jack_set_process_callback(client, process_peak, 0);
314 if (jack_activate(client)) {
315 fprintf(stderr, "Cannot activate client.\n");
316 exit(1);
320 // Connect our port to specified port(s)
321 if (argc > optind) {
322 while (argc > optind) {
323 connect_port( client, argv[ optind ] );
324 optind++;
326 } else {
327 fprintf(stderr,"Meter is not connected to a port.\n");
330 // Calculate the decay length (should be 1600ms)
331 decay_len = (int)(1.6f / (1.0f/rate));
334 // Display the scale
335 if (decibels_mode==0) {
336 display_scale( console_width );
339 while (running) {
340 float db = 20.0f * log10f(read_peak() * bias);
342 if (decibels_mode==1) {
343 printf("%1.1f\n", db);
344 } else {
345 display_meter( db, console_width );
348 fsleep( 1.0f/rate );
351 return 0;