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.
27 #include <sys/types.h>
30 #include <jack/jack.h>
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()
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
;
65 /* just incase the port isn't registered yet */
66 if (input_port
== NULL
) {
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
]);
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 */
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
;
110 return (int)( (def
/ 100.0f
) * ((float) size
) );
114 /* Close down JACK when exiting */
115 static void cleanup()
117 const char **all_ports
;
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
)
142 // Get the port we are connecting to
143 port
= jack_port_by_name(client
, port_name
);
145 fprintf(stderr
, "Can't find port '%s'\n", port_name
);
149 // Connect the port to our input port
150 printf("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
));
158 /* Sleep for a fraction of a second */
159 static int fsleep( float secs
)
163 return usleep( secs
* 1000000 );
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] [<port>]\n\n", progname
);
173 fprintf(stderr
, "where freqency is how often to update the meter per second [8]\n");
174 fprintf(stderr
, " ref-level is the reference signal level for 0dB on the meter\n");
175 fprintf(stderr
, " width is how wide to make the meter [79]\n");
176 fprintf(stderr
, " port is the JACK port to monitor\n");
181 void display_scale( int width
)
184 const int marks
[11] = { 0, -5, -10, -15, -20, -25, -30, -35, -40, -50, -60 };
185 char *scale
= malloc( width
+1 );
186 char *line
= malloc( width
+1 );
189 // Initialise the scale
190 for(i
=0; i
<width
; i
++) { scale
[i
] = ' '; line
[i
]='_'; }
195 // 'draw' on each of the db marks
196 for(i
=0; i
< 11; i
++) {
198 int pos
= iec_scale( marks
[i
], width
)-1;
201 // Create string of the db value
202 snprintf(mark
, 4, "%d", marks
[i
]);
204 // Position the label string
208 if (spos
+strlen(mark
)>width
) spos
=width
-slen
;
209 memcpy( scale
+spos
, mark
, slen
);
211 // Position little marker
215 // Print it to screen
216 printf("%s\n", scale
);
217 printf("%s\n", line
);
223 void display_meter( float peak
, int width
)
225 float db
= 20.0f
* log10f(peak
* bias
);
226 int size
= iec_scale( db
, width
);
232 } else if (dtime
++ > decay_len
) {
238 for(i
=0; i
<size
-1; i
++) { printf("#"); }
244 for(i
=0; i
<dpeak
-size
-1; i
++) { printf(" "); }
248 for(i
=0; i
<width
-dpeak
; i
++) { printf(" "); }
252 int main(int argc
, char *argv
[])
254 int console_width
= 79;
255 char client_name
[255];
261 // Make STDOUT unbuffered
262 setbuf(stdout
, NULL
);
264 while ((opt
= getopt(argc
, argv
, "w:f:r:h")) != -1) {
267 ref_lev
= atof(optarg
);
268 printf("Reference level: %.1fdB\n", ref_lev
);
269 bias
= powf(10.0f
, ref_lev
* -0.05f
);
273 printf("Updates per second: %d\n", rate
);
276 console_width
= atoi(optarg
);
277 printf("Console Width: %d\n", console_width
);
280 /* Force help to be shown */
291 // Register with Jack
292 snprintf(client_name
, 255, "meter-%d", getpid());
293 if ((client
= jack_client_new(client_name
)) == 0) {
294 fprintf(stderr
, "JACK server not running?\n");
297 printf("Registering as %s.\n", client_name
);
299 // Create our input port
300 if (!(input_port
= jack_port_register(client
, "meter", JACK_DEFAULT_AUDIO_TYPE
, JackPortIsInput
, 0))) {
301 fprintf(stderr
, "Cannot register input port 'meter'.\n");
305 // Register the cleanup function to be called when program exits
308 // Register the peak signal callback
309 jack_set_process_callback(client
, process_peak
, 0);
312 if (jack_activate(client
)) {
313 fprintf(stderr
, "Cannot activate client.\n");
318 // Connect our port to specified port
320 connect_port( client
, argv
[ optind
] );
322 printf("Meter is not connected to a port.\n");
325 // Calculate the decay length (should be 1600ms)
326 decay_len
= (int)(1.6f
/ (1.0f
/rate
));
330 display_scale( console_width
);
333 display_meter( read_peak(), console_width
);