ref: 8b4f02ed4de617adb9cab6ebac890882248271f7
parent: 1f3073531aeba93810a671e788e25f3e6428c2a7
author: robs <robs>
date: Fri Dec 22 17:52:19 EST 2006
Added silence padding effect.
--- a/AUTHORS
+++ b/AUTHORS
@@ -90,5 +90,5 @@
Rob Sykes robs@users.sourceforge.net
Bass & treble effects, FLAC support, initial 24bit
support, Octave plotting for filters, new flanger,
- file merging, various small fixes, enchancements
- and clean-ups.
+ file merging, speed via resampling, pad effect,
+ various small fixes, enchancements and clean-ups.
--- a/ChangeLog
+++ b/ChangeLog
@@ -77,6 +77,7 @@
problematic -v option. Use the vol effect instead. (robs)
o Added prompt to overwrite pre-existing output file (unless overridden
with --force). (robs)
+ o Added silence padding effect. (robs)
sox-12.18.2
-----------
--- a/sox.1
+++ b/sox.1
@@ -36,7 +36,7 @@
.SH DESCRIPTION
.I SoX
reads and writes most popular audio formats and can optionally apply
-effects to them; it includes a basic audio synthesiser, and on unix-like
+effects to them; it includes a basic audio synthesiser, and on Unix-like
systems, can play and record audio files.
.P
.I SoX
@@ -61,7 +61,7 @@
that follows.
The second type is `headerless', often called raw data. For a file
of this type, the audio data characteristics are sometimes described by
-the filename extension, sometimes by giving format options on the
+the file-name extension, sometimes by giving format options on the
.I SoX
command line, and otherwise by a combination of the two.
.P
@@ -70,7 +70,7 @@
.TP 10
sample rate
The sample rate in samples per second (or Hz). For example, digital telephony
-tradionally uses a ample rate of 8000Hz; CDs use 44,100Hz.
+traditionally uses a sample rate of 8000Hz; CDs use 44,100Hz.
.TP 10
sample size
The number of bits (or bytes) used to store each sample. Most popular are
@@ -83,7 +83,7 @@
linear, FLAC, etc.
.TP 10
channels
-The number of audio channels contained in the file. 1 (`mono') and 2
+The number of audio channels contained in the file. One (`mono') and two
(`stereo') are widely used.
.P
The term `bit-rate' is sometimes used as an overall measure of an audio
@@ -99,7 +99,7 @@
is wanted, then format options can be used to specify the differences.
.PP
If an output file format does not support the same data type, sample
-rate, or channel count as the input file format, then unless overriden
+rate, or channel count as the input file format, then unless overridden
on the command line, \fISoX\fR will automatically select the closest values
that the format does support.
.P
@@ -112,7 +112,7 @@
otherwise,
.I SoX
will try first using the file header (input files only), and then
-the filename extension to determine the file type.
+the file-name extension to determine the file type.
If the file type cannot be determined, then
.I SoX
will exit with an error.
@@ -148,10 +148,10 @@
other effects, when converting one format to another, and even when
simply playing the audio.
-Playing an audio file often involves resampling, and processing by
+Playing an audio file often involves re-sampling, and processing by
analogue components that can introduce a small DC offset and/or
amplification, all of which can produce distortion if the audio signal
-level was intially too close to the clipping point.
+level was initially too close to the clipping point.
For these reasons, it is usual to make sure that an audio
file's signal level does not exceed around 70% of the maximum (linear)
@@ -233,24 +233,24 @@
.B soxexam(1)
manual page for a more detailed description of
.I SoX
-and futher examples on how to use
+and further examples on how to use
.I SoX
with various file formats and effects.
.PP
.SH OPTIONS
-\fBSpecial Filename Options\fR
+\fBSpecial File-name Options\fR
.br
Each of these options is used in special circumstances in place of a normal
-filename on the command line.
+file-name on the command line.
.TP 10
\fB-\fR
\fISoX\fR can be used in pipeline operations by using the special
-filename `-' which,
-if used in place of input filename, will cause
+file-name `-' which,
+if used in place of input file-name, will cause
.I SoX
will read audio data from stdin,
and which,
-if used in place of output filename, will cause
+if used in place of output file-name, will cause
.I SoX
will send audio data to stdout.
Note that when using this option,
@@ -258,7 +258,7 @@
must also be given.
.TP 10
\fB-n\fR
-This can be used in place of an input or output filename
+This can be used in place of an input or output file-name
to specify that the `null' file type should be used. See
.B null
below for further information.
@@ -333,7 +333,7 @@
.RS
.IP 0
No messages are printed at all; use the exit status to determine
-if an error has ocurred.
+if an error has occurred.
.IP 1
Only error messages are printed. These are generated if
.I SoX
@@ -370,7 +370,7 @@
\fBInput File Options\fR
.br
These options apply to only input files and may only precede input
-filenames on the command line.
+file-names on the command line.
.TP 10
\fB-v \fIvolume\fR
Adjust volume by a factor of \fIvolume\fR.
@@ -416,7 +416,7 @@
multiple rate changing effects, the user can specify which to use as an effect.
If no rate change effect is specified then a default one will be chosen.
.TP 10
-\fB-t \fIfiletype\fR
+\fB-t \fIfile-type\fR
Gives the type of the audio file. This is useful when the
file extension is non-standard or when the type can not be determined by
looking at the header of the file.
@@ -423,7 +423,7 @@
The
.B -t
-option can also be used to override the type implied by an input filename
+option can also be used to override the type implied by an input file-name
extension, but if overriding with a type that has a header,
.I SoX
will exit with an appropriate error message if such a header is not
@@ -484,13 +484,13 @@
\fBOutput File Format Options\fR
.br
These options apply to only the output file and may only precede the output
-filename on the command line.
+file-name on the command line.
.TP 10
\fB--comment \fItext\fR
Specify the comment text to store in the output file header (where
applicable).
.TP 10
-\fB--comment-file \fIfilename\fR
+\fB--comment-file \fIfile-name\fR
Specify a file containing the comment text to store in the output
file header (where applicable).
.TP 10
@@ -502,7 +502,7 @@
use this option for more information.
.SH FILE TYPES
Note: a file type that can be determined
-by filename extension is listed with its name preceded by a dot.
+by file-name extension is listed with its name preceded by a dot.
.PP
.TP 10
.B .8svx
@@ -644,7 +644,7 @@
GSM in
.I SoX
is optional and requires access to an external GSM library. To see
-if there is support for gsm run \fBsox -h\fR
+if there is support for GSM run \fBsox -h\fR
and look for it under the list of supported file formats.
.TP 10
.B .hcom
@@ -657,7 +657,7 @@
to deal with an HCOM file under Unix or DOS.
.TP 10
.B .maud
-An IFF-conformant audio file type, registered by
+An IFF-conforming audio file type, registered by
MS MacroSystem Computer GmbH, published along
with the `Toccata' sound-card on the Amiga.
Allows 8bit linear, 16bit linear, A-Law, u-law
@@ -684,9 +684,9 @@
This is a special file type that can be used when normal
file reading or writing is not needed to use a particular effect.
It is selected by using the
-special filename
+special file-name
.B -n
-in place of an input or output filename.
+in place of an input or output file-name.
Using this file type to input audio is equivalent to
using a normal audio file that contains an infinite amount
@@ -700,7 +700,7 @@
(such as \fBnoiseprof\fR or \fBstat\fR).
The number of channels and the sampling rate associated with a null file
-are by default 2 and 44.1kHz respectively, but these can be overriden
+are by default 2 and 44.1kHz respectively, but these can be overridden
if necessary by using appropriate \fBFormat Options\fR.
One other use of the null file type is to use it in conjunction
@@ -1273,6 +1273,35 @@
Experiment with different threshold values to find the optimal one for your
sample.
.TP 10
+pad {\fIlength\fR[\fI@position\fR]}
+Pad the audio with silence, at the beginning, the end, or any
+specified points through the audio.
+Both
+.I length
+and
+.I position
+can specify a time or, if appended with an `s', a number of samples.
+.I length
+is the amount of silence to insert and
+.I position
+the position in the input audio stream at which to insert it.
+Any number of lengths and positions may be specified, provided that
+a specified position is not less that the previous one.
+.I position
+is optional for the first and last lengths specified and
+if omitted correspond to the beginning and the end of the audio respectively.
+For example:
+
+ pad 1.5 1.5
+
+adds 1.5 seconds of silence padding at each end of the audio, whilst
+
+ pad 4000s@3:00
+
+inserts 4000 samples of silence 3 minutes into the audio.
+If silence is wanted only at the end of the audio, specify either the end
+position or specify a zero-length pad at the start.
+.TP 10
pan \fIdirection\fB
Pan the audio from one channel to another. This is done by
changing the volume of the input channels so that it fades out on one
@@ -1301,7 +1330,7 @@
effect
but is left here for historical reasons.
.TP 10
-pitch \fIshift [ width interpole fade ]\fB
+pitch \fIshift [ width interpolate fade ]\fB
Change the pitch of file without affecting its duration by cross-fading
shifted samples.
.I shift
@@ -1310,7 +1339,7 @@
.I width
of window is in ms. Default width is 20ms. Try 30ms to lower pitch,
and 10ms to raise pitch.
-.I interpole
+.I interpolate
option, can be `cubic' or `linear'. Default is `cubic'. The
.I fade
option, can be `cos', `hamming', `linear' or `trapezoid'.
@@ -1325,8 +1354,8 @@
interpolation, a DSP algorithm. This method is relatively slow and memory intensive.
.br
--w < nut / ham > : select either a Nuttall (~90 dB stopband) or Hamming
-(~43 dB stopband) window. Default is
+-w < nut / ham > : select either a Nuttall (~90 dB stop-band) or Hamming
+(~43 dB stop-band) window. Default is
.I nut.
.br
@@ -1382,16 +1411,16 @@
By default, linear interpolation is used,
with a window width about 45 samples at the lower of the two rates.
-This gives an accuracy of about 16 bits, but insufficient stopband rejection
-in the case that you want to have rolloff greater than about 0.80 of
+This gives an accuracy of about 16 bits, but insufficient stop-band rejection
+in the case that you want to have roll-off greater than about 0.80 of
the Nyquist frequency.
-The \fI-q*\fR options will change the default values for rolloff and beta
+The \fI-q*\fR options will change the default values for roll-off and beta
as well as use quadratic interpolation of filter
coefficients, resulting in about 24 bits precision.
The \fI-qs\fR, \fI-q\fR, or \fI-ql\fR options specify increased accuracy
at the cost of lower execution speed. It is optional to specify
-rolloff and beta parameters when using the \fI-q*\fR options.
+roll-off and beta parameters when using the \fI-q*\fR options.
Following is a table of the reasonable defaults which are built-in to
\fISoX\fR:
@@ -1419,7 +1448,7 @@
\fIrolloff\fR refers to the cut-off frequency of the
low pass filter and is given in terms of the
Nyquist frequency for the lower sample rate. rolloff therefore should
-be something between 0.0 and 1.0, in practice 0.8-0.95. The defaults are
+be something between 0.0 and 1.0, in practise 0.8-0.95. The defaults are
indicated above.
The \fINyquist frequency\fR is equal to (sample rate / 2). Logically,
@@ -1438,10 +1467,10 @@
is, with closer being better. When increasing the sample rate of an
audio file you would not expect to have any frequencies exist that are
past the original Nyquist frequency. Because of resampling properties, it
-is common to have aliasing artefacts created above the old
+is common to have aliasing artifacts created above the old
Nyquist frequency. In that case the \fIrolloff\fR refers to how close
to the original Nyquist frequency to use a highpass filter to remove
-these artefacts, with closer also being better.
+these artifacts, with closer also being better.
The \fIbeta\fR parameter
determines the type of filter window used. Any value greater than 2.0 is
@@ -1449,7 +1478,7 @@
If unspecified, the default is a Kaiser window with beta 16.
In the case of Kaiser window (beta > 2.0), lower betas produce a somewhat
-faster transition from passband to stopband, at the cost of noticeable artifacts.
+faster transition from pass-band to stop-band, at the cost of noticeable artifacts.
A beta of 16 is the default, beta less than 10 is not recommended. If you want
a sharper cutoff, don't use low beta's, use a longer sample window.
A Nuttall window is selected by specifying any 'beta' <= 2, and the
@@ -1459,7 +1488,7 @@
This is the default effect if the two files have different sampling rates.
Default parameters are, as indicated above, Kaiser window of length 45,
-rolloff 0.80, beta 16, linear interpolation.
+roll-off 0.80, beta 16, linear interpolation.
\fBNOTE:\fR \fI-qs\fR is only slightly slower, but more accurate for
16-bit or higher precision.
@@ -1560,7 +1589,7 @@
stat [ \fI-s N\fB ] [\fI-rms\fB ] [\fI-freq\fB ] [ \fI-v\fB ] [ \fI-d\fB ]
Do a statistical check on the input file,
and print results on the standard error file. Audio is passed
-unmodified throught the
+unmodified through the
.I SoX
processing chain.
@@ -1631,7 +1660,7 @@
.TP 10
synth [\fIlen\fR] {[\fItype] [combine\fR] [\fIfreq\fR[\fI-freq2\fR]] [\fIoff\fR] [\fIph\fR] [\fIp1\fR] [\fIp2\fR] [\fIp3\fR]}
This effect can be used to generate fixed or swept frequency audio tones
-with various wave shapes, or to generate wideband noise of various
+with various wave shapes, or to generate wide-band noise of various
`colours'.
Multiple synth effects can be cascaded to produce more complex
waveforms; at each stage it is possible to choose whether the generated
@@ -1669,7 +1698,7 @@
sox -n output.au synth .5 sine 200-500 synth .5 sine fmod 700-100
-Frequencies can also specied in terms of musical semitones relative to
+Frequencies can also specified in terms of musical semitones relative to
`middle A' (440Hz); the following could be used to help tune
a guitar's `low E' string (on a system that supports
\fBalsa\fR):
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -18,7 +18,7 @@
btrworth.h chorus.c compand.c copy.c dcshift.c deemphas.c earwax.c \
echo.c echos.c equalizer.c fade.c FFT.c FFT.h filter.c flanger.c \
highp.c highpass.c lowp.c lowpass.c lua.c lintlib.c mask.c \
- mcompand.c noiseprof.c noisered.c noisered.h pan.c \
+ mcompand.c noiseprof.c noisered.c noisered.h pad.c pan.c \
phaser.c pitch.c polyphas.c rabbit.c rate.c repeat.c resample.c \
reverb.c reverse.c silence.c speed.c stat.c \
stretch.c swap.c synth.c tone.c trim.c vibro.c vol.c
--- a/src/fade.c
+++ b/src/fade.c
@@ -81,8 +81,7 @@
fade->in_stop_str = (char *)xmalloc(strlen(argv[0])+1);
strcpy(fade->in_stop_str,argv[0]);
/* Do a dummy parse to see if it will fail */
- if (st_parsesamples(0, fade->in_stop_str, &fade->in_stop, 't') !=
- ST_SUCCESS)
+ if (st_parsesamples(0, fade->in_stop_str, &fade->in_stop, 't') == NULL)
{
st_fail(st_fade_effect.usage);
return(ST_EOF);
@@ -100,7 +99,7 @@
/* Do a dummy parse to see if it will fail */
if (st_parsesamples(0, fade->out_stop_str,
- &fade->out_stop, 't') != ST_SUCCESS) {
+ &fade->out_stop, 't') == NULL) {
st_fail(st_fade_effect.usage);
return(ST_EOF);
}
@@ -112,7 +111,7 @@
/* Do a dummy parse to see if it will fail */
if (st_parsesamples(0, fade->out_start_str,
- &fade->out_start, 't') != ST_SUCCESS) {
+ &fade->out_start, 't') == NULL) {
st_fail(st_fade_effect.usage);
return(ST_EOF);
}
@@ -133,7 +132,7 @@
/* converting time values to samples */
fade->in_start = 0;
if (st_parsesamples(effp->ininfo.rate, fade->in_stop_str,
- &fade->in_stop, 't') != ST_SUCCESS)
+ &fade->in_stop, 't') == NULL)
{
st_fail(st_fade_effect.usage);
return(ST_EOF);
@@ -145,7 +144,7 @@
{
fade->do_out = 1;
if (st_parsesamples(effp->ininfo.rate, fade->out_stop_str,
- &fade->out_stop, 't') != ST_SUCCESS)
+ &fade->out_stop, 't') == NULL)
{
st_fail(st_fade_effect.usage);
return(ST_EOF);
@@ -155,7 +154,7 @@
if (fade->out_start_str)
{
if (st_parsesamples(effp->ininfo.rate, fade->out_start_str,
- &fade->out_start, 't') != ST_SUCCESS)
+ &fade->out_start, 't') == NULL)
{
st_fail(st_fade_effect.usage);
return(ST_EOF);
--- a/src/handlers.c
+++ b/src/handlers.c
@@ -112,6 +112,7 @@
st_mcompand_effect_fn,
st_noiseprof_effect_fn,
st_noisered_effect_fn,
+ st_pad_effect_fn,
st_pan_effect_fn,
st_phaser_effect_fn,
st_pick_effect_fn,
--- /dev/null
+++ b/src/pad.c
@@ -1,0 +1,135 @@
+/* Sound Tools Effect: Pad With Silence
+ *
+ * (c) 2006 robs@users.sourceforge.net
+ *
+ * See LICENSE file for further copyright information.
+ */
+
+#include "st_i.h"
+#include <string.h>
+
+typedef struct pad
+{
+ int npads; /* Number of pads requested */
+ struct {
+ char * str; /* Comman-line argument to parse for this pad */
+ st_size_t start; /* Start padding when in_pos equals this */
+ st_size_t pad; /* Number of samples to pad */
+ } * pads;
+
+ st_size_t in_pos; /* Number of samples read from the input stream */
+ int pads_pos; /* Number of pads completed so far */
+ st_size_t pad_pos; /* Number of samples through the current pad */
+} * pad_t;
+
+assert_static(sizeof(struct pad) <= ST_MAX_EFFECT_PRIVSIZE,
+ /* else */ pad_PRIVSIZE_too_big);
+
+static int parse(eff_t effp, char **argv, st_rate_t rate)
+{
+ pad_t p = (pad_t) effp->priv;
+ char const * next;
+ int i;
+
+ for (i = 0; i < p->npads; ++i) {
+ if (argv) /* 1st parse only */
+ p->pads[i].str = xstrdup(argv[i]);
+ next = st_parsesamples(rate, p->pads[i].str, &p->pads[i].pad, 't');
+ if (next == NULL) break;
+ if (*next == '\0')
+ p->pads[i].start = i? ST_SIZE_MAX : 0;
+ else {
+ if (*next != '@') break;
+ next = st_parsesamples(rate, next+1, &p->pads[i].start, 't');
+ if (next == NULL || *next != '\0') break;
+ }
+ if (i > 0 && p->pads[i].start <= p->pads[i-1].start) break;
+ }
+ if (i < p->npads) {
+ st_fail(effp->h->usage);
+ return ST_EOF;
+ }
+ return ST_SUCCESS;
+}
+
+static int st_pad_getopts(eff_t effp, int n, char **argv)
+{
+ pad_t p = (pad_t) effp->priv;
+ p->pads = xcalloc(p->npads = n, sizeof(*p->pads));
+ return parse(effp, argv, ST_MAXRATE); /* No rate yet, parse with dummy */
+}
+
+static int st_pad_start(eff_t effp)
+{
+ pad_t p = (pad_t) effp->priv;
+ int i;
+
+ parse(effp, 0, effp->ininfo.rate); /* Re-parse now rate is known */
+ p->in_pos = p->pad_pos = p->pads_pos = 0;
+ for (i = 0; i < p->npads; ++i)
+ if (p->pads[i].pad)
+ return ST_SUCCESS;
+ return ST_EFF_NULL;
+}
+
+static int st_pad_flow(eff_t effp, const st_sample_t * ibuf, st_sample_t * obuf, st_size_t * isamp, st_size_t * osamp)
+{
+ pad_t p = (pad_t) effp->priv;
+ st_size_t c, idone = 0, odone = 0;
+ *isamp /= effp->ininfo.channels;
+ *osamp /= effp->ininfo.channels;
+
+ do {
+ /* Copying: */
+ for (; idone < *isamp && odone < *osamp && !(p->pads_pos != p->npads && p->in_pos == p->pads[p->pads_pos].start); ++idone, ++odone, ++p->in_pos)
+ for (c = 0; c < effp->ininfo.channels; ++c) *obuf++ = *ibuf++;
+
+ /* Padding: */
+ if (p->pads_pos != p->npads && p->in_pos == p->pads[p->pads_pos].start) {
+ for (; odone < *osamp && p->pad_pos < p->pads[p->pads_pos].pad; ++odone, ++p->pad_pos)
+ for (c = 0; c < effp->ininfo.channels; ++c) *obuf++ = 0;
+ if (p->pad_pos == p->pads[p->pads_pos].pad) { /* Move to next pad? */
+ ++p->pads_pos;
+ p->pad_pos = 0;
+ }
+ }
+ } while (idone < *isamp && odone < *osamp);
+
+ *isamp = idone * effp->ininfo.channels;
+ *osamp = odone * effp->ininfo.channels;
+ return ST_SUCCESS;
+}
+
+static int st_pad_drain(eff_t effp, st_sample_t * obuf, st_size_t * osamp)
+{
+ static st_size_t isamp = 0;
+ pad_t p = (pad_t) effp->priv;
+ if (p->pads_pos != p->npads && p->in_pos != p->pads[p->pads_pos].start)
+ p->in_pos = ST_SIZE_MAX; /* Invoke the final pad (with no given start) */
+ return st_pad_flow(effp, 0, obuf, &isamp, osamp);
+}
+
+static int st_pad_stop(eff_t effp)
+{
+ pad_t p = (pad_t) effp->priv;
+ if (p->pads_pos != p->npads)
+ st_warn("Input audio too short; pads not applied: %i",p->npads-p->pads_pos);
+ /* Don't free stuff from getopts; start & stop must be symmetric */
+ return ST_SUCCESS;
+}
+
+static st_effect_t st_pad_effect = {
+ "pad",
+ "Usage: pad {length[@position]}",
+ ST_EFF_MCHAN,
+ st_pad_getopts,
+ st_pad_start,
+ st_pad_flow,
+ st_pad_drain,
+ st_pad_stop
+};
+
+const st_effect_t *st_pad_effect_fn(void)
+{
+ return &st_pad_effect;
+}
--- a/src/play.in
+++ b/src/play.in
@@ -82,9 +82,9 @@
EFFECTs are one or more of the following: avg, band, bandpass, bandreject,
bass, chorus, compand, copy, dcshift, deemph, dither, earwax, echo, echos,
equalizer, fade, filter, flanger, highpass, highp, lowpass, lowp, mask,
-mcompand, noiseprof, noisered, pan, phaser, pick, pitch, polyphase, rabbit,
-rate, repeat, resample, reverb, reverse, silence, speed, stat, stretch,
-swap, synth, treble, trim, vibro, vol.
+mcompand, noiseprof, noisered, pad, pan, phaser, pick, pitch, polyphase,
+rabbit, rate, repeat, resample, reverb, reverse, silence, speed, stat,
+stretch, swap, synth, treble, trim, vibro, vol.
See sox man page for detailed information on supported file types, data
formats, and effect options."
@@ -94,7 +94,7 @@
# loop over arguments
while [ $# -ne 0 ]; do
case "$1" in
- avg|band|bandpass|bandreject|bass|chorus|compand|copy|dcshift|deemph|dither|earwax|echo|echos|equalizer|fade|filter|flanger|highpass|highp|lowpass|lowp|mask|mcompand|noiseprof|noisered|pan|phaser|pick|pitch|polyphase|rabbit|rate|repeat|resample|reverb|reverse|silence|speed|stat|stretch|swap|synth|treble|trim|vibro|vol)
+ avg|band|bandpass|bandreject|bass|chorus|compand|copy|dcshift|deemph|dither|earwax|echo|echos|equalizer|fade|filter|flanger|highpass|highp|lowpass|lowp|mask|mcompand|noiseprof|noisered|pad|pan|phaser|pick|pitch|polyphase|rabbit|rate|repeat|resample|reverb|reverse|silence|speed|stat|stretch|swap|synth|treble|trim|vibro|vol)
effects="$@"
break
;;
--- a/src/silence.c
+++ b/src/silence.c
@@ -121,8 +121,7 @@
strcpy(silence->start_duration_str,argv[0]);
/* Perform a fake parse to do error checking */
if (st_parsesamples(0,silence->start_duration_str,
- &silence->start_duration,'s') !=
- ST_SUCCESS)
+ &silence->start_duration,'s') == NULL)
{
st_fail(st_silence_effect.usage);
return(ST_EOF);
@@ -175,8 +174,7 @@
strcpy(silence->stop_duration_str,argv[0]);
/* Perform a fake parse to do error checking */
if (st_parsesamples(0,silence->stop_duration_str,
- &silence->stop_duration,'s') !=
- ST_SUCCESS)
+ &silence->stop_duration,'s') == NULL)
{
st_fail(st_silence_effect.usage);
return(ST_EOF);
@@ -259,8 +257,7 @@
if (silence->start)
{
if (st_parsesamples(effp->ininfo.rate, silence->start_duration_str,
- &silence->start_duration, 's') !=
- ST_SUCCESS)
+ &silence->start_duration, 's') == NULL)
{
st_fail(st_silence_effect.usage);
return(ST_EOF);
@@ -269,8 +266,7 @@
if (silence->stop)
{
if (st_parsesamples(effp->ininfo.rate,silence->stop_duration_str,
- &silence->stop_duration,'s') !=
- ST_SUCCESS)
+ &silence->stop_duration,'s') == NULL)
{
st_fail(st_silence_effect.usage);
return(ST_EOF);
--- a/src/st.h
+++ b/src/st.h
@@ -401,7 +401,7 @@
int st_updateeffect(eff_t, const st_signalinfo_t *in, const st_signalinfo_t *out, int);
int st_gettype(ft_t, bool);
ft_t st_initformat(void);
-int st_parsesamples(st_rate_t rate, const char *str, st_size_t *samples, char def);
+char const * st_parsesamples(st_rate_t rate, const char *str, st_size_t *samples, char def);
extern char const * st_message_filename;
--- a/src/st_i.h
+++ b/src/st_i.h
@@ -291,6 +291,7 @@
extern const st_effect_t *st_mcompand_effect_fn(void);
extern const st_effect_t *st_noiseprof_effect_fn(void);
extern const st_effect_t *st_noisered_effect_fn(void);
+extern const st_effect_t *st_pad_effect_fn(void);
extern const st_effect_t *st_pan_effect_fn(void);
extern const st_effect_t *st_phaser_effect_fn(void);
extern const st_effect_t *st_pick_effect_fn(void);
--- a/src/synth.c
+++ b/src/synth.c
@@ -279,8 +279,7 @@
synth->length_str = (char *)xmalloc(strlen(argv[argn])+1);
strcpy(synth->length_str,argv[argn]);
/* Do a dummy parse of to see if it will fail */
- if (st_parsesamples(0, synth->length_str, &synth->length, 't') !=
- ST_SUCCESS)
+ if (st_parsesamples(0, synth->length_str, &synth->length, 't') == NULL)
{
st_fail(st_synth_effect.usage);
return (ST_EOF);
@@ -379,7 +378,7 @@
if (synth->length_str)
{
if (st_parsesamples(effp->ininfo.rate, synth->length_str,
- &synth->length, 't') != ST_SUCCESS)
+ &synth->length, 't') == NULL)
{
st_fail(st_synth_effect.usage);
return(ST_EOF);
--- a/src/trim.c
+++ b/src/trim.c
@@ -49,8 +49,7 @@
trim->length_str = (char *)xmalloc(strlen(argv[1])+1);
strcpy(trim->length_str,argv[1]);
/* Do a dummy parse to see if it will fail */
- if (st_parsesamples(0, trim->length_str,
- &trim->length, 't') != ST_SUCCESS)
+ if (st_parsesamples(0, trim->length_str, &trim->length, 't') == NULL)
{
st_fail(st_trim_effect.usage);
return(ST_EOF);
@@ -59,8 +58,7 @@
trim->start_str = (char *)xmalloc(strlen(argv[0])+1);
strcpy(trim->start_str,argv[0]);
/* Do a dummy parse to see if it will fail */
- if (st_parsesamples(0, trim->start_str,
- &trim->start, 't') != ST_SUCCESS)
+ if (st_parsesamples(0, trim->start_str, &trim->start, 't') == NULL)
{
st_fail(st_trim_effect.usage);
return(ST_EOF);
@@ -83,7 +81,7 @@
trim_t trim = (trim_t) effp->priv;
if (st_parsesamples(effp->ininfo.rate, trim->start_str,
- &trim->start, 't') != ST_SUCCESS)
+ &trim->start, 't') == NULL)
{
st_fail(st_trim_effect.usage);
return(ST_EOF);
@@ -94,7 +92,7 @@
if (trim->length_str)
{
if (st_parsesamples(effp->ininfo.rate, trim->length_str,
- &trim->length, 't') != ST_SUCCESS)
+ &trim->length, 't') == NULL)
{
st_fail(st_trim_effect.usage);
return(ST_EOF);
--- a/src/util.c
+++ b/src/util.c
@@ -305,18 +305,31 @@
* treated as an amount of time. This is converted into seconds and
* fraction of seconds and then use the sample rate to calculate
* # of samples.
- * Returns ST_EOF on error.
+ * Returns NULL on error, pointer to next char to parse otherwise.
*/
-int st_parsesamples(st_rate_t rate, const char *str, st_size_t *samples, char def)
+char const * st_parsesamples(st_rate_t rate, const char *str, st_size_t *samples, char def)
{
int found_samples = 0, found_time = 0;
int time = 0;
long long_samples;
float frac = 0;
+ char const * end;
+ char const * pos;
+ bool found_colon, found_dot;
- if (strchr(str, ':') || strchr(str, '.') || str[strlen(str)-1] == 't')
+ for (end = str; *end && strchr("0123456789:.ts", *end); ++end);
+ if (end == str)
+ return NULL;
+
+ pos = strchr(str, ':');
+ found_colon = pos && pos < end;
+
+ pos = strchr(str, '.');
+ found_dot = pos && pos < end;
+
+ if (found_colon || found_dot || *(end-1) == 't')
found_time = 1;
- else if (str[strlen(str)-1] == 's')
+ else if (*(end-1) == 's')
found_samples = 1;
if (found_time || (def == 't' && !found_samples))
@@ -326,7 +339,7 @@
while(1)
{
if (str[0] != '.' && sscanf(str, "%d", &time) != 1)
- return ST_EOF;
+ return NULL;
*samples += time;
while (*str != ':' && *str != '.' && *str != 0)
@@ -343,19 +356,19 @@
if (*str == '.')
{
if (sscanf(str, "%f", &frac) != 1)
- return ST_EOF;
+ return NULL;
}
*samples *= rate;
*samples += (rate * frac) + 0.5;
- return ST_SUCCESS;
+ return end;
}
if (found_samples || (def == 's' && !found_time))
{
if (sscanf(str, "%ld", &long_samples) != 1)
- return ST_EOF;
+ return NULL;
*samples = long_samples;
- return ST_SUCCESS;
+ return end;
}
- return ST_EOF;
+ return NULL;
}
--- a/src/xmalloc.c
+++ b/src/xmalloc.c
@@ -56,3 +56,16 @@
return ptr;
}
+
+/*
+ * Perform a strdup; abort if not possible.
+ */
+char * xstrdup(char const * s)
+{
+ char * ptr = strdup(s);
+
+ if (ptr == NULL)
+ st_fail("out of memory");
+
+ return ptr;
+}
--- a/src/xmalloc.h
+++ b/src/xmalloc.h
@@ -27,5 +27,6 @@
void *xcalloc(size_t nmemb, size_t size);
void *xrealloc(void *ptr, size_t newsize);
+char * xstrdup(char const * s);
#endif