Removed symlinks
[jackmeter.git] / jack_meter.c
blob6a67748236575800c2f018b96742712a701fbff8
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;
41 char *server_name = NULL;
42 jack_port_t *input_port = NULL;
43 jack_client_t *client = NULL;
44 jack_options_t options = JackNoStartServer;
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] [-s servername] [-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, " -s is the [optional] name given the jack server when it was started\n");
177 fprintf(stderr, " -n changes mode to output meter level as number in decibels\n");
178 fprintf(stderr, " <port> the port(s) to monitor (multiple ports are mixed)\n");
179 exit(1);
183 void display_scale( int width )
185 int i=0;
186 const int marks[11] = { 0, -5, -10, -15, -20, -25, -30, -35, -40, -50, -60 };
187 char *scale = malloc( width+1 );
188 char *line = malloc( width+1 );
191 // Initialise the scale
192 for(i=0; i<width; i++) { scale[i] = ' '; line[i]='_'; }
193 scale[width] = 0;
194 line[width] = 0;
197 // 'draw' on each of the db marks
198 for(i=0; i < 11; i++) {
199 char mark[5];
200 int pos = iec_scale( marks[i], width )-1;
201 int spos, slen;
203 // Create string of the db value
204 snprintf(mark, 4, "%d", marks[i]);
206 // Position the label string
207 slen = strlen(mark);
208 spos = pos-(slen/2);
209 if (spos<0) spos=0;
210 if (spos+strlen(mark)>width) spos=width-slen;
211 memcpy( scale+spos, mark, slen );
213 // Position little marker
214 line[pos] = '|';
217 // Print it to screen
218 printf("%s\n", scale);
219 printf("%s\n", line);
220 free(scale);
221 free(line);
225 void display_meter( int db, int width )
227 int size = iec_scale( db, width );
228 int i;
230 if (size > dpeak) {
231 dpeak = size;
232 dtime = 0;
233 } else if (dtime++ > decay_len) {
234 dpeak = size;
237 printf("\r");
239 for(i=0; i<size-1; i++) { printf("#"); }
241 if (dpeak==size) {
242 printf("I");
243 } else {
244 printf("#");
245 for(i=0; i<dpeak-size-1; i++) { printf(" "); }
246 printf("I");
249 for(i=0; i<width-dpeak; i++) { printf(" "); }
253 int main(int argc, char *argv[])
255 int console_width = 79;
256 jack_status_t status;
257 int running = 1;
258 float ref_lev;
259 int decibels_mode = 0;
260 int rate = 8;
261 int opt;
263 // Make STDOUT unbuffered
264 setbuf(stdout, NULL);
266 while ((opt = getopt(argc, argv, "s:w:f:r:nhv")) != -1) {
267 switch (opt) {
268 case 's':
269 server_name = (char *) malloc (sizeof (char) * strlen(optarg));
270 strcpy (server_name, optarg);
271 options |= JackServerName;
272 break;
273 case 'r':
274 ref_lev = atof(optarg);
275 fprintf(stderr,"Reference level: %.1fdB\n", ref_lev);
276 bias = powf(10.0f, ref_lev * -0.05f);
277 break;
278 case 'f':
279 rate = atoi(optarg);
280 fprintf(stderr,"Updates per second: %d\n", rate);
281 break;
282 case 'w':
283 console_width = atoi(optarg);
284 fprintf(stderr,"Console Width: %d\n", console_width);
285 break;
286 case 'n':
287 decibels_mode = 1;
288 break;
289 case 'h':
290 case 'v':
291 default:
292 /* Show usage/version information */
293 usage( argv[0] );
294 break;
300 // Register with Jack
301 if ((client = jack_client_open("meter", options, &status, server_name)) == 0) {
302 fprintf(stderr, "Failed to start jack client: %d\n", status);
303 exit(1);
305 fprintf(stderr,"Registering as '%s'.\n", jack_get_client_name( client ) );
307 // Create our input port
308 if (!(input_port = jack_port_register(client, "in", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0))) {
309 fprintf(stderr, "Cannot register input port 'meter'.\n");
310 exit(1);
313 // Register the cleanup function to be called when program exits
314 atexit( cleanup );
316 // Register the peak signal callback
317 jack_set_process_callback(client, process_peak, 0);
320 if (jack_activate(client)) {
321 fprintf(stderr, "Cannot activate client.\n");
322 exit(1);
326 // Connect our port to specified port(s)
327 if (argc > optind) {
328 while (argc > optind) {
329 connect_port( client, argv[ optind ] );
330 optind++;
332 } else {
333 fprintf(stderr,"Meter is not connected to a port.\n");
336 // Calculate the decay length (should be 1600ms)
337 decay_len = (int)(1.6f / (1.0f/rate));
340 // Display the scale
341 if (decibels_mode==0) {
342 display_scale( console_width );
345 while (running) {
346 float db = 20.0f * log10f(read_peak() * bias);
348 if (decibels_mode==1) {
349 printf("%1.1f\n", db);
350 } else {
351 display_meter( db, console_width );
354 fsleep( 1.0f/rate );
357 return 0;