1
0
mirror of http://mpg123.de/trunk/.git synced 2025-07-30 02:01:12 +03:00

mpg123, libout123, fmt123: Make a very special friend happy, introduce output mute.

This introduces software muting in libout123, to be triggered via terminal control
key 'u' (m was taken) or the remote control commands 'mute' and 'unmute'. For this,
libout123 needs to know what a zero looks like in the current encoding. I hope
I handled that smartly enough with the MPG123_ZEROSAMPLE macro in fmt123.

I explicitly decided against linking in libsyn123. That makes only sense when
going all-in and deciding that libout123 shall convert, resample, and mix
on-the-fly to make input data match the output. This might be nice to have,
but it is also nice to have a library that does not really care about the
content it transports. It is a simple transporter with a buffer. Said buffer
necessitates that the transporter knows what empty sound looks like, but I
really don't want to burden it with more knowledge for simplicity.

This muting needs to be inside libout123 whe the buffer is used. Feeding
silence from the client application does not have latency you expect when
(un)pause is already negotiated with the buffer.



git-svn-id: svn://scm.orgis.org/mpg123/trunk@4589 35dc7657-300d-0410-a2e5-dc2837fedb53
This commit is contained in:
thor
2020-01-31 23:48:50 +00:00
parent 737a128b36
commit dabbc01437
14 changed files with 162 additions and 36 deletions

12
README
View File

@ -73,13 +73,14 @@ Note that this Ctrl+C behaviour is special to this mode; when any of the followi
3.2 Advanced Console Usage 3.2 Advanced Console Usage
You can specify the option -C to enable a terminal control interface enabling to influence playback on current title/playlist by pressing some key: You can specify the option -C to enable a terminal control interface enabling to influence playback on current title/playlist by pressing some key:
-= terminal control keys =- -= terminal control keys =-
[s] or [ ] interrupt/restart playback (i.e. 'pause') [s] or [ ] interrupt/restart playback (i.e. '(un)pause')
[f] next track [f] next track
[d] previous track [d] previous track
[]] next directory (next track until directory part changes)
[[] previous directory (previous track until directory part changes)
[b] back to beginning of track [b] back to beginning of track
[p] pause while looping current sound chunk [p] loop around current position (don't combine with output buffer)
[.] forward [.] forward
[,] rewind [,] rewind
[:] fast forward [:] fast forward
@ -88,11 +89,16 @@ You can specify the option -C to enable a terminal control interface enabling to
[<] fine rewind [<] fine rewind
[+] volume up [+] volume up
[-] volume down [-] volume down
[u] (un)mute volume
[r] RVA switch [r] RVA switch
[v] verbose switch [v] verbose switch
[l] list current playlist, indicating current track there [l] list current playlist, indicating current track there
[t] display tag info (again) [t] display tag info (again)
[m] print MPEG header info (again) [m] print MPEG header info (again)
[c] or [C] pitch up (small step, big step)
[x] or [X] pitch down (small step, big step)
[w] reset pitch to zero
[k] print out current position in playlist and track, for the benefit of some external tool to store bookmarks
[h] this help [h] this help
[q] quit [q] quit

View File

@ -22,6 +22,7 @@ COMMAND CODES
You can get this info via the control command "help". You can get this info via the control command "help".
HELP/H: command listing (LONG/SHORT forms), command case insensitve HELP/H: command listing (LONG/SHORT forms), command case insensitve
LOAD/L <trackname>: load and start playing resource <trackname> LOAD/L <trackname>: load and start playing resource <trackname>
@ -38,6 +39,10 @@ JUMP/J <frame>|<+offset>|<-offset>|<[+|-]seconds>s: jump to mpeg frame <frame> o
VOLUME/V <percent>: set volume in % (0..100...); float value VOLUME/V <percent>: set volume in % (0..100...); float value
MUTE: turn on software mute in output
UNMUTE: turn off software mute in output
RVA off|(mix|radio)|(album|audiophile): set rva mode RVA off|(mix|radio)|(album|audiophile): set rva mode
EQ/E <channel> <band> <value>: set equalizer value for frequency band 0 to 31 on channel 1 (left) or 2 (right) or 3 (both) EQ/E <channel> <band> <value>: set equalizer value for frequency band 0 to 31 on channel 1 (left) or 2 (right) or 3 (both)
@ -52,25 +57,36 @@ SCAN: scan through the file, building seek index
SAMPLE: print out the sample position and total number of samples SAMPLE: print out the sample position and total number of samples
FORMAT: print out sampling rate in Hz and channel count
SEQ <bass> <mid> <treble>: simple eq setting... SEQ <bass> <mid> <treble>: simple eq setting...
PITCH <[+|-]value>: adjust playback speed (+0.01 is 1 % faster) PITCH <[+|-]value>: adjust playback speed (+0.01 is 1 % faster)
SILENCE: be silent during playback (meaning silence in text form) SILENCE: be silent during playback (meaning silence in text form)
STATE: Print auxilliary state info in several lines (just try it to see what info is there). STATE: Print auxiliary state info in several lines (just try it to see what info is there).
TAG/T: Print all available (ID3) tag info, for ID3v2 that gives output of all collected text fields, using the ID3v2.3/4 4-character names. NOTE: ID3v2 data will be deleted on non-forward seeks.
TAG/T: Print all available (ID3) tag info, for ID3v2 that gives output of all collected text fields, using the ID3v2.3/4 4-character names.
The output is multiple lines, begin marked by "@T {", end by "@T }". The output is multiple lines, begin marked by "@T {", end by "@T }".
ID3v1 data is like in the @I info lines (see below), just with "@T" in front. ID3v1 data is like in the @I info lines (see below), just with "@T" in front.
An ID3v2 data field is introduced via ([ ... ] means optional): An ID3v2 data field is introduced via ([ ... ] means optional):
@T ID3v2.<NAME>[ [lang(<LANG>)] desc(<description>)]: @T ID3v2.<NAME>[ [lang(<LANG>)] desc(<description>)]:
The lines of data follow with "=" prefixed: The lines of data follow with "=" prefixed:
@T =<one line of content in UTF-8 encoding> @T =<one line of content in UTF-8 encoding>
meaning of the @S stream info: meaning of the @S stream info:
S <mpeg-version> <layer> <sampling freq> <mode(stereo/mono/...)> <mode_ext> <framesize> <stereo> <copyright> <error_protected> <emphasis> <bitrate> <extension> <vbr(0/1=yes/no)> S <mpeg-version> <layer> <sampling freq> <mode(stereo/mono/...)> <mode_ext> <framesize> <stereo> <copyright> <error_protected> <emphasis> <bitrate> <extension> <vbr(0/1=yes/no)>
The @I lines after loading a track give some ID3 info, the format: The @I lines after loading a track give some ID3 info, the format:
@I ID3:artist album year comment genretext @I ID3:artist album year comment genretext
where artist,album and comment are exactly 30 characters each, year is 4 characters, genre text unspecified. where artist,album and comment are exactly 30 characters each, year is 4 characters, genre text unspecified.
You will encounter "@I ID3.genre:<number>" and "@I ID3.track:<number>". You will encounter "@I ID3.genre:<number>" and "@I ID3.track:<number>".

View File

@ -561,8 +561,10 @@ complete junk on the input side. Fatal errors were only considered
for output. With version 1.26.0, this changed to the behaviour for output. With version 1.26.0, this changed to the behaviour
described below. described below.
.P .P
The process exit code is zero (success) if all tracks in a playlist When not using the remote control interface (which returns input
had at least one frame parsed, even if it did not decode cleanly, or errors as text messages), the process exit code is zero (success)
only if all tracks in a playlist had at least one frame parsed,
even if it did not decode cleanly, or
are empty, MPEG-wise (perhaps only metadata, or really an empty file). are empty, MPEG-wise (perhaps only metadata, or really an empty file).
When you decode nothing, nothing is the result and that is fine. When When you decode nothing, nothing is the result and that is fine. When
a track later aborts because of parser errors or breakdown of the a track later aborts because of parser errors or breakdown of the

View File

@ -239,3 +239,10 @@ int set_pitch(mpg123_handle *fr, out123_handle *ao, double new_pitch)
} }
return out123_start(ao, pitch_rate(rate), channels, format); return out123_start(ao, pitch_rate(rate), channels, format);
} }
int set_mute(out123_handle *ao, int mutestate)
{
return out123_param( ao
, mutestate ? OUT123_ADD_FLAGS : OUT123_REMOVE_FLAGS
, OUT123_MUTE, 0, NULL );
}

View File

@ -33,6 +33,8 @@ void print_capabilities(out123_handle *ao, mpg123_handle *mh);
Returns 1 if pitch setting succeeded, 0 otherwise. Returns 1 if pitch setting succeeded, 0 otherwise.
*/ */
int set_pitch(mpg123_handle *fr, out123_handle *ao, double new_pitch); int set_pitch(mpg123_handle *fr, out123_handle *ao, double new_pitch);
// Enable/disable software mute state.
int set_mute(out123_handle *ao, int mutestate);
#endif #endif

View File

@ -31,6 +31,7 @@
int stopped = 0; int stopped = 0;
int paused = 0; int paused = 0;
int muted = 0;
static int term_is_fun = -1; static int term_is_fun = -1;
int term_have_fun(int fd, struct parameter *param) int term_have_fun(int fd, struct parameter *param)
@ -338,9 +339,10 @@ void print_stat(mpg123_handle *fr, long offset, out123_handle *ao, int draw_bar
if(len >= 0 && len < linelen) if(len >= 0 && len < linelen)
{ /* Volume info. */ { /* Volume info. */
int len_add = snprintf( line+len, linelen-len int len_add = snprintf( line+len, linelen-len
, " %s %03u=%03u" , " %s %03u%c%03u"
, rva_statname[param->rva], roundui(basevol*100), roundui(realvol*100) , rva_statname[param->rva]
); , roundui(basevol*100), muted ? 'm' : '='
, roundui(realvol*100) );
if(len_add > 0) if(len_add > 0)
len += len_add; len += len_add;
} }

View File

@ -1,7 +1,7 @@
/* /*
common: anything can happen here... frame reading, output, messages common: anything can happen here... frame reading, output, messages
copyright ?-2006 by the mpg123 project - free software under the terms of the LGPL 2.1 copyright ?-2020 by the mpg123 project - free software under the terms of the LGPL 2.1
see COPYING and AUTHORS files in distribution or http://mpg123.org see COPYING and AUTHORS files in distribution or http://mpg123.org
initially written by Michael Hipp initially written by Michael Hipp
*/ */
@ -14,6 +14,7 @@
extern int stopped; extern int stopped;
extern int paused; extern int paused;
extern int muted;
/* Return non-zero if full terminal fun is desired/possible. */ /* Return non-zero if full terminal fun is desired/possible. */
int term_have_fun(int fd, struct parameter *param); int term_have_fun(int fd, struct parameter *param);

View File

@ -513,6 +513,18 @@ int control_generic (mpg123_handle *fr)
continue; continue;
} }
if(!strcasecmp(comstr, "MUTE")) {
set_mute(ao, muted=TRUE);
generic_sendmsg("mute");
continue;
}
if(!strcasecmp(comstr, "UNMUTE")) {
set_mute(ao, muted=FALSE);
generic_sendmsg("unmute");
continue;
}
if(!strcasecmp(comstr, "T") || !strcasecmp(comstr, "TAG")) { if(!strcasecmp(comstr, "T") || !strcasecmp(comstr, "TAG")) {
generic_sendalltag(fr); generic_sendalltag(fr);
continue; continue;
@ -594,6 +606,8 @@ int control_generic (mpg123_handle *fr)
generic_sendmsg("H STOP/S: stop playback (closes file)"); generic_sendmsg("H STOP/S: stop playback (closes file)");
generic_sendmsg("H JUMP/J <frame>|<+offset>|<-offset>|<[+|-]seconds>s: jump to mpeg frame <frame> or change position by offset, same in seconds if number followed by \"s\""); generic_sendmsg("H JUMP/J <frame>|<+offset>|<-offset>|<[+|-]seconds>s: jump to mpeg frame <frame> or change position by offset, same in seconds if number followed by \"s\"");
generic_sendmsg("H VOLUME/V <percent>: set volume in % (0..100...); float value"); generic_sendmsg("H VOLUME/V <percent>: set volume in % (0..100...); float value");
generic_sendmsg("H MUTE: turn on software mute in output");
generic_sendmsg("H UNMUTE: turn off software mute in output");
generic_sendmsg("H RVA off|(mix|radio)|(album|audiophile): set rva mode"); generic_sendmsg("H RVA off|(mix|radio)|(album|audiophile): set rva mode");
generic_sendmsg("H EQ/E <channel> <band> <value>: set equalizer value for frequency band 0 to 31 on channel %i (left) or %i (right) or %i (both)", MPG123_LEFT, MPG123_RIGHT, MPG123_LR); generic_sendmsg("H EQ/E <channel> <band> <value>: set equalizer value for frequency band 0 to 31 on channel %i (left) or %i (right) or %i (both)", MPG123_LEFT, MPG123_RIGHT, MPG123_LR);
generic_sendmsg("H EQFILE <filename>: load EQ settings from a file"); generic_sendmsg("H EQFILE <filename>: load EQ settings from a file");

View File

@ -100,8 +100,8 @@ enum mpg123_enc_enum
*/ */
#define MPG123_SAMPLESIZE(enc) ( \ #define MPG123_SAMPLESIZE(enc) ( \
(enc) < 1 \ (enc) < 1 \
? 0 \ ? 0 \
: ( (enc) & MPG123_ENC_8 \ : ( (enc) & MPG123_ENC_8 \
? 1 \ ? 1 \
: ( (enc) & MPG123_ENC_16 \ : ( (enc) & MPG123_ENC_16 \
? 2 \ ? 2 \
@ -115,6 +115,28 @@ enum mpg123_enc_enum
: 0 \ : 0 \
) ) ) ) ) ) ) ) ) ) ) )
/** Representation of zero in differing encodings.
* This exists to define proper silence in various encodings without
* having to link to libsyn123 to do actual conversions at runtime.
* You have to handle big/little endian order yourself, though.
* This takes the shortcut that any signed encoding has a zero with
* all-zero bits. Unsigned linear encodings just have the highest bit set
* (2^(n-1) for n bits), while the nonlinear 8-bit ones are special.
* \param enc the encoding (mpg123_enc_enum value)
* \param siz bytes per sample (return value of MPG123_SAMPLESIZE(enc))
* \param off byte (octet) offset counted from LSB
* \return unsigned byte value for the designated octet
*/
#define MPG123_ZEROSAMPLE(enc, siz, off) ( \
(enc) == MPG123_ENC_ULAW_8 \
? (off == 0 ? 0xff : 0x00) \
: ( (enc) == MPG123_ENC_ALAW_8 \
? (off == 0 ? 0xd5 : 0x00) \
: ( (((enc) & (MPG123_ENC_SIGNED|MPG123_ENC_FLOAT)) || (siz) != ((off)+1)) \
? 0x00 \
: 0x80 \
) ) )
/** Structure defining an audio format. /** Structure defining an audio format.
* Providing the members as individual function arguments to define a certain * Providing the members as individual function arguments to define a certain
* output format is easy enough. This struct makes is more comfortable to deal * output format is easy enough. This struct makes is more comfortable to deal

View File

@ -95,6 +95,7 @@ out123_handle* attribute_align_arg out123_new(void)
ao->channels = -1; ao->channels = -1;
ao->format = -1; ao->format = -1;
ao->framesize = 0; ao->framesize = 0;
memset(ao->zerosample, 0, 8);
ao->state = play_dead; ao->state = play_dead;
ao->auxflags = 0; ao->auxflags = 0;
ao->preload = 0.; ao->preload = 0.;
@ -220,6 +221,12 @@ out123_param( out123_handle *ao, enum out123_parms code
case OUT123_FLAGS: case OUT123_FLAGS:
ao->flags = (int)value; ao->flags = (int)value;
break; break;
case OUT123_ADD_FLAGS:
ao->flags |= (int)value;
break;
case OUT123_REMOVE_FLAGS:
ao->flags &= ~((int)value);
break;
case OUT123_PRELOAD: case OUT123_PRELOAD:
ao->preload = fvalue; ao->preload = fvalue;
break; break;
@ -279,6 +286,7 @@ out123_getparam( out123_handle *ao, enum out123_parms code
switch(code) switch(code)
{ {
case OUT123_FLAGS: case OUT123_FLAGS:
case OUT123_ADD_FLAGS:
value = ao->flags; value = ao->flags;
break; break;
case OUT123_PRELOAD: case OUT123_PRELOAD:
@ -528,7 +536,16 @@ out123_start(out123_handle *ao, long rate, int channels, int encoding)
ao->rate = rate; ao->rate = rate;
ao->channels = channels; ao->channels = channels;
ao->format = encoding; ao->format = encoding;
ao->framesize = out123_encsize(encoding)*channels; int samplesize = out123_encsize(encoding);
ao->framesize = samplesize*channels;
// The most convoluted way to say nothing at all.
for(int i=0; i<samplesize; ++i)
#ifdef WORDS_BIGENDIAN
ao->zerosample[samplesize-1-i] =
#else
ao->zerosample[i] =
#endif
MPG123_ZEROSAMPLE(ao->format, samplesize, i);
#ifndef NOXFERMEM #ifndef NOXFERMEM
if(have_buffer(ao)) if(have_buffer(ao))
@ -617,6 +634,30 @@ void attribute_align_arg out123_stop(out123_handle *ao)
ao->state = play_stopped; ao->state = play_stopped;
} }
// Replace the data in a given block of audio data with zeroes
// in the correct encoding.
static void mute_block( unsigned char *bytes, int count
, unsigned char* zerosample, int samplesize )
{
// The count is expected to be a multiple of samplesize,
// this is just to ensure that the loop ends properly, should be noop.
count -= count % samplesize;
if(!count)
return;
// Initialize with one zero sample, then multiply that
// to eventually cover the whole buffer.
memcpy(bytes, zerosample, samplesize);
int offset = samplesize;
count -= samplesize;
while(count)
{
int block = offset > count ? count : offset;
memcpy(bytes+offset, bytes, block);
offset += block;
count -= block;
}
}
size_t attribute_align_arg size_t attribute_align_arg
out123_play(out123_handle *ao, void *bytes, size_t count) out123_play(out123_handle *ao, void *bytes, size_t count)
{ {
@ -649,25 +690,29 @@ out123_play(out123_handle *ao, void *bytes, size_t count)
return buffer_write(ao, bytes, count); return buffer_write(ao, bytes, count);
else else
#endif #endif
do /* Playback in a loop to be able to continue after interruptions. */
{ {
errno = 0; if(ao->flags & OUT123_MUTE)
int block = count > INT_MAX ? INT_MAX : count; mute_block( bytes, count, ao->zerosample
written = ao->write(ao, (unsigned char*)bytes, block); , MPG123_SAMPLESIZE(ao->format) );
debug4( "written: %d errno: %i (%s), keep_on=%d" do /* Playback in a loop to be able to continue after interruptions. */
, written, errno, strerror(errno)
, ao->flags & OUT123_KEEP_PLAYING );
if(written > 0){ sum+=written; count -= written; }
if(written < block && errno != EINTR)
{ {
ao->errcode = OUT123_DEV_PLAY; errno = 0;
if(!AOQUIET) int block = count > INT_MAX ? INT_MAX : count;
error1("Error in writing audio (%s?)!", strerror(errno)); written = ao->write(ao, bytes, block);
/* This is a serious issue ending this playback round. */ debug4( "written: %d errno: %i (%s), keep_on=%d"
break; , written, errno, strerror(errno)
} , ao->flags & OUT123_KEEP_PLAYING );
} while(count && ao->flags & OUT123_KEEP_PLAYING); if(written > 0){ sum+=written; count -= written; }
if(written < block && errno != EINTR)
{
ao->errcode = OUT123_DEV_PLAY;
if(!AOQUIET)
error1("Error in writing audio (%s?)!", strerror(errno));
/* This is a serious issue ending this playback round. */
break;
}
} while(count && ao->flags & OUT123_KEEP_PLAYING);
}
debug3( "out123_play(%p, %p, ...) = %"SIZE_P debug3( "out123_play(%p, %p, ...) = %"SIZE_P
, (void*)ao, bytes, (size_p)sum ); , (void*)ao, bytes, (size_p)sum );
return sum; return sum;

View File

@ -117,6 +117,8 @@ enum out123_parms
* (e.g. ../lib/mpg123 or ./plugins). The environment variable MPG123_MODDIR * (e.g. ../lib/mpg123 or ./plugins). The environment variable MPG123_MODDIR
* is always tried first and the in-built installation path last. * is always tried first and the in-built installation path last.
*/ */
, OUT123_ADD_FLAGS /**< enable given flags */
, OUT123_REMOVE_FLAGS /**< disable diven flags */
}; };
/** Flags to tune out123 behaviour */ /** Flags to tune out123 behaviour */
@ -125,8 +127,8 @@ enum out123_flags
OUT123_HEADPHONES = 0x01 /**< output to headphones (if supported) */ OUT123_HEADPHONES = 0x01 /**< output to headphones (if supported) */
, OUT123_INTERNAL_SPEAKER = 0x02 /**< output to speaker (if supported) */ , OUT123_INTERNAL_SPEAKER = 0x02 /**< output to speaker (if supported) */
, OUT123_LINE_OUT = 0x04 /**< output to line out (if supported) */ , OUT123_LINE_OUT = 0x04 /**< output to line out (if supported) */
, OUT123_QUIET = 0x08 /**< no printouts to standard error */ , OUT123_QUIET = 0x08 /**< no printouts to standard error */
, OUT123_KEEP_PLAYING = 0x10 /**< , OUT123_KEEP_PLAYING = 0x10 /**<
* When this is set (default), playback continues in a loop when the device * When this is set (default), playback continues in a loop when the device
* does not consume all given data at once. This happens when encountering * does not consume all given data at once. This happens when encountering
* signals (like SIGSTOP, SIGCONT) that cause interruption of the underlying * signals (like SIGSTOP, SIGCONT) that cause interruption of the underlying
@ -136,6 +138,7 @@ enum out123_flags
* over the data given to it via out123_play(), unless a communication error * over the data given to it via out123_play(), unless a communication error
* arises. * arises.
*/ */
, OUT123_MUTE = 0x20 /**< software mute (play silent audio) */
}; };
/** Read-only output driver/device property flags (OUT123_PROPFLAGS). */ /** Read-only output driver/device property flags (OUT123_PROPFLAGS). */
@ -510,7 +513,7 @@ void out123_stop(out123_handle *ao);
* Also note that it is no accident that the buffer parameter is not marked * Also note that it is no accident that the buffer parameter is not marked
* as constant. Some output drivers might need to do things like swap * as constant. Some output drivers might need to do things like swap
* byte order. This is done in-place instead of wasting memory on yet * byte order. This is done in-place instead of wasting memory on yet
* another copy. * another copy. Software muting also overwrites the data.
* \param ao handle * \param ao handle
* \param buffer pointer to raw audio data to be played * \param buffer pointer to raw audio data to be played
* \param bytes number of bytes to read from the buffer * \param bytes number of bytes to read from the buffer

View File

@ -83,6 +83,7 @@ struct out123_struct
int channels; /* number of channels */ int channels; /* number of channels */
int format; /* encoding (TODO: rename this to "encoding"!) */ int format; /* encoding (TODO: rename this to "encoding"!) */
int framesize; /* Output needs data in chunks of framesize bytes. */ int framesize; /* Output needs data in chunks of framesize bytes. */
char zerosample[8]; /* Zero in current encoding, max 64 bit. */
enum playstate state; /* ... */ enum playstate state; /* ... */
int auxflags; /* For now just one: quiet mode (for probing). */ int auxflags; /* For now just one: quiet mode (for probing). */
int propflags; /* Property flags, set by driver. */ int propflags; /* Property flags, set by driver. */

View File

@ -49,17 +49,18 @@ struct keydef term_help[] =
,{ MPG123_FINE_REWIND_KEY, 0, "fine rewind" } ,{ MPG123_FINE_REWIND_KEY, 0, "fine rewind" }
,{ MPG123_VOL_UP_KEY, 0, "volume up" } ,{ MPG123_VOL_UP_KEY, 0, "volume up" }
,{ MPG123_VOL_DOWN_KEY, 0, "volume down" } ,{ MPG123_VOL_DOWN_KEY, 0, "volume down" }
,{ MPG123_VOL_MUTE_KEY, 0, "(un)mute volume" }
,{ MPG123_RVA_KEY, 0, "RVA switch" } ,{ MPG123_RVA_KEY, 0, "RVA switch" }
,{ MPG123_VERBOSE_KEY, 0, "verbose switch" } ,{ MPG123_VERBOSE_KEY, 0, "verbose switch" }
,{ MPG123_PLAYLIST_KEY, 0, "list current playlist, indicating current track there" } ,{ MPG123_PLAYLIST_KEY, 0, "list current playlist, indicating current track there" }
,{ MPG123_TAG_KEY, 0, "display tag info (again)" } ,{ MPG123_TAG_KEY, 0, "display tag info (again)" }
,{ MPG123_MPEG_KEY, 0, "print MPEG header info (again)" } ,{ MPG123_MPEG_KEY, 0, "print MPEG header info (again)" }
,{ MPG123_HELP_KEY, 0, "this help" }
,{ MPG123_QUIT_KEY, 0, "quit" }
,{ MPG123_PITCH_UP_KEY, MPG123_PITCH_BUP_KEY, "pitch up (small step, big step)" } ,{ MPG123_PITCH_UP_KEY, MPG123_PITCH_BUP_KEY, "pitch up (small step, big step)" }
,{ MPG123_PITCH_DOWN_KEY, MPG123_PITCH_BDOWN_KEY, "pitch down (small step, big step)" } ,{ MPG123_PITCH_DOWN_KEY, MPG123_PITCH_BDOWN_KEY, "pitch down (small step, big step)" }
,{ MPG123_PITCH_ZERO_KEY, 0, "reset pitch to zero" } ,{ MPG123_PITCH_ZERO_KEY, 0, "reset pitch to zero" }
,{ MPG123_BOOKMARK_KEY, 0, "print out current position in playlist and track, for the benefit of some external tool to store bookmarks" } ,{ MPG123_BOOKMARK_KEY, 0, "print out current position in playlist and track, for the benefit of some external tool to store bookmarks" }
,{ MPG123_HELP_KEY, 0, "this help" }
,{ MPG123_QUIT_KEY, 0, "quit" }
}; };
void term_sigcont(int sig); void term_sigcont(int sig);
@ -386,6 +387,9 @@ static void term_handle_key(mpg123_handle *fr, out123_handle *ao, char val)
case MPG123_VOL_DOWN_KEY: case MPG123_VOL_DOWN_KEY:
mpg123_volume_change(fr, -0.02); mpg123_volume_change(fr, -0.02);
break; break;
case MPG123_VOL_MUTE_KEY:
set_mute(ao, muted=!muted);
break;
case MPG123_PITCH_UP_KEY: case MPG123_PITCH_UP_KEY:
case MPG123_PITCH_BUP_KEY: case MPG123_PITCH_BUP_KEY:
case MPG123_PITCH_DOWN_KEY: case MPG123_PITCH_DOWN_KEY:

View File

@ -46,6 +46,7 @@
#define MPG123_VOL_UP_KEY '+' #define MPG123_VOL_UP_KEY '+'
#define MPG123_VOL_DOWN_KEY '-' #define MPG123_VOL_DOWN_KEY '-'
#define MPG123_VOL_MUTE_KEY 'u'
#define MPG123_VERBOSE_KEY 'v' #define MPG123_VERBOSE_KEY 'v'
#define MPG123_RVA_KEY 'r' #define MPG123_RVA_KEY 'r'
#define MPG123_PLAYLIST_KEY 'l' #define MPG123_PLAYLIST_KEY 'l'