ref: 542cab5f35508e4bd8dd52db069a562f5f86d33a
parent: 226e3a5e7cce21ee4dc0c10a8da84af4473e8adf
parent: c97d3bb141f953c4aa07a4462fe2495a53b0e1c9
author: Ulrich Klauer <ulrich@chirlu.de>
date: Mon Oct 15 23:37:18 EDT 2012
Merge branch 'dot' into master Get the fixes from dot into the master branch.
--- a/ChangeLog
+++ b/ChangeLog
@@ -43,6 +43,36 @@
sox-14.4.1 20xx-xx-xx
----------
+Newly deprecated features (to be removed in future):
+
+ Deprec- Feature [O(ption)] Removal
+ ated in [F(ormat)] [E(ffect)] Replacement due after
+ ------- ---------------------- ---------------------- -------
+ 14.4.1 OpenMP < 3.0 OpenMP >= 3.0 14.4.1
+
+File formats:
+
+ o Fix pipe file-type detection regression. (robs)
+ o MAUD write fixes. [3507927] (Carl Eric Codere and Ulrich Klauer)
+ o Fix crash when seeking within a FLAC file. [3476843] (Eric Wong)
+ o Fix Ogg Vorbis files with certain numbers of channels being
+ truncated. (Ulrich Klauer)
+
+Audio device drivers:
+
+ o Check whether pulseaudio is available before choosing it as
+ default. (robs)
+
+Effects:
+
+ o Restore 8 seconds default for spectrogram, if the input length is
+ not known. (Ulrich Klauer)
+
+Other bug fixes:
+
+ o Fix input length calculation for combine methods other than
+ concatenate. (Ulrich Klauer)
+
sox-14.4.0 2012-03-04
----------
--- a/sox.1
+++ b/sox.1
@@ -1448,7 +1448,7 @@
The following parameters are used with, and have the same meaning for,
several effects:
.TP
-\fIcentre\fR[\fBk\fR]
+\fIcenter\fR[\fBk\fR]
See
.IR frequency .
.TP
@@ -3313,8 +3313,10 @@
which the pitch (and tempo) should be adjusted: greater than 0
increases, less than 0 decreases.
.SP
-By default, the speed change is performed by resampling with the \fBrate\fR
-effect using its default quality/speed. For higher quality or higher speed
+Technically, the speed effect only changes the sample rate information,
+leaving the samples themselves untouched. The \fBrate\fR effect is invoked
+automatically to resample to the output sample rate, using its default
+quality/speed. For higher quality or higher speed
resampling, in addition to the \fBspeed\fR effect, specify
the \fBrate\fR effect with the desired quality option.
.SP
--- a/src/flac.c
+++ b/src/flac.c
@@ -35,9 +35,10 @@
uint64_t total_samples;
/* Decode buffer: */
- FLAC__int32 const * const * decoded_wide_samples;
- unsigned number_of_wide_samples;
- unsigned wide_sample_number;
+ sox_sample_t *req_buffer; /* this may be on the stack */
+ size_t number_of_requested_samples;
+ sox_sample_t *leftover_buf; /* heap */
+ unsigned number_of_leftover_samples;
FLAC__StreamDecoder * decoder;
FLAC__bool eof;
@@ -158,6 +159,11 @@
{
sox_format_t * ft = (sox_format_t *) client_data;
priv_t * p = (priv_t *)ft->priv;
+ sox_sample_t * dst = p->req_buffer;
+ unsigned channel;
+ unsigned nsamples = frame->header.blocksize;
+ unsigned sample = 0;
+ size_t actual = nsamples * p->channels;
(void) flac;
@@ -165,11 +171,47 @@
lsx_fail_errno(ft, SOX_EINVAL, "FLAC ERROR: parameters differ between frame and header");
return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
}
+ if (dst == NULL) {
+ lsx_warn("FLAC ERROR: entered write callback without a buffer (SoX bug)");
+ return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+ }
- /* FIXME: We're skating on thin ice here: buffer may be on the stack! */
- p->decoded_wide_samples = buffer;
- p->number_of_wide_samples = frame->header.blocksize;
- p->wide_sample_number = 0;
+ /* FLAC may give us too much data, prepare the leftover buffer */
+ if (actual > p->number_of_requested_samples) {
+ size_t to_stash = actual - p->number_of_requested_samples;
+
+ p->leftover_buf = lsx_malloc(to_stash * sizeof(sox_sample_t));
+ p->number_of_leftover_samples = to_stash;
+ nsamples = p->number_of_requested_samples / p->channels;
+
+ p->req_buffer += p->number_of_requested_samples;
+ p->number_of_requested_samples = 0;
+ } else {
+ p->req_buffer += actual;
+ p->number_of_requested_samples -= actual;
+ }
+
+leftover_copy:
+
+ for (; sample < nsamples; sample++) {
+ for (channel = 0; channel < p->channels; channel++) {
+ FLAC__int32 d = buffer[channel][sample];
+ switch (p->bits_per_sample) {
+ case 8: *dst++ = SOX_SIGNED_8BIT_TO_SAMPLE(d,); break;
+ case 16: *dst++ = SOX_SIGNED_16BIT_TO_SAMPLE(d,); break;
+ case 24: *dst++ = SOX_SIGNED_24BIT_TO_SAMPLE(d,); break;
+ case 32: *dst++ = SOX_SIGNED_32BIT_TO_SAMPLE(d,); break;
+ }
+ }
+ }
+
+ /* copy into the leftover buffer if we've prepared it */
+ if (sample < frame->header.blocksize) {
+ nsamples = frame->header.blocksize;
+ dst = p->leftover_buf;
+ goto leftover_copy;
+ }
+
return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
}
@@ -224,35 +266,66 @@
static size_t read_samples(sox_format_t * const ft, sox_sample_t * sampleBuffer, size_t const requested)
{
priv_t * p = (priv_t *)ft->priv;
- size_t actual = 0;
+ size_t prev_requested;
if (p->seek_pending) {
p->seek_pending = sox_false;
- p->wide_sample_number = p->number_of_wide_samples = 0;
- if (!FLAC__stream_decoder_seek_absolute(p->decoder, (FLAC__uint64)(p->seek_offset / ft->signal.channels)))
+
+ /* discard leftover decoded data */
+ free(p->leftover_buf);
+ p->leftover_buf = NULL;
+ p->number_of_leftover_samples = 0;
+
+ p->req_buffer = sampleBuffer;
+ p->number_of_requested_samples = requested;
+
+ /* calls decoder_write_callback */
+ if (!FLAC__stream_decoder_seek_absolute(p->decoder, (FLAC__uint64)(p->seek_offset / ft->signal.channels))) {
+ p->req_buffer = NULL;
return 0;
- }
- while (!p->eof && actual < requested) {
- if (p->wide_sample_number >= p->number_of_wide_samples)
- FLAC__stream_decoder_process_single(p->decoder);
- if (p->wide_sample_number >= p->number_of_wide_samples)
- p->eof = sox_true;
- else { /* FIXME: this block should really be inside the decode callback */
- unsigned channel;
+ }
+ } else if (p->number_of_leftover_samples > 0) {
- for (channel = 0; channel < p->channels; channel++, actual++) {
- FLAC__int32 d = p->decoded_wide_samples[channel][p->wide_sample_number];
- switch (p->bits_per_sample) {
- case 8: *sampleBuffer++ = SOX_SIGNED_8BIT_TO_SAMPLE(d,); break;
- case 16: *sampleBuffer++ = SOX_SIGNED_16BIT_TO_SAMPLE(d,); break;
- case 24: *sampleBuffer++ = SOX_SIGNED_24BIT_TO_SAMPLE(d,); break;
- case 32: *sampleBuffer++ = SOX_SIGNED_32BIT_TO_SAMPLE(d,); break;
- }
- }
- ++p->wide_sample_number;
+ /* small request, no need to decode more samples since we have leftovers */
+ if (requested < p->number_of_leftover_samples) {
+ size_t req_bytes = requested * sizeof(sox_sample_t);
+
+ memcpy(sampleBuffer, p->leftover_buf, req_bytes);
+ p->number_of_leftover_samples -= requested;
+ memmove(p->leftover_buf, (char *)p->leftover_buf + req_bytes,
+ (size_t)p->number_of_leftover_samples * sizeof(sox_sample_t));
+ return requested;
}
+
+ /* first, give them all of our leftover data: */
+ memcpy(sampleBuffer, p->leftover_buf,
+ p->number_of_leftover_samples * sizeof(sox_sample_t));
+
+ p->req_buffer = sampleBuffer + p->number_of_leftover_samples;
+ p->number_of_requested_samples = requested - p->number_of_leftover_samples;
+
+ free(p->leftover_buf);
+ p->leftover_buf = NULL;
+ p->number_of_leftover_samples = 0;
+
+ /* continue invoking decoder below */
+ } else {
+ p->req_buffer = sampleBuffer;
+ p->number_of_requested_samples = requested;
}
- return actual;
+
+ /* invoke the decoder, calls decoder_write_callback */
+ while ((prev_requested = p->number_of_requested_samples) && !p->eof) {
+ if (!FLAC__stream_decoder_process_single(p->decoder))
+ break; /* error, but maybe got earlier in the loop, though */
+
+ /* number_of_requested_samples decrements as the decoder progresses */
+ if (p->number_of_requested_samples == prev_requested)
+ p->eof = sox_true;
+ }
+ p->req_buffer = NULL;
+
+ return requested - p->number_of_requested_samples;
}
@@ -263,6 +336,10 @@
if (!FLAC__stream_decoder_finish(p->decoder) && p->eof)
lsx_warn("decoder MD5 checksum mismatch.");
FLAC__stream_decoder_delete(p->decoder);
+
+ free(p->leftover_buf);
+ p->leftover_buf = NULL;
+ p->number_of_leftover_samples = 0;
return SOX_SUCCESS;
}
--- a/src/formats.c
+++ b/src/formats.c
@@ -343,7 +343,7 @@
return SOX_EOF;
}
if (!ft->signal.precision) {
- lsx_fail_errno(ft,SOX_EFMT,"data encoding was not specified");
+ lsx_fail_errno(ft,SOX_EFMT,"data encoding or sample size was not specified");
return SOX_EOF;
}
return SOX_SUCCESS;
--- a/src/maud.c
+++ b/src/maud.c
@@ -2,6 +2,8 @@
*
* supports: mono and stereo, linear, a-law and u-law reading and writing
*
+ * an IFF format; description at http://lclevy.free.fr/amiga/MAUDINFO.TXT
+ *
* Copyright 1998-2006 Chris Bagwell and SoX Contributors
* This source code is freely redistributable and may be used for
* any purpose. This copyright notice must be maintained.
@@ -225,6 +227,11 @@
{
/* All samples are already written out. */
+ priv_t *p = (priv_t*)ft->priv;
+ uint32_t mdat_size; /* MDAT chunk size */
+ mdat_size = p->nsamples * (ft->encoding.bits_per_sample >> 3);
+ lsx_padbytes(ft, (size_t) (mdat_size%2));
+
if (lsx_seeki(ft, (off_t)0, 0) != 0)
{
lsx_fail_errno(ft,errno,"can't rewind output file to rewrite MAUD header");
@@ -235,13 +242,16 @@
return(SOX_SUCCESS);
}
-#define MAUDHEADERSIZE (4+(4+4+32)+(4+4+32)+(4+4))
+#define MAUDHEADERSIZE (4+(4+4+32)+(4+4+19+1)+(4+4))
static void maudwriteheader(sox_format_t * ft)
{
priv_t * p = (priv_t *) ft->priv;
+ uint32_t mdat_size; /* MDAT chunk size */
+ mdat_size = p->nsamples * (ft->encoding.bits_per_sample >> 3);
+
lsx_writes(ft, "FORM");
- lsx_writedw(ft, (p->nsamples* (ft->encoding.bits_per_sample >> 3)) + MAUDHEADERSIZE); /* size of file */
+ lsx_writedw(ft, MAUDHEADERSIZE + mdat_size + mdat_size%2); /* size of file */
lsx_writes(ft, "MAUD"); /* File type */
lsx_writes(ft, "MHDR");
@@ -306,8 +316,9 @@
lsx_writedw(ft, 0); /* reserved */
lsx_writes(ft, "ANNO");
- lsx_writedw(ft, 30); /* length of block */
- lsx_writes(ft, "file create by Sound eXchange ");
+ lsx_writedw(ft, 19); /* length of block */
+ lsx_writes(ft, "file created by SoX");
+ lsx_padbytes(ft, (size_t)1);
lsx_writes(ft, "MDAT");
lsx_writedw(ft, p->nsamples * (ft->encoding.bits_per_sample >> 3)); /* samples in file */
--- a/src/sox.c
+++ b/src/sox.c
@@ -1618,6 +1618,7 @@
/* Report all input files; do this only the 1st time process() is called: */
if (!current_input) for (i = 0; i < input_count; i++)
report_file_info(files[i]);
+ combiner_signal.length = SOX_UNKNOWN_LEN;
} else {
size_t total_channels = 0;
size_t min_channels = SOX_SIZE_MAX;
@@ -1624,7 +1625,7 @@
size_t max_channels = 0;
size_t min_rate = SOX_SIZE_MAX;
size_t max_rate = 0;
- uint64_t total_length = 0, max_length = 0;
+ uint64_t total_length = 0, max_length_ws = 0;
/* Report all input files and gather info on differing rates & numbers of
* channels, and on the resulting output audio length: */
@@ -1635,7 +1636,9 @@
max_channels = max(max_channels, files[i]->ft->signal.channels);
min_rate = min(min_rate , files[i]->ft->signal.rate);
max_rate = max(max_rate , files[i]->ft->signal.rate);
- max_length = max(max_length , files[i]->ft->signal.length);
+ max_length_ws = files[i]->ft->signal.length ?
+ max(max_length_ws, files[i]->ft->signal.length / files[i]->ft->signal.channels) :
+ SOX_UNKNOWN_LEN;
if (total_length != SOX_UNKNOWN_LEN && files[i]->ft->signal.length)
total_length += files[i]->ft->signal.length;
else
@@ -1656,14 +1659,15 @@
if (min_rate != max_rate)
exit(1);
- if (combine_method == sox_concatenate)
- combiner_signal.length = total_length;
- else if (is_parallel(combine_method))
- combiner_signal.length = max_length;
-
/* Store the calculated # of combined channels: */
combiner_signal.channels =
combine_method == sox_merge? total_channels : max_channels;
+
+ if (combine_method == sox_concatenate)
+ combiner_signal.length = total_length;
+ else if (is_parallel(combine_method))
+ combiner_signal.length = max_length_ws != SOX_UNKNOWN_LEN ?
+ max_length_ws * combiner_signal.channels : SOX_UNKNOWN_LEN;
}
} /* calculate_combiner_signal_parameters */
@@ -2536,6 +2540,7 @@
sox_format_handler_t const * handler = sox_find_format(name, sox_false);
if (handler) {
sox_format_t format, * ft = &format;
+ lsx_debug("Looking for a default device: trying format `%s'", name);
memset(ft, 0, sizeof(*ft));
ft->filename = (char *)device_name(name);
ft->priv = lsx_calloc(1, handler->priv_size);
--- a/src/spectrogram.c
+++ b/src/spectrogram.c
@@ -225,7 +225,7 @@
pixels_per_sec = min(5000, p->x_size / duration);
else if (!p->x_size && pixels_per_sec && duration)
p->x_size = min(5000, (int)(pixels_per_sec * duration + .5));
- if (!duration && effp->in_signal.length) {
+ if (!duration && effp->in_signal.length != SOX_UNKNOWN_LEN) {
duration = effp->in_signal.length / (effp->in_signal.rate * effp->in_signal.channels);
duration -= start_time;
if (duration <= 0)
--- a/src/vorbis.c
+++ b/src/vorbis.c
@@ -146,6 +146,7 @@
/* Setup buffer */
vb->buf_len = DEF_BUF_LEN;
+ vb->buf_len -= vb->buf_len % (vi->channels*2); /* 2 bytes per sample */
vb->buf = lsx_calloc(vb->buf_len, sizeof(char));
vb->start = vb->end = 0;