594 lines
17 KiB
C++
594 lines
17 KiB
C++
// ------------------------------------------------------------------------
|
|
// ecasignalview.cpp: A simple command-line tools for monitoring
|
|
// signal amplitude.
|
|
// Copyright (C) 1999-2005,2007,2008 Kai Vehmanen
|
|
// Copyright (C) 2005 Jeffrey Cunningham
|
|
//
|
|
// 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
|
|
// ------------------------------------------------------------------------
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
|
|
#include <cstdlib>
|
|
#include <iostream>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include <cassert>
|
|
#include <cmath>
|
|
#include <cstdio>
|
|
|
|
#include <signal.h>
|
|
#include <unistd.h>
|
|
|
|
#include <sys/time.h> /* POSIX: select() */
|
|
#include <sys/select.h> /* POSIX: timeval struct */
|
|
|
|
#include <kvutils/kvu_com_line.h>
|
|
#include <kvutils/kvu_utils.h>
|
|
#include <kvutils/kvu_numtostr.h>
|
|
|
|
#include <eca-control-interface.h>
|
|
|
|
#include "ecicpp_helpers.h"
|
|
|
|
#ifdef HAVE_TERMIOS_H
|
|
/* see: http://www.opengroup.org/onlinepubs/007908799/xsh/termios.h.html */
|
|
#include <termios.h>
|
|
#endif
|
|
|
|
#if defined(ECA_USE_NCURSES_H) || defined(ECA_USE_NCURSES_NCURSES_H) || defined(ECA_USE_CURSES_H)
|
|
#define ECASV_USE_CURSES 1
|
|
|
|
#ifdef ECA_USE_NCURSES_H
|
|
#include <ncurses.h>
|
|
#include <term.h> /* for setupterm() */
|
|
#elif ECA_USE_NCURSES_NCURSES_H
|
|
#include <ncurses/ncurses.h>
|
|
#include <ncurses/term.h> /* for setupterm() */
|
|
#else
|
|
#include <curses.h>
|
|
#include <term.h> /* for setupterm() */
|
|
#endif
|
|
|
|
#endif /* ECA_*CURSES_H */
|
|
|
|
#include <cstring>
|
|
|
|
/**
|
|
* Import namespaces
|
|
*/
|
|
|
|
using namespace std;
|
|
|
|
/**
|
|
* Type definitions
|
|
*/
|
|
|
|
struct ecasv_channel_stats {
|
|
double last_peak;
|
|
double drawn_peak;
|
|
double max_peak;
|
|
long int clipped_samples;
|
|
vector<double> avg_peak; // jkc: addition
|
|
int avg_peak_ptr; // jkc: addition
|
|
double avg_peak_val; // jkc: addition
|
|
};
|
|
|
|
/**
|
|
* Function declarations
|
|
*/
|
|
|
|
int main(int argc, char *argv[]);
|
|
void ecasv_parse_command_line(ECA_CONTROL_INTERFACE* cop, int argc, char *argv[]);
|
|
void ecasv_fill_defaults(void);
|
|
std::string ecasv_cop_to_string(ECA_CONTROL_INTERFACE* cop);
|
|
void ecasv_output_init(void);
|
|
void ecasv_output_cleanup(void);
|
|
int ecasv_print_vu_meters(ECA_CONTROL_INTERFACE* eci,
|
|
std::vector<struct ecasv_channel_stats>* chstats);
|
|
void ecasv_update_chstats(std::vector<struct ecasv_channel_stats>* chstats,
|
|
int ch, double value);
|
|
void ecasv_create_bar(double value, int barlen, unsigned char* barbuf);
|
|
void ecasv_print_usage(void);
|
|
void ecasv_signal_handler(int signum);
|
|
void reset_stats_fcn(vector<struct ecasv_channel_stats>* chstats); // jkc: addition
|
|
float dB(float v) { return 10.0*log10(v*v); } // jkc: addition
|
|
void ecasv_set_buffered(void);
|
|
void ecasv_set_unbuffered(void);
|
|
int ecasv_kbhit();
|
|
|
|
/**
|
|
* Static global variables
|
|
*/
|
|
|
|
static const string ecatools_signalview_version = "20051112-10";
|
|
static bool ecasv_log_display_mode = false; // jkc: addition
|
|
static const double ecasv_clipped_threshold_const = 1.0f - 1.0f / 16384.0f;
|
|
static const int ecasv_bar_length_const = 32;
|
|
static const int ecasv_header_height_const = 9;
|
|
static const long int ecasv_rate_default_const = 50;
|
|
static const long int ecasv_buffersize_default_const = 128;
|
|
|
|
static unsigned char ecasv_bar_buffer[ecasv_bar_length_const + 1] = { 0 };
|
|
static bool ecasv_enable_debug, ecasv_enable_cumulative_mode;
|
|
static long int ecasv_buffersize, ecasv_rate_msec;
|
|
static string ecasv_input, ecasv_output, ecasv_format_string;
|
|
static int ecasv_chcount = 0;
|
|
|
|
static ECA_CONTROL_INTERFACE* ecasv_eci_repp = 0;
|
|
|
|
static sig_atomic_t done = 0;
|
|
static sig_atomic_t reset_stats = 0;
|
|
static int avg_peak_buffer_sz=100; // jkc: addition
|
|
|
|
#ifdef HAVE_TERMIOS_H
|
|
struct termios old_term, new_term;
|
|
#endif
|
|
|
|
/**
|
|
* Function definitions
|
|
*/
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
int res;
|
|
struct sigaction es_handler;
|
|
es_handler.sa_handler = ecasv_signal_handler;
|
|
sigemptyset(&es_handler.sa_mask);
|
|
es_handler.sa_flags = 0;
|
|
|
|
sigaction(SIGTERM, &es_handler, 0);
|
|
sigaction(SIGINT, &es_handler, 0);
|
|
sigaction(SIGQUIT, &es_handler, 0);
|
|
sigaction(SIGABRT, &es_handler, 0);
|
|
sigaction(SIGHUP, &es_handler, 0);
|
|
|
|
struct sigaction ign_handler;
|
|
ign_handler.sa_handler = SIG_IGN;
|
|
sigemptyset(&ign_handler.sa_mask);
|
|
ign_handler.sa_flags = 0;
|
|
|
|
/* ignore the following signals */
|
|
sigaction(SIGPIPE, &ign_handler, 0);
|
|
sigaction(SIGFPE, &ign_handler, 0);
|
|
|
|
ECA_CONTROL_INTERFACE eci;
|
|
|
|
eci.command("cs-add default");
|
|
eci.command("c-add default");
|
|
|
|
/* set engine buffersize */
|
|
eci.command("cs-set-param -b:" + kvu_numtostr(ecasv_buffersize));
|
|
/* in case JACK is used, do not send nor receive transport events */
|
|
eci.command("cs-set-param -G:jack,ecasignalview,notransport");
|
|
|
|
/* note: might change the cs options (-G, -z, etc) */
|
|
ecasv_parse_command_line(&eci,argc,argv);
|
|
|
|
if (ecasv_format_string.size() > 0) {
|
|
eci.command("cs-set-audio-format " + ecasv_format_string);
|
|
}
|
|
|
|
string format;
|
|
if (ecicpp_add_input(&eci, ecasv_input, &format) < 0) return -1;
|
|
|
|
cout << "Using audio format -f:" << format << "\n";
|
|
|
|
ecasv_chcount = ecicpp_format_channels(format);
|
|
cout << "Setting up " << ecasv_chcount << " separate channels for analysis." << endl;
|
|
|
|
if (ecicpp_add_output(&eci, ecasv_output, format) < 0) return -1;
|
|
|
|
ecasv_eci_repp = &eci;
|
|
|
|
vector<struct ecasv_channel_stats> chstats;
|
|
|
|
eci.command("cop-add -evp");
|
|
eci.command("cop-add -ev");
|
|
if (ecasv_enable_cumulative_mode == true) {
|
|
eci.command("cop-set 2,1,1");
|
|
}
|
|
|
|
eci.command("cop-select 1");
|
|
|
|
if (ecicpp_connect_chainsetup(&eci, "default") < 0) {
|
|
return -1;
|
|
}
|
|
|
|
int secs = 0, msecs = ecasv_rate_msec;
|
|
while(msecs > 999) {
|
|
++secs;
|
|
msecs -= 1000;
|
|
}
|
|
|
|
ecasv_output_init();
|
|
|
|
eci.command("start");
|
|
|
|
int chr=0; // jkc: addition
|
|
int rv=0; // jkc: addition
|
|
while(! done ) {
|
|
kvu_sleep(secs, msecs * 1000000);
|
|
res = ecasv_print_vu_meters(&eci, &chstats);
|
|
if (res < 0)
|
|
break;
|
|
|
|
#if defined(ECASV_USE_CURSES)
|
|
// jkc: addition until noted
|
|
if (ecasv_kbhit()) {
|
|
/* note: getch() is a curses.h function */
|
|
switch (chr=getch()) {
|
|
case 'q':
|
|
case 27: /* Esc */
|
|
case 'Q':
|
|
done=true;
|
|
break;
|
|
case ' ':
|
|
reset_stats_fcn(&chstats);
|
|
break;
|
|
}
|
|
}
|
|
// jkc: end of addition
|
|
#endif
|
|
}
|
|
|
|
ecasv_output_cleanup();
|
|
#ifdef ECASV_USE_CURSES
|
|
endwin();
|
|
#endif
|
|
|
|
return rv;
|
|
}
|
|
|
|
void ecasv_parse_command_line(ECA_CONTROL_INTERFACE *eci, int argc, char *argv[])
|
|
{
|
|
COMMAND_LINE cline = COMMAND_LINE (argc, argv);
|
|
if (cline.size() == 0 ||
|
|
cline.has("--version") ||
|
|
cline.has("--help") ||
|
|
cline.has("-h")) {
|
|
ecasv_print_usage();
|
|
exit(1);
|
|
}
|
|
|
|
ecasv_enable_debug = false;
|
|
ecasv_enable_cumulative_mode = false;
|
|
ecasv_rate_msec = 0;
|
|
ecasv_buffersize = 0;
|
|
|
|
cline.begin();
|
|
cline.next(); // 1st argument
|
|
while (cline.end() != true) {
|
|
string arg = cline.current();
|
|
if (arg.size() > 0) {
|
|
if (arg[0] != '-') {
|
|
if (ecasv_input == "")
|
|
ecasv_input = arg;
|
|
else
|
|
if (ecasv_output == "")
|
|
ecasv_output = arg;
|
|
}
|
|
else {
|
|
string prefix = kvu_get_argument_prefix(arg);
|
|
if (prefix == "b")
|
|
ecasv_buffersize = atol(kvu_get_argument_number(1, arg).c_str());
|
|
if (prefix == "c") ecasv_enable_cumulative_mode = true;
|
|
if (prefix == "d") ecasv_enable_debug = true;
|
|
if (prefix == "f")
|
|
ecasv_format_string = string(arg.begin() + 3, arg.end());
|
|
if (prefix == "I") ecasv_log_display_mode = false; // jkc: addition
|
|
if (prefix == "L") ecasv_log_display_mode = true; // jkc: addition
|
|
if (prefix == "r")
|
|
ecasv_rate_msec = atol(kvu_get_argument_number(1, arg).c_str());
|
|
if (prefix == "G" ||
|
|
prefix == "B" ||
|
|
(prefix.size() > 0 && prefix[0] == 'M') ||
|
|
prefix == "r" ||
|
|
prefix == "z") {
|
|
eci->command("cs-option " + arg);
|
|
}
|
|
}
|
|
}
|
|
cline.next();
|
|
}
|
|
|
|
ecasv_fill_defaults();
|
|
}
|
|
|
|
void ecasv_fill_defaults(void)
|
|
{
|
|
// ECA_RESOURCES ecarc;
|
|
|
|
if (ecasv_input.size() == 0) ecasv_input = "/dev/dsp";
|
|
if (ecasv_output.size() == 0) ecasv_output = "null";
|
|
if (ecasv_buffersize == 0) ecasv_buffersize = ecasv_buffersize_default_const;
|
|
if (ecasv_rate_msec == 0) ecasv_rate_msec = ecasv_rate_default_const;
|
|
if (ecasv_format_string.size() == 0) ecasv_format_string = "s16_le,2,44100,i";
|
|
|
|
// ecarc.resource("default-audio-format");
|
|
}
|
|
|
|
string ecasv_cop_to_string(ECA_CONTROL_INTERFACE* eci)
|
|
{
|
|
eci->command("cop-status");
|
|
return(eci->last_string());
|
|
}
|
|
|
|
void ecasv_output_init(void)
|
|
{
|
|
#ifdef ECASV_USE_CURSES
|
|
initscr();
|
|
erase();
|
|
int r=0; // jkc: added r for row indexing here and below
|
|
mvprintw(r++, 0, "ecasignalview v%s (%s) -- (C) K.Vehmanen, J.Cunningham", ecatools_signalview_version.c_str(), VERSION);
|
|
//mvprintw(r++, 0, "* (C) 1999-2005 Kai Vehmanen, Jeff Cunningham *\n");
|
|
//mvprintw(r++, 0, "******************************************************\n\n");
|
|
|
|
++r;
|
|
mvprintw(r++, 2, "Input/output: \"%s\" => \"%s\"",
|
|
ecasv_input.c_str(),ecasv_output.c_str());
|
|
double avg_length = (double)ecasv_rate_msec * avg_peak_buffer_sz;
|
|
mvprintw(r++, 2,
|
|
"Settings: %s refresh=%ldms bsize=%ld avg-length=%.0fms",
|
|
ecasv_format_string.c_str(), ecasv_rate_msec, ecasv_buffersize, avg_length);
|
|
/* mvprintw(r++, 0, "refresh rate = %ld (msec), buffer size = %ld, "
|
|
"avg-length = %.0f (msec)",
|
|
ecasv_rate_msec, ecasv_buffersize, avg_length); */
|
|
++r;
|
|
const char* bar="------------------------------------------------------------------------------\n";
|
|
mvprintw(r++, 0, bar);
|
|
mvprintw(r, 0, "channel");
|
|
if (ecasv_log_display_mode)
|
|
mvprintw(r++,38, "%s avg-peak dB max-peak dB clipped\n", ecasv_bar_buffer);
|
|
else
|
|
mvprintw(r++,38, "%s avg-peak max-peak clipped\n", ecasv_bar_buffer);
|
|
mvprintw(r++, 0, bar);
|
|
|
|
memset(ecasv_bar_buffer, ' ', ecasv_bar_length_const - 4);
|
|
ecasv_bar_buffer[ecasv_bar_length_const - 4] = 0;
|
|
mvprintw(r + ecasv_chcount + 3, 0, "Press spacebar to reset stats"); // jkc: addition
|
|
move(r + ecasv_chcount - 2, 0);
|
|
|
|
// 13 + 12
|
|
|
|
refresh();
|
|
#endif
|
|
}
|
|
|
|
void ecasv_output_cleanup(void)
|
|
{
|
|
#ifdef ECASV_USE_CURSES
|
|
endwin();
|
|
#endif
|
|
|
|
// FIXME: should be enabled
|
|
#if 0
|
|
if (ecasv_eci_repp != 0) {
|
|
cout << endl << endl << endl;
|
|
ecasv_eci_repp->command("cop-status");
|
|
}
|
|
#endif
|
|
}
|
|
|
|
// jkc: addition of reset_stats function
|
|
void reset_stats_fcn(vector<struct ecasv_channel_stats>* chstats)
|
|
{
|
|
#ifdef ECASV_USE_CURSES
|
|
vector<struct ecasv_channel_stats>::iterator s=chstats->begin();
|
|
while (s!=chstats->end()) {
|
|
s->last_peak=0;
|
|
s->max_peak=0;
|
|
s->drawn_peak=0;
|
|
s->clipped_samples=0;
|
|
s++;
|
|
}
|
|
#endif
|
|
}
|
|
// jkc: end of addition
|
|
|
|
int ecasv_print_vu_meters(ECA_CONTROL_INTERFACE* eci, vector<struct ecasv_channel_stats>* chstats)
|
|
{
|
|
int result = 0;
|
|
|
|
/* check wheter to reset peaks */
|
|
if (reset_stats) {
|
|
reset_stats = 0;
|
|
for(int n = 0; n < ecasv_chcount; n++) {
|
|
(*chstats)[n].max_peak = 0;
|
|
(*chstats)[n].clipped_samples = 0;
|
|
}
|
|
}
|
|
|
|
#ifdef ECASV_USE_CURSES
|
|
for(int n = 0; n < ecasv_chcount; n++) {
|
|
eci->command("copp-select " + kvu_numtostr(n + 1));
|
|
eci->command("copp-get");
|
|
|
|
if (eci->error()) {
|
|
result = -1;
|
|
break;
|
|
}
|
|
|
|
double value = eci->last_float();
|
|
|
|
ecasv_update_chstats(chstats, n, value);
|
|
|
|
ecasv_create_bar((*chstats)[n].drawn_peak, ecasv_bar_length_const, ecasv_bar_buffer);
|
|
// jkc: commented out following two lines and substituted what follows until noted
|
|
// mvprintw(ecasv_header_height_const+n, 0, "Ch-%02d: %s| %.5f %ld\n",
|
|
// n + 1, ecasv_bar_buffer, (*chstats)[n].max_peak, (*chstats)[n].clipped_samples);
|
|
// Calculate average peak value
|
|
|
|
if (ecasv_log_display_mode)
|
|
mvprintw(ecasv_header_height_const+n, 0,
|
|
"Ch-%02d: %s %.2f %.2f %ld\n",
|
|
n+1, ecasv_bar_buffer,
|
|
dB((*chstats)[n].avg_peak_val),
|
|
dB((*chstats)[n].max_peak),
|
|
(*chstats)[n].clipped_samples);
|
|
else
|
|
mvprintw(ecasv_header_height_const+n, 0,
|
|
"Ch-%02d: %s %.5f %.5f %ld\n",
|
|
n+1, ecasv_bar_buffer,
|
|
(*chstats)[n].avg_peak_val,
|
|
(*chstats)[n].max_peak,
|
|
(*chstats)[n].clipped_samples);
|
|
// jkc: end of substitution
|
|
}
|
|
move(ecasv_header_height_const + 2 + ecasv_chcount, 0);
|
|
refresh();
|
|
#else
|
|
cout << ecasv_cop_to_string(eci) << endl;
|
|
#endif
|
|
|
|
return result;
|
|
}
|
|
|
|
void ecasv_update_chstats(vector<struct ecasv_channel_stats>* chstats, int ch, double value)
|
|
{
|
|
/* 1. in case a new channel is encoutered */
|
|
if (static_cast<int>(chstats->size()) <= ch) {
|
|
chstats->resize(ch + 1);
|
|
// jkc: added until noted
|
|
(*chstats)[ch].last_peak=0;
|
|
(*chstats)[ch].drawn_peak=0;
|
|
(*chstats)[ch].max_peak=0;
|
|
(*chstats)[ch].clipped_samples=0;
|
|
(*chstats)[ch].avg_peak.resize(avg_peak_buffer_sz,0);
|
|
(*chstats)[ch].avg_peak_ptr=0;
|
|
// jkc: end of additions
|
|
}
|
|
|
|
/* 2. update last_peak and drawn_peak */
|
|
(*chstats)[ch].last_peak = value;
|
|
if ((*chstats)[ch].last_peak < (*chstats)[ch].drawn_peak) {
|
|
(*chstats)[ch].drawn_peak *= ((*chstats)[ch].last_peak / (*chstats)[ch].drawn_peak);
|
|
}
|
|
else {
|
|
(*chstats)[ch].drawn_peak = (*chstats)[ch].last_peak;
|
|
}
|
|
|
|
/* 3. update max_peak */
|
|
if (value > (*chstats)[ch].max_peak) {
|
|
(*chstats)[ch].max_peak = value;
|
|
}
|
|
|
|
/* 4. update clipped_samples counter */
|
|
if (value > ecasv_clipped_threshold_const) {
|
|
(*chstats)[ch].clipped_samples++;
|
|
}
|
|
|
|
// jkc: added until noted
|
|
/* 5. update running average vector */
|
|
(*chstats)[ch].avg_peak[(*chstats)[ch].avg_peak_ptr] = value;
|
|
(*chstats)[ch].avg_peak_ptr = ((*chstats)[ch].avg_peak_ptr == avg_peak_buffer_sz-1)?
|
|
0 : (*chstats)[ch].avg_peak_ptr+1;
|
|
vector<double>::iterator p=(*chstats)[ch].avg_peak.begin();
|
|
(*chstats)[ch].avg_peak_val=0;
|
|
while (p!=(*chstats)[ch].avg_peak.end()) { (*chstats)[ch].avg_peak_val+=*p++; }
|
|
(*chstats)[ch].avg_peak_val/=avg_peak_buffer_sz;
|
|
// jkc; end of addition
|
|
}
|
|
|
|
void ecasv_create_bar(double value, int barlen, unsigned char* barbuf)
|
|
{
|
|
int curlen = static_cast<int>(rint(((value / 1.0f) * barlen)));
|
|
for(int n = 0; n < barlen; n++) {
|
|
if (n <= curlen)
|
|
barbuf[n] = '*';
|
|
else
|
|
barbuf[n] = ' ';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sets terminal to unbuffered mode (no echo,
|
|
* non-canonical input). -jkc
|
|
*/
|
|
void ecasv_set_unbuffered(void)
|
|
{
|
|
#ifdef HAVE_TERMIOS_H
|
|
tcgetattr( STDIN_FILENO, &old_term );
|
|
new_term = old_term;
|
|
new_term.c_lflag &= ~( ICANON | ECHO );
|
|
tcsetattr( STDIN_FILENO, TCSANOW, &new_term );
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* Sets terminal to buffered mode -jkc
|
|
*/
|
|
void ecasv_set_buffered(void)
|
|
{
|
|
#ifdef HAVE_TERMIOS_H
|
|
tcsetattr( STDIN_FILENO, TCSANOW, &old_term );
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* Reads a character from the terminal console. -jkc
|
|
*/
|
|
int ecasv_kbhit(void)
|
|
{
|
|
int result;
|
|
fd_set set;
|
|
struct timeval tv;
|
|
|
|
FD_ZERO(&set);
|
|
FD_SET(STDIN_FILENO,&set); /* watch stdin */
|
|
tv.tv_sec = 0;
|
|
tv.tv_usec = 0; /* don't wait */
|
|
|
|
/* quick peek at the input, to see if anything is there */
|
|
ecasv_set_unbuffered();
|
|
result = select( STDIN_FILENO+1,&set,NULL,NULL,&tv);
|
|
ecasv_set_buffered();
|
|
|
|
return result == 1;
|
|
}
|
|
|
|
void ecasv_print_usage(void)
|
|
{
|
|
cerr << "****************************************************************************\n";
|
|
cerr << "* ecasignalview, v" << ecatools_signalview_version << " (" << VERSION << ")\n";
|
|
cerr << "* Copyright 1999-2005 Kai Vehmanen, Jeffrey Cunningham\n";
|
|
cerr << "* Licensed under the terms of the GNU General Public License\n";
|
|
cerr << "****************************************************************************\n";
|
|
|
|
cerr << "\nUSAGE: ecasignalview [options] [input] [output] \n";
|
|
cerr << "\nOptions:\n";
|
|
cerr << "\t-b:buffersize\n";
|
|
// cerr << "\t\t-c (cumulative mode)\n";
|
|
cerr << "\t-d (debug mode)\n";
|
|
cerr << "\t-f:bits,channels,samplerate\n";
|
|
cerr << "\t-r:refresh_msec\n\n";
|
|
cerr << "\t-I (linear-scale)\n";
|
|
cerr << "\t-L (logarithmic-scale)\n";
|
|
}
|
|
|
|
void ecasv_signal_handler(int signum)
|
|
{
|
|
if (signum == SIGHUP) {
|
|
reset_stats = 1;
|
|
}
|
|
else {
|
|
cerr << "Interrupted... cleaning up.\n";
|
|
done=1;
|
|
}
|
|
}
|