|
Packit |
c32a2d |
/*
|
|
Packit |
c32a2d |
common: misc stuff... audio flush, status display...
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
copyright ?-2015 by the mpg123 project - free software under the terms of the LGPL 2.1
|
|
Packit |
c32a2d |
see COPYING and AUTHORS files in distribution or http://mpg123.org
|
|
Packit |
c32a2d |
initially written by Michael Hipp
|
|
Packit |
c32a2d |
*/
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* Need snprintf. */
|
|
Packit |
c32a2d |
#define _DEFAULT_SOURCE
|
|
Packit |
c32a2d |
#define _BSD_SOURCE
|
|
Packit |
c32a2d |
#include "mpg123app.h"
|
|
Packit |
c32a2d |
#include "out123.h"
|
|
Packit |
c32a2d |
#include <sys/stat.h>
|
|
Packit |
c32a2d |
#include "common.h"
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
#ifdef __EMX__
|
|
Packit |
c32a2d |
/* Special ways for OS/2 EMX */
|
|
Packit |
c32a2d |
#include <stdlib.h>
|
|
Packit |
c32a2d |
#else
|
|
Packit |
c32a2d |
/* POSIX stuff */
|
|
Packit |
c32a2d |
#ifdef HAVE_TERMIOS
|
|
Packit |
c32a2d |
#include <termios.h>
|
|
Packit |
c32a2d |
#include <sys/ioctl.h>
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
#include "debug.h"
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
int stopped = 0;
|
|
Packit |
c32a2d |
int paused = 0;
|
|
Packit |
c32a2d |
static int term_is_fun = -1;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
int term_have_fun(int fd)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
if(term_is_fun > -1)
|
|
Packit |
c32a2d |
return term_is_fun;
|
|
Packit |
c32a2d |
else
|
|
Packit |
c32a2d |
term_is_fun = 0;
|
|
Packit |
c32a2d |
#ifdef HAVE_TERMIOS
|
|
Packit |
c32a2d |
if(term_width(fd) > 0 && param.term_visual)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
/* Only play with non-dumb terminals. */
|
|
Packit |
c32a2d |
char *tname = compat_getenv("TERM");
|
|
Packit |
c32a2d |
if(tname)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
if(strcmp(tname, "") && strcmp(tname, "dumb"))
|
|
Packit |
c32a2d |
term_is_fun = 1;
|
|
Packit |
c32a2d |
free(tname);
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
return term_is_fun;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* Also serves as a way to detect if we have an interactive terminal. */
|
|
Packit |
c32a2d |
int term_width(int fd)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
#ifdef __EMX__
|
|
Packit |
c32a2d |
/* OS/2 */
|
|
Packit |
c32a2d |
int s[2];
|
|
Packit |
c32a2d |
_scrsize (s);
|
|
Packit |
c32a2d |
if (s[0] >= 0)
|
|
Packit |
c32a2d |
return s[0];
|
|
Packit |
c32a2d |
#else
|
|
Packit |
c32a2d |
#ifdef HAVE_TERMIOS
|
|
Packit |
c32a2d |
/* POSIX */
|
|
Packit |
c32a2d |
struct winsize geometry;
|
|
Packit |
c32a2d |
geometry.ws_col = 0;
|
|
Packit |
c32a2d |
if(ioctl(fd, TIOCGWINSZ, &geometry) >= 0)
|
|
Packit |
c32a2d |
return (int)geometry.ws_col;
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
return -1;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
const char* rva_name[3] = { "off", "mix", "album" };
|
|
Packit |
c32a2d |
static const char* rva_statname[3] = { "---", "mix", "alb" };
|
|
Packit |
c32a2d |
static const char *modes[5] = {"Stereo", "Joint-Stereo", "Dual-Channel", "Single-Channel", "Invalid" };
|
|
Packit |
c32a2d |
static const char *smodes[5] = { "stereo", "j-s", "dual", "mono", "o.O" };
|
|
Packit |
c32a2d |
static const char *layers[4] = { "Unknown" , "I", "II", "III" };
|
|
Packit |
c32a2d |
static const char *versions[4] = {"1.0", "2.0", "2.5", "x.x" };
|
|
Packit |
c32a2d |
static const int samples_per_frame[4][4] =
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
{ -1,384,1152,1152 }, /* MPEG 1 */
|
|
Packit |
c32a2d |
{ -1,384,1152,576 }, /* MPEG 2 */
|
|
Packit |
c32a2d |
{ -1,384,1152,576 }, /* MPEG 2.5 */
|
|
Packit |
c32a2d |
{ -1,-1,-1,-1 }, /* Unknown */
|
|
Packit |
c32a2d |
};
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* concurring to print_rheader... here for control_generic */
|
|
Packit |
c32a2d |
const char* remote_header_help = "S <mpeg-version> <layer> <sampling freq> <mode(stereo/mono/...)> <mode_ext> <framesize> <stereo> <copyright> <error_protected> <emphasis> <bitrate> <extension> <vbr(0/1=yes/no)>";
|
|
Packit |
c32a2d |
void print_remote_header(mpg123_handle *mh)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
struct mpg123_frameinfo i;
|
|
Packit |
c32a2d |
mpg123_info(mh, &i);
|
|
Packit |
c32a2d |
if(i.mode >= 4 || i.mode < 0) i.mode = 4;
|
|
Packit |
c32a2d |
if(i.version >= 3 || i.version < 0) i.version = 3;
|
|
Packit |
c32a2d |
generic_sendmsg("S %s %d %ld %s %d %d %d %d %d %d %d %d %d",
|
|
Packit |
c32a2d |
versions[i.version],
|
|
Packit |
c32a2d |
i.layer,
|
|
Packit |
c32a2d |
i.rate,
|
|
Packit |
c32a2d |
modes[i.mode],
|
|
Packit |
c32a2d |
i.mode_ext,
|
|
Packit |
c32a2d |
i.framesize,
|
|
Packit |
c32a2d |
i.mode == MPG123_M_MONO ? 1 : 2,
|
|
Packit |
c32a2d |
i.flags & MPG123_COPYRIGHT ? 1 : 0,
|
|
Packit |
c32a2d |
i.flags & MPG123_CRC ? 1 : 0,
|
|
Packit |
c32a2d |
i.emphasis,
|
|
Packit |
c32a2d |
i.bitrate,
|
|
Packit |
c32a2d |
i.flags & MPG123_PRIVATE ? 1 : 0,
|
|
Packit |
c32a2d |
i.vbr);
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
void print_header(mpg123_handle *mh)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
struct mpg123_frameinfo i;
|
|
Packit |
c32a2d |
mpg123_info(mh, &i);
|
|
Packit |
c32a2d |
if(i.mode > 4 || i.mode < 0) i.mode = 4;
|
|
Packit |
c32a2d |
if(i.version > 3 || i.version < 0) i.version = 3;
|
|
Packit |
c32a2d |
if(i.layer > 3 || i.layer < 0) i.layer = 0;
|
|
Packit |
c32a2d |
fprintf(stderr,"MPEG %s, Layer: %s, Freq: %ld, mode: %s, modext: %d, BPF : %d\n",
|
|
Packit |
c32a2d |
versions[i.version],
|
|
Packit |
c32a2d |
layers[i.layer], i.rate,
|
|
Packit |
c32a2d |
modes[i.mode],i.mode_ext,i.framesize);
|
|
Packit |
c32a2d |
fprintf(stderr,"Channels: %d, copyright: %s, original: %s, CRC: %s, emphasis: %d.\n",
|
|
Packit |
c32a2d |
i.mode == MPG123_M_MONO ? 1 : 2,i.flags & MPG123_COPYRIGHT ? "Yes" : "No",
|
|
Packit |
c32a2d |
i.flags & MPG123_ORIGINAL ? "Yes" : "No", i.flags & MPG123_CRC ? "Yes" : "No",
|
|
Packit |
c32a2d |
i.emphasis);
|
|
Packit |
c32a2d |
fprintf(stderr,"Bitrate: ");
|
|
Packit |
c32a2d |
switch(i.vbr)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
case MPG123_CBR:
|
|
Packit |
c32a2d |
if(i.bitrate) fprintf(stderr, "%d kbit/s", i.bitrate);
|
|
Packit |
c32a2d |
else fprintf(stderr, "%d kbit/s (free format)", (int)((double)(i.framesize+4)*8*i.rate*0.001/samples_per_frame[i.version][i.layer]+0.5));
|
|
Packit |
c32a2d |
break;
|
|
Packit |
c32a2d |
case MPG123_VBR: fprintf(stderr, "VBR"); break;
|
|
Packit |
c32a2d |
case MPG123_ABR: fprintf(stderr, "%d kbit/s ABR", i.abr_rate); break;
|
|
Packit |
c32a2d |
default: fprintf(stderr, "???");
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
fprintf(stderr, " Extension value: %d\n", i.flags & MPG123_PRIVATE ? 1 : 0);
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
void print_header_compact(mpg123_handle *mh)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
struct mpg123_frameinfo i;
|
|
Packit |
c32a2d |
mpg123_info(mh, &i);
|
|
Packit |
c32a2d |
if(i.mode > 4 || i.mode < 0) i.mode = 4;
|
|
Packit |
c32a2d |
if(i.version > 3 || i.version < 0) i.version = 3;
|
|
Packit |
c32a2d |
if(i.layer > 3 || i.layer < 0) i.layer = 0;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
fprintf(stderr,"MPEG %s L %s ", versions[i.version], layers[i.layer]);
|
|
Packit |
c32a2d |
switch(i.vbr)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
case MPG123_CBR:
|
|
Packit |
c32a2d |
if(i.bitrate) fprintf(stderr, "cbr%d", i.bitrate);
|
|
Packit |
c32a2d |
else fprintf(stderr, "cbr%d", (int)((double)i.framesize*8*i.rate*0.001/samples_per_frame[i.version][i.layer]+0.5));
|
|
Packit |
c32a2d |
break;
|
|
Packit |
c32a2d |
case MPG123_VBR: fprintf(stderr, "vbr"); break;
|
|
Packit |
c32a2d |
case MPG123_ABR: fprintf(stderr, "abr%d", i.abr_rate); break;
|
|
Packit |
c32a2d |
default: fprintf(stderr, "???");
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
fprintf(stderr," %ld %s\n", i.rate, smodes[i.mode]);
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
unsigned int roundui(double val)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
double base = floor(val);
|
|
Packit |
c32a2d |
return (unsigned int) ((val-base) < 0.5 ? base : base + 1 );
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* Split into mm:ss.xx or hh:mm:ss, depending on value. */
|
|
Packit |
c32a2d |
static void settle_time(double tim, unsigned long *times, char *sep)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
if(tim >= 3600.)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
*sep = ':';
|
|
Packit |
c32a2d |
times[0] = (unsigned long) tim/3600;
|
|
Packit |
c32a2d |
tim -= times[0]*3600;
|
|
Packit |
c32a2d |
times[1] = (unsigned long) tim/60;
|
|
Packit |
c32a2d |
tim -= times[1]*60;
|
|
Packit |
c32a2d |
times[2] = (unsigned long) tim;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
else
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
*sep = '.';
|
|
Packit |
c32a2d |
times[0] = (unsigned long) tim/60;
|
|
Packit |
c32a2d |
times[1] = (unsigned long) tim%60;
|
|
Packit |
c32a2d |
times[2] = (unsigned long) (tim*100)%100;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* Print output buffer fill. */
|
|
Packit |
c32a2d |
void print_buf(const char* prefix, out123_handle *ao)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
long rate;
|
|
Packit |
c32a2d |
int framesize;
|
|
Packit |
c32a2d |
double tim;
|
|
Packit |
c32a2d |
unsigned long times[3];
|
|
Packit |
c32a2d |
char timesep;
|
|
Packit |
c32a2d |
size_t buffsize;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
buffsize = out123_buffered(ao);
|
|
Packit |
c32a2d |
if(out123_getformat(ao, &rate, NULL, NULL, &framesize))
|
|
Packit |
c32a2d |
return;
|
|
Packit |
c32a2d |
tim = (double)(buffsize/framesize)/rate;
|
|
Packit |
c32a2d |
settle_time(tim, times, ×ep);
|
|
Packit |
c32a2d |
fprintf( stderr, "\r%s[%02lu:%02lu%c%02lu]"
|
|
Packit |
c32a2d |
, prefix, times[0], times[1], timesep, times[2] );
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* Note about position info with buffering:
|
|
Packit |
c32a2d |
Negative positions mean that the previous track is still playing from the
|
|
Packit |
c32a2d |
buffer. It's a countdown. The frame counter always relates to the last
|
|
Packit |
c32a2d |
decoded frame, what entered the buffer right now. */
|
|
Packit |
c32a2d |
void print_stat(mpg123_handle *fr, long offset, out123_handle *ao, int draw_bar)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
size_t buffered;
|
|
Packit |
c32a2d |
off_t decoded;
|
|
Packit |
c32a2d |
off_t elapsed;
|
|
Packit |
c32a2d |
off_t remain;
|
|
Packit |
c32a2d |
off_t length;
|
|
Packit |
c32a2d |
off_t frame;
|
|
Packit |
c32a2d |
off_t frames;
|
|
Packit |
c32a2d |
off_t rframes;
|
|
Packit |
c32a2d |
int spf;
|
|
Packit |
c32a2d |
double basevol, realvol;
|
|
Packit |
c32a2d |
char *icy;
|
|
Packit |
c32a2d |
long rate;
|
|
Packit |
c32a2d |
int framesize;
|
|
Packit |
c32a2d |
struct mpg123_frameinfo mi;
|
|
Packit |
c32a2d |
char linebuf[256];
|
|
Packit |
c32a2d |
char *line = NULL;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
#ifndef WIN32
|
|
Packit |
c32a2d |
#ifndef GENERIC
|
|
Packit |
c32a2d |
/* Only generate new stat line when stderr is ready... don't overfill... */
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
struct timeval t;
|
|
Packit |
c32a2d |
fd_set serr;
|
|
Packit |
c32a2d |
int n,errfd = fileno(stderr);
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
t.tv_sec=t.tv_usec=0;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
FD_ZERO(&serr);
|
|
Packit |
c32a2d |
FD_SET(errfd,&serr);
|
|
Packit |
c32a2d |
n = select(errfd+1,NULL,&serr,NULL,&t);
|
|
Packit |
c32a2d |
if(n <= 0) return;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
if(out123_getformat(ao, &rate, NULL, NULL, &framesize))
|
|
Packit |
c32a2d |
return;
|
|
Packit |
c32a2d |
buffered = out123_buffered(ao)/framesize;
|
|
Packit |
c32a2d |
decoded = mpg123_tell(fr);
|
|
Packit |
c32a2d |
length = mpg123_length(fr);
|
|
Packit |
c32a2d |
frame = mpg123_tellframe(fr);
|
|
Packit |
c32a2d |
frames = mpg123_framelength(fr);
|
|
Packit |
c32a2d |
spf = mpg123_spf(fr);
|
|
Packit |
c32a2d |
if(decoded < 0 || length < 0 || frame < 0 || frames <= 0 || spf <= 0)
|
|
Packit |
c32a2d |
return;
|
|
Packit |
c32a2d |
/* Apply offset. */
|
|
Packit |
c32a2d |
frame += offset;
|
|
Packit |
c32a2d |
if(frame < 0)
|
|
Packit |
c32a2d |
frame = 0;
|
|
Packit |
c32a2d |
/* Some sensible logic around offsets and time.
|
|
Packit |
c32a2d |
Buffering makes the relationships between the numbers non-trivial. */
|
|
Packit |
c32a2d |
rframes = frames-frame;
|
|
Packit |
c32a2d |
elapsed = decoded + offset*spf - buffered; /* May be negative, a countdown. */
|
|
Packit |
c32a2d |
remain = elapsed > 0 ? length - elapsed : length;
|
|
Packit |
c32a2d |
if( MPG123_OK == mpg123_info(fr, &mi)
|
|
Packit |
c32a2d |
&& MPG123_OK == mpg123_getvolume(fr, &basevol, &realvol, NULL) )
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
char framefmt[10];
|
|
Packit |
c32a2d |
char framestr[2][32];
|
|
Packit |
c32a2d |
int linelen;
|
|
Packit |
c32a2d |
int maxlen;
|
|
Packit |
c32a2d |
int len;
|
|
Packit |
c32a2d |
int ti;
|
|
Packit |
c32a2d |
/* Deal with overly long times. */
|
|
Packit |
c32a2d |
double tim[3];
|
|
Packit |
c32a2d |
unsigned long times[3][3];
|
|
Packit |
c32a2d |
char timesep[3];
|
|
Packit |
c32a2d |
char sign[3] = {' ', ' ', ' '};
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* 255 is enough for the data I prepare, if there is no terminal width to
|
|
Packit |
c32a2d |
fill */
|
|
Packit |
c32a2d |
maxlen = term_width(STDERR_FILENO);
|
|
Packit |
c32a2d |
linelen = maxlen > 0 ? maxlen : (sizeof(linebuf)-1);
|
|
Packit |
c32a2d |
line = linelen >= sizeof(linebuf)
|
|
Packit |
c32a2d |
? malloc(linelen+1) /* Only malloc if it is a really long line. */
|
|
Packit |
c32a2d |
: linebuf; /* Small buffer on stack is enough. */
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
tim[0] = (double)elapsed/rate;
|
|
Packit |
c32a2d |
tim[1] = (double)remain/rate;
|
|
Packit |
c32a2d |
tim[2] = (double)buffered/rate;
|
|
Packit |
c32a2d |
for(ti=0; ti<3; ++ti)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
if(tim[ti] < 0.){ sign[ti] = '-'; tim[ti] = -tim[ti]; }
|
|
Packit |
c32a2d |
settle_time(tim[ti], times[ti], ×ep[ti]);
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
/* Taking pains to properly size the frame number fields. */
|
|
Packit |
c32a2d |
len = snprintf( framefmt, sizeof(framefmt)
|
|
Packit |
c32a2d |
, "%%0%d"OFF_P, (int)log10(frames)+1 );
|
|
Packit |
c32a2d |
if(len < 0 || len >= sizeof(framefmt))
|
|
Packit |
c32a2d |
memcpy(framefmt, "%05"OFF_P, sizeof("%05"OFF_P));
|
|
Packit |
c32a2d |
snprintf( framestr[0], sizeof(framestr[0])-1, framefmt, (off_p)frame);
|
|
Packit |
c32a2d |
framestr[0][sizeof(framestr[0])-1] = 0;
|
|
Packit |
c32a2d |
snprintf( framestr[1], sizeof(framestr[1])-1, framefmt, (off_p)rframes);
|
|
Packit |
c32a2d |
framestr[1][sizeof(framestr[1])-1] = 0;
|
|
Packit |
c32a2d |
/* Now start with the state line. */
|
|
Packit |
c32a2d |
memset(line, 0, linelen+1); /* Always one zero more. */
|
|
Packit |
c32a2d |
/* Start with position info. */
|
|
Packit |
c32a2d |
len = snprintf( line, linelen
|
|
Packit |
c32a2d |
, "%c %s+%s %c%02lu:%02lu%c%02lu+%02lu:%02lu%c%02lu"
|
|
Packit |
c32a2d |
, stopped ? '_' : (paused ? '=' : '>')
|
|
Packit |
c32a2d |
, framestr[0], framestr[1]
|
|
Packit |
c32a2d |
, sign[0]
|
|
Packit |
c32a2d |
, times[0][0], times[0][1], timesep[0], times[0][2]
|
|
Packit |
c32a2d |
, times[1][0], times[1][1], timesep[1], times[1][2]
|
|
Packit |
c32a2d |
);
|
|
Packit |
c32a2d |
/* Just cut it. */
|
|
Packit |
c32a2d |
if(len >= linelen)
|
|
Packit |
c32a2d |
len=linelen;
|
|
Packit |
c32a2d |
if(len >= 0 && param.usebuffer && len < linelen )
|
|
Packit |
c32a2d |
{ /* Buffer info. */
|
|
Packit |
c32a2d |
int len_add = snprintf( line+len, linelen-len
|
|
Packit |
c32a2d |
, " [%02lu:%02lu%c%02lu]"
|
|
Packit |
c32a2d |
, times[2][0], times[2][1], timesep[2], times[2][2] );
|
|
Packit |
c32a2d |
if(len_add > 0)
|
|
Packit |
c32a2d |
len += len_add;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
if(len >= 0 && len < linelen)
|
|
Packit |
c32a2d |
{ /* Volume info. */
|
|
Packit |
c32a2d |
int len_add = snprintf( line+len, linelen-len
|
|
Packit |
c32a2d |
, " %s %03u=%03u"
|
|
Packit |
c32a2d |
, rva_statname[param.rva], roundui(basevol*100), roundui(realvol*100)
|
|
Packit |
c32a2d |
);
|
|
Packit |
c32a2d |
if(len_add > 0)
|
|
Packit |
c32a2d |
len += len_add;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
if(len >= 0 && len < linelen)
|
|
Packit |
c32a2d |
{ /* Bitrate. */
|
|
Packit |
c32a2d |
int len_add = snprintf( line+len, linelen-len
|
|
Packit |
c32a2d |
, " %3d kb/s", mi.bitrate );
|
|
Packit |
c32a2d |
if(len_add > 0)
|
|
Packit |
c32a2d |
len += len_add;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
if(len >= 0 && len < linelen)
|
|
Packit |
c32a2d |
{ /* Size of frame in bytes. */
|
|
Packit |
c32a2d |
int len_add = snprintf( line+len, linelen-len
|
|
Packit |
c32a2d |
, " %4d B", mi.framesize );
|
|
Packit |
c32a2d |
if(len_add > 0)
|
|
Packit |
c32a2d |
len += len_add;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
if(len >= 0 && len < linelen)
|
|
Packit |
c32a2d |
{ /* Size of frame in bytes. */
|
|
Packit |
c32a2d |
int len_add = 0;
|
|
Packit |
c32a2d |
long res = 0;
|
|
Packit |
c32a2d |
if(mpg123_getstate(fr, MPG123_ACCURATE, &res, NULL) == MPG123_OK)
|
|
Packit |
c32a2d |
len_add = snprintf( line+len, linelen-len
|
|
Packit |
c32a2d |
, " %s", res ? "acc" : "fuz" );
|
|
Packit |
c32a2d |
if(len_add > 0)
|
|
Packit |
c32a2d |
len += len_add;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
if(len >= 0 && len < linelen)
|
|
Packit |
c32a2d |
{ /* Size of frame in bytes. */
|
|
Packit |
c32a2d |
int len_add = 0;
|
|
Packit |
c32a2d |
long res = mpg123_clip(fr);
|
|
Packit |
c32a2d |
if(res >= 0)
|
|
Packit |
c32a2d |
len_add = snprintf( line+len, linelen-len
|
|
Packit |
c32a2d |
, " %4ld clip", res );
|
|
Packit |
c32a2d |
if(len_add > 0)
|
|
Packit |
c32a2d |
len += len_add;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
if(len >= 0 && len < linelen)
|
|
Packit |
c32a2d |
{ /* Size of frame in bytes. */
|
|
Packit |
c32a2d |
int len_add = 0;
|
|
Packit |
c32a2d |
len_add = snprintf( line+len, linelen-len
|
|
Packit |
c32a2d |
, " p%+.3f", param.pitch );
|
|
Packit |
c32a2d |
if(len_add > 0)
|
|
Packit |
c32a2d |
len += len_add;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
if(len >= 0)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
if(maxlen > 0 && len > maxlen)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
/* Emergency cut to avoid terminal scrolling. */
|
|
Packit |
c32a2d |
int i;
|
|
Packit |
c32a2d |
/* Blank a word that would have been cut off. */
|
|
Packit |
c32a2d |
for(i=maxlen; i>=0; --i)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
char old = line[i];
|
|
Packit |
c32a2d |
line[i] = ' ';
|
|
Packit |
c32a2d |
if(old == ' ')
|
|
Packit |
c32a2d |
break;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
line[maxlen] = 0;
|
|
Packit |
c32a2d |
len = maxlen;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
/* Ensure that it is filled with spaces if we got some line length.
|
|
Packit |
c32a2d |
Shouldn't we always fill to maxlen? */
|
|
Packit |
c32a2d |
if(maxlen > 0)
|
|
Packit |
c32a2d |
memset(line+len, ' ', linelen-len);
|
|
Packit |
c32a2d |
#ifdef HAVE_TERMIOS
|
|
Packit |
c32a2d |
draw_bar = draw_bar && term_have_fun(STDERR_FILENO);
|
|
Packit |
c32a2d |
/* Use inverse color to draw a progress bar. */
|
|
Packit |
c32a2d |
if(maxlen > 0 && draw_bar)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
char old;
|
|
Packit |
c32a2d |
int barlen = 0;
|
|
Packit |
c32a2d |
if(length > 0 && elapsed > 0)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
if(elapsed < length)
|
|
Packit |
c32a2d |
barlen = (int)((double)elapsed/length * maxlen);
|
|
Packit |
c32a2d |
else
|
|
Packit |
c32a2d |
barlen = maxlen;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
old = line[barlen];
|
|
Packit |
c32a2d |
fprintf(stderr, "\x1b[7m");
|
|
Packit |
c32a2d |
line[barlen] = 0;
|
|
Packit |
c32a2d |
fprintf(stderr, "\r%s", line);
|
|
Packit |
c32a2d |
line[barlen] = old;
|
|
Packit |
c32a2d |
fprintf(stderr, "\x1b[0m");
|
|
Packit |
c32a2d |
fprintf(stderr, "%s", line+barlen);
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
else
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
fprintf(stderr, "\r%s", line);
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
/* Check for changed tags here too? */
|
|
Packit |
c32a2d |
if( mpg123_meta_check(fr) & MPG123_NEW_ICY && MPG123_OK == mpg123_icy(fr, &icy) )
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
if(line) /* Clear the inverse video. */
|
|
Packit |
c32a2d |
fprintf(stderr, "\r%s", line);
|
|
Packit |
c32a2d |
fprintf(stderr, "\nICY-META: %s\n", icy);
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
if(line && line != linebuf)
|
|
Packit |
c32a2d |
free(line);
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
void clear_stat()
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
int len = term_width(STDERR_FILENO);
|
|
Packit |
c32a2d |
if(len > 0)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
char fmt[20];
|
|
Packit |
c32a2d |
int flen;
|
|
Packit |
c32a2d |
if( (flen=snprintf(fmt, sizeof(fmt), "\r%%%ds\r", len)) > 0
|
|
Packit |
c32a2d |
&& flen < sizeof(fmt) )
|
|
Packit |
c32a2d |
fprintf(stderr, fmt, " ");
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
}
|