ref: d0ab0542497b5523234cca504c710ca8dc1c4723
parent: e5059c2f7f5999f15c9282beb93f525860c2e3ac
author: robs <robs>
date: Mon May 14 14:57:29 EDT 2007
Allow simpler synth commands; null pointer idiom for format drivers.
--- a/sox.1
+++ b/sox.1
@@ -105,8 +105,7 @@
.EE
plays a collection of audio files whilst applying a bass boosting effect,
.EX
- play -c4 -n -c1 synth sin %-12 sin %-9 sin %-5 sin %-2 \(rs
- vol 0.7 mixer fade q 0.1 1 0.1
+ play -n -c1 synth sin %-12 sin %-9 sin %-5 sin %-2 fade q 0.1 1 0.1
.EE
plays a synthesised `A minor seventh' chord with a pipe-organ sound,
.EX
@@ -417,9 +416,9 @@
and is useful mainly with effects that produce information about the
audio instead of affecting it (such as \fBnoiseprof\fR or \fBstat\fR).
.SP
-The number of channels and the sampling rate associated with a null file
-are by default 2 and 44\*d1\ kHz respectively, but, as with a normal
-file, these can be overridden if desired using command-line format
+The sampling rate associated with a null file
+is by default 44\*d1\ kHz, but, as with a normal
+file, this can be overridden if desired using command-line format
options (see below).
.SP
One other use of \fB\-n\fR is to use it in conjunction with
--- a/soxeffect.7
+++ b/soxeffect.7
@@ -929,13 +929,13 @@
effect that can has an associated length).
.SP
For example, the following produces a 3 second, 44\*d1\ kHz,
-stereo audio file containing a sine-wave swept from 300 to 3300\ Hz:
+audio file containing a sine-wave swept from 300 to 3300\ Hz:
.EX
sox -n output.au synth 3 sine 300-3300
.EE
-and this produces an 8\ kHz mono version:
+and this produces an 8\ kHz version:
.EX
- sox -r 8000 -c 1 -n output.au synth 3 sine 300-3300
+ sox -r 8000 -n output.au synth 3 sine 300-3300
.EE
Multiple channels can be synthesised by specifying the set of
parameters shown between braces multiple times;
--- a/src/auto.c
+++ b/src/auto.c
@@ -184,7 +184,7 @@
sox_debug("Detected file format type: %s", type);
set_endianness_if_not_already_set(ft);
- return (* ft->h->startread)(ft);
+ return ft->h->startread? (* ft->h->startread)(ft) : SOX_SUCCESS;
}
static int sox_autostartwrite(ft_t ft)
--- a/src/flac.c
+++ b/src/flac.c
@@ -367,6 +367,7 @@
/* FIXME: FLAC should not need to know about this oddity */
if (format->signal.encoding < SOX_ENCODING_SIZE_IS_WORD)
format->signal.size = SOX_SIZE_16BIT;
+ format->signal.encoding = SOX_ENCODING_FLAC;
encoder->bits_per_sample = (format->signal.size > 4 ? 4 : format->signal.size) << 3;
--- a/src/nulfile.c
+++ b/src/nulfile.c
@@ -1,35 +1,45 @@
/*
- * July 5, 1991
- * Copyright 1991 Lance Norskog And Sundry Contributors
- * This source code is freely redistributable and may be used for
- * any purpose. This copyright notice must be maintained.
- * Lance Norskog And Sundry Contributors are not responsible for
- * the consequences of using this software.
+ * File format: null (c) 2006-7 SoX contributers
+ * Based on an original idea by Carsten Borchardt
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This library 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 Lesser
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, write to the Free Software Foundation,
+ * Fifth Floor, 51 Franklin Street, Boston, MA 02111-1301, USA.
*/
-/*
- * libSoX null file format driver.
- * Written by Carsten Borchardt
- * The author is not responsible for the consequences
- * of using this software
- */
-
#include "sox_i.h"
#include <string.h>
-static int sox_nulstartread(ft_t ft)
+static int startread(ft_t ft)
{
/* If format parameters are not given, set somewhat arbitrary
* (but commonly used) defaults: */
- if (ft->signal.rate == 0) ft->signal.rate = 44100;
- if (ft->signal.channels == 0) ft->signal.channels = 2;
- if (ft->signal.size ==-1) ft->signal.size = SOX_SIZE_16BIT;
- if (ft->signal.encoding == SOX_ENCODING_UNKNOWN) ft->signal.encoding = SOX_ENCODING_SIGN2;
-
+ if (!ft->signal.rate) {
+ ft->signal.rate = 44100;
+ sox_report("sample rate not specified; using %i", ft->signal.rate);
+ }
+ if (ft->signal.size <= 0) {
+ ft->signal.size = SOX_SIZE_16BIT;
+ sox_report("precision not specified; using %s", sox_size_bits_str[ft->signal.size]);
+ }
+ if (ft->signal.encoding == SOX_ENCODING_UNKNOWN) {
+ ft->signal.encoding = SOX_ENCODING_SIGN2;
+ sox_report("encoding not specified; using %s", sox_encodings_str[ft->signal.encoding]);
+ }
return SOX_SUCCESS;
}
-static sox_size_t sox_nulread(ft_t ft UNUSED, sox_ssample_t *buf, sox_size_t len)
+static sox_size_t read(ft_t ft UNUSED, sox_ssample_t *buf, sox_size_t len)
{
/* Reading from null generates silence i.e. (sox_sample_t)0. */
memset(buf, 0, sizeof(sox_ssample_t) * len);
@@ -36,33 +46,20 @@
return len; /* Return number of samples "read". */
}
-static sox_size_t sox_nulwrite(ft_t ft UNUSED, const sox_ssample_t *buf UNUSED, sox_size_t len)
+static sox_size_t write(ft_t ft UNUSED, const sox_ssample_t *buf UNUSED, sox_size_t len)
{
/* Writing to null just discards the samples */
return len; /* Return number of samples "written". */
}
-static const char *nulnames[] = {
- "null",
- "nul", /* For backwards compatibility with scripts that used -t nul. */
- NULL,
-};
-
-static sox_format_t sox_nul_format = {
- nulnames,
- SOX_FILE_DEVICE | SOX_FILE_PHONY | SOX_FILE_NOSTDIO,
- sox_nulstartread,
- sox_nulread,
- sox_format_nothing,
- sox_format_nothing,
- sox_nulwrite,
- sox_format_nothing,
- sox_format_nothing_seek
-};
-
const sox_format_t *sox_nul_format_fn(void);
const sox_format_t *sox_nul_format_fn(void)
{
- return &sox_nul_format;
+ static const char *names[] = { "null", "nul"/* with -t; deprecated*/, NULL};
+ static sox_format_t driver = {
+ names, SOX_FILE_DEVICE | SOX_FILE_PHONY | SOX_FILE_NOSTDIO,
+ startread, read, 0, 0, write, 0, 0
+ };
+ return &driver;
}
--- a/src/skeleff.c
+++ b/src/skeleff.c
@@ -128,7 +128,7 @@
/*
* Effect descriptor.
* If no specific processing is needed for any of
- * the 6 functions, then the function can be deleted
+ * the 6 functions, then the function above can be deleted
* and 0 used in place of the its name below.
*/
static sox_effect_t sox_skel_effect = {
--- a/src/skelform.c
+++ b/src/skelform.c
@@ -206,7 +206,11 @@
NULL
};
-/* Format descriptor */
+/* Format descriptor
+ * If no specific processing is needed for any of
+ * the 7 functions, then the function above can be deleted
+ * and 0 used in place of the its name below.
+ */
static sox_format_t sox_skel_format = {
names,
SOX_FILE_SEEK,
--- a/src/sox.c
+++ b/src/sox.c
@@ -576,6 +576,14 @@
exit(0);
}
+ for (i = 0; i < input_count; i++) {
+ int j;
+ for (j =0; j < nuser_effects && !files[i]->desc->signal.channels; ++j)
+ files[i]->desc->signal.channels = user_efftab[j].ininfo.channels;
+ if (!files[i]->desc->signal.channels)
+ ++files[i]->desc->signal.channels;
+ }
+
if (repeatable_random)
sox_debug("Not reseeding PRNG; randomness is repeatable");
else {
@@ -949,14 +957,20 @@
f->desc->mode == 'r'? "Input File " : "Output File ", f->desc->filename);
if (strcmp(f->desc->filename, "-") == 0 || (f->desc->h->flags & SOX_FILE_DEVICE))
fprintf(stderr, " (%s)", f->desc->h->names[0]);
+ fprintf(stderr, "\n");
- fprintf(stderr, "\n"
- "Sample Size : %s (%s)\n"
- "Sample Encoding: %s\n"
+ if (f->desc->signal.size)
+ fprintf(stderr, "Sample Size : %s (%s)\n",
+ sox_size_bits_str[f->desc->signal.size],
+ sox_sizes_str[f->desc->signal.size]);
+
+ if (f->desc->signal.encoding)
+ fprintf(stderr, "Sample Encoding: %s\n",
+ sox_encodings_str[f->desc->signal.encoding]);
+
+ fprintf(stderr,
"Channels : %u\n"
"Sample Rate : %u\n",
- sox_size_bits_str[f->desc->signal.size], sox_sizes_str[f->desc->signal.size],
- sox_encodings_str[f->desc->signal.encoding],
f->desc->signal.channels,
f->desc->signal.rate);
@@ -969,14 +983,15 @@
ws, "~="[f->desc->signal.rate == 44100],
(double)ws/ f->desc->signal.rate * 44100 / 588);
}
- fprintf(stderr,
- "Endian Type : %s\n"
- "Reverse Nibbles: %s\n"
- "Reverse Bits : %s\n",
- f->desc->signal.size == 1? "N/A" :
- f->desc->signal.reverse_bytes != SOX_IS_BIGENDIAN ? "big" : "little",
- no_yes[f->desc->signal.reverse_nibbles],
- no_yes[f->desc->signal.reverse_bits]);
+ if (f->desc->signal.size > 1)
+ fprintf(stderr, "Endian Type : %s\n",
+ f->desc->signal.reverse_bytes != SOX_IS_BIGENDIAN ? "big" : "little");
+ if (f->desc->signal.size)
+ fprintf(stderr,
+ "Reverse Nibbles: %s\n"
+ "Reverse Bits : %s\n",
+ no_yes[f->desc->signal.reverse_nibbles],
+ no_yes[f->desc->signal.reverse_bits]);
}
if (f->replay_gain != HUGE_VAL)
@@ -1371,6 +1386,8 @@
int effects_mask = 0;
sox_bool need_rate = combiner.rate != ofile->desc->signal.rate;
sox_bool need_chan = combiner.channels != ofile->desc->signal.channels;
+ int user_mchan = -1;
+ sox_size_t channels = combiner.channels;
{ /* Check if we have to add effects to change rate/chans or if the
user has specified effects to do this, in which case, check if
@@ -1386,14 +1403,17 @@
need_rate = sox_false;
++user_rate_effects;
}
+ if (user_efftab[i].h->flags & SOX_EFF_MCHAN)
+ user_mchan = i;
}
if (user_chan_effects > 1) {
sox_fail("Cannot specify multiple effects that change number of channels");
exit(2);
}
- if (user_rate_effects > 1)
- sox_report("Cannot specify multiple effects that change sample rate");
- /* FIXME: exit here or add comment as to why not */
+ if (user_rate_effects > 1) {
+ sox_fail("Cannot specify multiple effects that change sample rate");
+ exit(2);
+ }
}
/* --------- add the effects ------------------------ */
@@ -1401,28 +1421,26 @@
/* efftab[0] is always the input stream and always exists */
neffects = 1;
- /* If reducing channels, it's faster to do so before all other effects: */
- if (need_chan && combiner.channels > ofile->desc->signal.channels) {
- add_default_effect("mixer", &effects_mask);
- need_chan = sox_false;
- }
- /* If reducing rate, it's faster to do so before all other effects
- * (except reducing channels): */
- if (need_rate && combiner.rate > ofile->desc->signal.rate) {
- add_default_effect("resample", &effects_mask);
- need_rate = sox_false;
- }
/* Copy user specified effects into the real efftab */
- for (i = 0; i < nuser_effects; i++) {
- memcpy(&efftab[neffects], &user_efftab[i], sizeof(efftab[0]));
- add_effect(&effects_mask);
+ for (i = 0; i <= nuser_effects; i++) {
+ /* If reducing channels, it's faster to do so before all other effects: */
+ if ((int)i > user_mchan && need_chan && combiner.channels > ofile->desc->signal.channels) {
+ add_default_effect("mixer", &effects_mask);
+ channels = ofile->desc->signal.channels;
+ need_chan = sox_false;
+ }
+ /* If reducing rate, it's faster to do so before all other effects
+ * (except reducing channels): */
+ if (need_rate)
+ if (i == nuser_effects || (channels <= 2 && combiner.rate > ofile->desc->signal.rate)) {
+ add_default_effect("resample", &effects_mask);
+ need_rate = sox_false;
+ }
+ if (i < nuser_effects) {
+ memcpy(&efftab[neffects], &user_efftab[i], sizeof(efftab[0]));
+ add_effect(&effects_mask);
+ }
}
- /* If rate/channels-changing effects are needed but haven't yet been
- * added, then do it here. Change rate before channels because it's
- * faster to change rate on a smaller # of channels and # of channels
- * can not be reduced, only increased, at this point. */
- if (need_rate)
- add_default_effect("resample", &effects_mask);
if (need_chan)
add_default_effect("mixer", &effects_mask);
}
@@ -1467,6 +1485,10 @@
}
for (i = 1; i < neffects; ++i) {
struct sox_effect * e = &efftab[i];
+ if (e->ininfo.channels > 2 && !(e->h->flags & SOX_EFF_MCHAN)) {
+ sox_fail("Sorry, effect '%s' cannot handle multiple channels, and SoX can only help out in the case of 2 channels", e->name);
+ return SOX_EOF;
+ }
sox_report("Effects chain: %-10s %-6s %uHz", e->name,
e->ininfo.channels < 2 ? "mono" :
(e->h->flags & SOX_EFF_MCHAN)? "multi" : "stereo", e->ininfo.rate);
@@ -1633,7 +1655,7 @@
/* I have no input data ? */
if (efftab[e - 1].odone == efftab[e - 1].olen) {
- sox_debug("%s no data to pull to me!", efftab[e].name);
+ sox_debug_more("%s no data to pull to me!", efftab[e].name);
return 0;
}
@@ -1713,7 +1735,7 @@
if (effstatus == SOX_EOF)
return SOX_EOF;
if (done == 0) {
- sox_fail("Effect took & gave no samples!");
+ sox_fail("'%s' effect took & gave no samples!", efftab[e].name);
exit(2);
}
return SOX_SUCCESS;
--- a/src/soxio.c
+++ b/src/soxio.c
@@ -154,7 +154,7 @@
set_endianness_if_not_already_set(ft);
/* Read and write starters can change their formats. */
- if ((*ft->h->startread)(ft) != SOX_SUCCESS)
+ if (ft->h->startread && (*ft->h->startread)(ft) != SOX_SUCCESS)
{
sox_fail("Failed reading `%s': %s", ft->filename, ft->sox_errstr);
goto input_error;
@@ -164,8 +164,8 @@
* This is because libsox usually doesn't set this for mono file
* formats (for historical reasons).
*/
- if (ft->signal.channels == 0)
- ft->signal.channels = 1;
+ if (!(ft->h->flags & SOX_FILE_PHONY) && !ft->signal.channels)
+ ft->signal.channels = 1;
if (sox_checkformat(ft) )
{
@@ -295,7 +295,7 @@
set_endianness_if_not_already_set(ft);
/* Read and write starters can change their formats. */
- if ((*ft->h->startwrite)(ft) != SOX_SUCCESS)
+ if (ft->h->startwrite && (*ft->h->startwrite)(ft) != SOX_SUCCESS)
{
sox_fail("Failed writing %s: %s", ft->filename, ft->sox_errstr);
goto output_error;
@@ -320,13 +320,13 @@
sox_size_t sox_read(ft_t f, sox_ssample_t * buf, sox_size_t len)
{
- sox_size_t actual = (*f->h->read)(f, buf, len);
+ sox_size_t actual = f->h->read? (*f->h->read)(f, buf, len) : 0;
return (actual > len? 0 : actual);
}
sox_size_t sox_write(ft_t ft, const sox_ssample_t *buf, sox_size_t len)
{
- return (*ft->h->write)(ft, buf, len);
+ return ft->h->write? (*ft->h->write)(ft, buf, len) : 0;
}
#define TWIDDLE_BYTE(ub, type) \
@@ -451,9 +451,9 @@
int rc;
if (ft->mode == 'r')
- rc = (*ft->h->stopread)(ft);
+ rc = ft->h->stopread? (*ft->h->stopread)(ft) : SOX_SUCCESS;
else
- rc = (*ft->h->stopwrite)(ft);
+ rc = ft->h->stopwrite? (*ft->h->stopwrite)(ft) : SOX_SUCCESS;
if (!(ft->h->flags & SOX_FILE_NOSTDIO))
fclose(ft->fp);
@@ -467,17 +467,17 @@
return rc;
}
-int sox_seek(ft_t ft, sox_size_t offset, int whence)
-{
- /* FIXME: Implement SOX_SEEK_CUR and SOX_SEEK_END. */
- if (whence != SOX_SEEK_SET)
- return SOX_EOF; /* FIXME: return SOX_EINVAL */
+int sox_seek(ft_t ft, sox_size_t offset, int whence)
+{
+ /* FIXME: Implement SOX_SEEK_CUR and SOX_SEEK_END. */
+ if (whence != SOX_SEEK_SET)
+ return SOX_EOF; /* FIXME: return SOX_EINVAL */
- /* If file is a seekable file and this handler supports seeking,
- * the invoke handlers function.
- */
- if (ft->seekable && (ft->h->flags & SOX_FILE_SEEK))
- return (*ft->h->seek)(ft, offset);
- else
- return SOX_EOF; /* FIXME: return SOX_EBADF */
+ /* If file is a seekable file and this handler supports seeking,
+ * the invoke handlers function.
+ */
+ if (ft->seekable && (ft->h->flags & SOX_FILE_SEEK))
+ return ft->h->seek? (*ft->h->seek)(ft, offset) : SOX_EOF;
+ else
+ return SOX_EOF; /* FIXME: return SOX_EBADF */
}
--- a/src/synth.c
+++ b/src/synth.c
@@ -22,7 +22,7 @@
synth_trapezium,
synth_trapetz = synth_trapezium, /* Deprecated name for trapezium */
synth_exp,
- /* Repetetives above, noises below */
+ /* Tones above, noises below */
synth_whitenoise,
synth_noise = synth_whitenoise, /* Just a handy alias */
synth_pinknoise,
@@ -365,6 +365,16 @@
NUMERIC_PARAMETER(p1, 0, 100)
} while (0);
}
+
+ /* If no channels parameters were given, create one default channel: */
+ if (!synth->number_of_channels) {
+ synth->channels = xmalloc(sizeof(*synth->channels));
+ create_channel(&synth->channels[synth->number_of_channels++]);
+ }
+
+ if (!effp->ininfo.channels)
+ effp->ininfo.channels = synth->number_of_channels;
+
return SOX_SUCCESS;
}
@@ -384,12 +394,6 @@
sox_fail(effp->h->usage);
return SOX_EOF;
}
-
- /* If no channels parameters were given, create one default channel: */
- if (!synth->number_of_channels) {
- synth->channels = xmalloc(sizeof(*synth->channels));
- create_channel(&synth->channels[synth->number_of_channels++]);
- }
/* If too few channel parameters were given, copy channels: */
if (synth->number_of_channels < effp->ininfo.channels) {