ref: 8534b0efb42887309e80f2fd72d14147be4a5cb3
parent: 53e5c79a161bd7a94bf50f4eca555add41fdf85d
author: robs <robs>
date: Thu Jan 31 14:48:38 EST 2008
Fix [1864216] comments mangled when writing ogg-vorbis
--- a/ChangeLog
+++ b/ChangeLog
@@ -4,6 +4,24 @@
This file contains a list of all changes starting after the release of
sox-11gamma.
+sox-14.0.2 2008-xx-xx
+----------
+
+ File formats:
+
+ Effects:
+
+ Other new features:
+
+ o Command line support for multiple file comments. (robs)
+
+ Bug fixes:
+
+ o Fix [1864216] comments mangled when writing ogg-vorbis. (robs)
+
+ Internal improvements:
+
+
sox-14.0.1 2008-01-29
----------
--- a/configure.ac
+++ b/configure.ac
@@ -1,6 +1,6 @@
dnl Process this file with autoconf to produce a configure script.
-AC_INIT(SoX, 14.0.1, sox-devel@lists.sourceforge.net)
+AC_INIT(SoX, 14.0.2, sox-devel@lists.sourceforge.net)
dnl Find target architecture
AC_CANONICAL_TARGET
--- a/sox.1
+++ b/sox.1
@@ -587,20 +587,6 @@
effect is not specified on the
command line it will be invoked internally with default parameters.
.TP
-\fB\-\-comment \fITEXT\fR
-Specify the comment text to store in the output file header (where
-applicable).
-.SP
-SoX will provide a default comment if this option (or
-.BR \-\-comment\-file )
-is not given; to specify that no comment should be stored in the output file,
-use
-.B "\-\-comment \(dq\(dq" .
-.TP
-\fB\-\-comment\-file \fIFILENAME\fR
-Specify a file containing the comment text to store in the output
-file header (where applicable).
-.TP
\fB\-r, \fB\-\-rate\fR \fIRATE\fR
Gives the sample rate in Hz of the file. To cause the output file to have
a different sample rate than the input file, include this option with
@@ -720,6 +706,23 @@
.SS Output File Format Options
These options apply only to the output file and may precede only the output
filename on the command line.
+.TP
+\fB\-\-add\-comment \fITEXT\fR
+Append a comment in the output file header (where applicable).
+.TP
+\fB\-\-comment \fITEXT\fR
+Specify the comment text to store in the output file header (where
+applicable).
+.SP
+SoX will provide a default comment if this option (or
+.BR \-\-comment\-file )
+is not given; to specify that no comment should be stored in the output file,
+use
+.B "\-\-comment \(dq\(dq" .
+.TP
+\fB\-\-comment\-file \fIFILENAME\fR
+Specify a file containing the comment text to store in the output
+file header (where applicable).
.TP
\fB\-C\fR, \fB\-\-compression\fR \fIFACTOR\fR
The compression factor for variably compressing output file formats. If
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -286,7 +286,7 @@
#end !HAVE_LIBLTDL
endif
-EXTRA_DIST = tests.sh testall.sh tests.bat testall.bat monkey.au monkey.wav sox_sample_test.c amr-wb-test CMakeLists.txt soxstdint.h.cmake soxconfig.h.cmake example1.c
+EXTRA_DIST = tests.sh testall.sh tests.bat testall.bat monkey.au monkey.wav sox_sample_test.c amr-wb-test CMakeLists.txt soxstdint.h.cmake soxconfig.h.cmake example1.c test-comments
all: sox$(EXEEXT) play rec sox_sample_test$(EXEEXT) example1$(EXEEXT)
--- a/src/aiff.c
+++ b/src/aiff.c
@@ -97,7 +97,9 @@
releaseLoopBegin = 0, releaseLoopEnd = 0;
sox_ssize_t seekto = 0;
sox_size_t ssndsize = 0;
+ char *annotation;
char *author;
+ char *comment = NULL;
char *copyright;
char *nametext;
@@ -286,19 +288,25 @@
sox_readb(ft, (unsigned char *)&trash8);
}
else if (strncmp(buf, "ANNO", 4) == 0) {
- rc = textChunk(&(ft->comment), "Annotation:", ft);
- if (rc)
- {
- /* Fail already called in function */
- return(SOX_EOF);
- }
+ rc = textChunk(&annotation, "Annotation:", ft);
+ if (rc)
+ {
+ /* Fail already called in function */
+ return(SOX_EOF);
+ }
+ if (annotation)
+ append_comments(&ft->comments, annotation);
+ free(annotation);
}
else if (strncmp(buf, "COMT", 4) == 0) {
- rc = commentChunk(&(ft->comment), "Comment:", ft);
+ rc = commentChunk(&comment, "Comment:", ft);
if (rc) {
/* Fail already called in function */
return(SOX_EOF);
}
+ if (comment)
+ append_comments(&ft->comments, comment);
+ free(comment);
}
else if (strncmp(buf, "AUTH", 4) == 0) {
/* Author chunk */
@@ -743,6 +751,7 @@
unsigned i;
sox_size_t padded_comment_size = 0, comment_size = 0;
sox_size_t comment_chunk_size = 0;
+ char * comment = cat_comments(ft->comments);
/* MARK and INST chunks */
if (ft->instr.nloops) {
@@ -770,9 +779,9 @@
/* COMT comment chunk -- holds comments text with a timestamp and marker id */
/* We calculate the comment_chunk_size if we will be writing a comment */
- if (ft->comment)
+ if (ft->comments)
{
- comment_size = strlen(ft->comment);
+ comment_size = strlen(comment);
/* Must put an even number of characters out.
* True 68k processors OS's seem to require this.
*/
@@ -789,7 +798,7 @@
sox_writes(ft, "AIFF"); /* File type */
/* Now we write the COMT comment chunk using the precomputed sizes */
- if (ft->comment)
+ if (ft->comments)
{
sox_writes(ft, "COMT");
sox_writedw(ft, comment_chunk_size);
@@ -807,10 +816,11 @@
/* now write the count and the bytes of text */
sox_writew(ft, padded_comment_size);
- sox_writes(ft, ft->comment);
+ sox_writes(ft, comment);
if (comment_size != padded_comment_size)
sox_writes(ft, " ");
}
+ free(comment);
/* COMM chunk -- describes encoding (and #frames) */
sox_writes(ft, "COMM");
--- a/src/au.c
+++ b/src/au.c
@@ -268,7 +268,8 @@
*/
buf[hdr_size] = '\0';
- ft->comment = buf;
+ append_comments(&ft->comments, buf);
+ free(buf);
}
/* Needed for seeking */
ft->length = data_size/ft->signal.size;
@@ -410,6 +411,7 @@
uint32_t channels;
int x;
int comment_size;
+ char * comment = cat_comments(ft->comments);
encoding = sox_ausunencoding(ft->signal.size, ft->signal.encoding);
if (encoding == SUN_ENCODING_UNKNOWN) {
@@ -439,15 +441,9 @@
magic = SUN_MAGIC;
sox_writedw(ft, magic);
- /* Info field is at least 4 bytes. Here I force it to something
- * useful when there is no comments.
- */
- if (ft->comment == NULL)
- ft->comment = xstrdup("SoX");
-
hdr_size = SUN_HDRSIZE;
- comment_size = strlen(ft->comment) + 1; /*+1 = null-term. */
+ comment_size = strlen(comment) + 1; /*+1 = null-term. */
if (comment_size < 4)
comment_size = 4; /* minimum size */
@@ -465,10 +461,11 @@
channels = ft->signal.channels;
sox_writedw(ft, channels);
- sox_writes(ft, ft->comment);
+ sox_writes(ft, comment);
/* Info must be 4 bytes at least and null terminated. */
- x = strlen(ft->comment);
+ x = strlen(comment);
+ free(comment);
for (;x < 3; x++)
sox_writeb(ft, 0);
--- a/src/cdr.c
+++ b/src/cdr.c
@@ -52,7 +52,6 @@
ft->signal.size = SOX_SIZE_16BIT;
ft->signal.encoding = SOX_ENCODING_SIGN2;
ft->signal.channels = 2;
- ft->comment = NULL;
/* Need length for seeking */
if(ft->seekable){
--- a/src/cvsd.c
+++ b/src/cvsd.c
@@ -457,6 +457,7 @@
{
struct cvsdpriv *p = (struct cvsdpriv *) ft->priv;
size_t len;
+ char * comment = cat_comments(ft->comments);
memset(hdr->Filename, 0, sizeof(hdr->Filename));
len = strlen(ft->filename);
@@ -470,11 +471,12 @@
hdr->Srate = p->cvsd_rate/100;
hdr->Days = hdr->Custom1 = hdr->Custom2 = 0;
memset(hdr->Info, 0, sizeof(hdr->Info));
- len = strlen(ft->comment);
+ len = strlen(comment);
if (len >= sizeof(hdr->Info))
len = sizeof(hdr->Info)-1;
- memcpy(hdr->Info, ft->comment, len);
+ memcpy(hdr->Info, comment, len);
memset(hdr->extend, 0, sizeof(hdr->extend));
+ free(comment);
}
/* ---------------------------------------------------------------------- */
--- a/src/flac.c
+++ b/src/flac.c
@@ -83,26 +83,18 @@
decoder->total_samples = metadata->data.stream_info.total_samples;
}
else if (metadata->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) {
- size_t i, comment_size = 0;
+ size_t i;
if (metadata->data.vorbis_comment.num_comments == 0)
return;
- if (ft->comment != NULL) {
- sox_warn("FLAC: multiple Vorbis comment block ignored");
+ if (ft->comments != NULL) {
+ sox_warn("multiple Vorbis comment block ignored");
return;
}
for (i = 0; i < metadata->data.vorbis_comment.num_comments; ++i)
- comment_size += metadata->data.vorbis_comment.comments[i].length + 1;
-
- ft->comment = (char *) xcalloc(comment_size, sizeof(char));
-
- for (i = 0; i < metadata->data.vorbis_comment.num_comments; ++i) {
- strcat(ft->comment, (char const *) metadata->data.vorbis_comment.comments[i].entry);
- if (i != metadata->data.vorbis_comment.num_comments - 1)
- strcat(ft->comment, "\n");
- }
+ append_comment(&ft->comments, (char const *) metadata->data.vorbis_comment.comments[i].entry);
}
}
@@ -231,7 +223,7 @@
Decoder * decoder = (Decoder *) ft->priv;
if (!FLAC__stream_decoder_finish(decoder->flac) && decoder->eof)
- sox_warn("FLAC decoder MD5 checksum mismatch.");
+ sox_warn("decoder MD5 checksum mismatch.");
FLAC__stream_decoder_delete(decoder->flac);
return SOX_SUCCESS;
}
@@ -422,37 +414,22 @@
++encoder->num_metadata;
}
- if (ft->comment != NULL && * ft->comment != '\0') {
+ if (ft->comments) { /* Make the comment structure */
FLAC__StreamMetadata_VorbisComment_Entry entry;
- char * comments, * comment, * end_of_comment;
+ int i;
encoder->metadata[encoder->num_metadata] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT);
-
- /* Check if there is a FIELD=value pair already in the comment; if not, add one */
- if (strchr(ft->comment, '=') == NULL) {
- static const char prepend[] = "COMMENT=";
- comments = xmalloc(strlen(ft->comment) + sizeof(prepend));
- strcpy(comments, prepend);
- strcat(comments, ft->comment);
- }
- else
- comments = strdup(ft->comment);
-
- comment = comments;
-
- do {
- entry.entry = (FLAC__byte *) comment;
- end_of_comment = strchr(comment, '\n');
- if (end_of_comment != NULL) {
- *end_of_comment = '\0';
- comment = end_of_comment + 1;
- }
- entry.length = strlen((char const *) entry.entry);
-
+ for (i = 0; ft->comments[i]; ++i) {
+ static const char prepend[] = "Comment=";
+ char * text = xcalloc(strlen(prepend) + strlen(ft->comments[i]) + 1, sizeof(*text));
+ /* Prepend `Comment=' if no field-name already in the comment */
+ if (!strchr(ft->comments[i], '='))
+ strcpy(text, prepend);
+ entry.entry = (FLAC__byte *) strcat(text, ft->comments[i]);
+ entry.length = strlen(text);
FLAC__metadata_object_vorbiscomment_append_comment(encoder->metadata[encoder->num_metadata], entry, /*copy= */ sox_true);
- } while (end_of_comment != NULL);
-
- free(comments);
+ free(text);
+ }
++encoder->num_metadata;
}
--- a/src/maud.c
+++ b/src/maud.c
@@ -157,8 +157,6 @@
return(SOX_EOF);
}
- ft->comment = 0;
-
continue;
}
--- a/src/sf.c
+++ b/src/sf.c
@@ -32,7 +32,7 @@
*/
static void readcodes(sox_format_t * ft, SFHEADER *sfhead)
{
- char *commentbuf = NULL, *sfcharp, *newline;
+ char *commentbuf = NULL, *sfcharp;
sox_size_t bsize;
sox_bool finished = sox_false;
SFCODE *sfcodep;
@@ -52,16 +52,13 @@
case SF_COMMENT:
commentbuf = (char *) xmalloc(bsize + 1);
memcpy(commentbuf, sfcharp, bsize);
- sox_report("IRCAM comment: %s", sfcharp);
commentbuf[bsize] = '\0';
- if((newline = strchr(commentbuf, '\n')) != NULL)
- *newline = '\0';
break;
}
sfcodep = (SFCODE *) (sfcharp + bsize);
} while(!finished);
- if(commentbuf != NULL) /* handles out of memory condition as well */
- ft->comment = commentbuf;
+ append_comments(&ft->comments, commentbuf);
+ free(commentbuf);
}
static int sox_sfseek(sox_format_t * ft, sox_size_t offset)
@@ -166,6 +163,7 @@
SFCODE *sfcodep;
char *sfcharp;
int rc;
+ char * comment = cat_comments(ft->comments);
/* Needed for rawwrite() */
rc = sox_rawstartwrite(ft);
@@ -201,11 +199,12 @@
memcpy(&sfhead.sfinfo, &sf->info, sizeof(struct sfinfo));
sfcodep = (SFCODE *) (&sfhead.sfinfo + 1);
sfcodep->code = SF_COMMENT;
- sfcodep->bsize = strlen(ft->comment) + sizeof(SFCODE);
+ sfcodep->bsize = strlen(comment) + sizeof(SFCODE);
while (sfcodep->bsize % 4)
sfcodep->bsize++;
sfcharp = (char *) sfcodep;
- strcpy(sfcharp + sizeof(SFCODE), ft->comment);
+ strcpy(sfcharp + sizeof(SFCODE), comment);
+ free(comment);
sfcodep = (SFCODE *) (sfcharp + sfcodep->bsize);
sfcodep->code = SF_END;
sfcodep->bsize = sizeof(SFCODE);
--- a/src/skelform.c
+++ b/src/skelform.c
@@ -62,11 +62,7 @@
ft->signal.size = SOX_SIZE_BYTE; /* or WORD ... */
ft->signal.encoding = SOX_ENCODING_UNSIGNED; /* or SIGN2 ... */
ft->signal.channels = 1; /* or 2 or 4 */
- {
- char *comment = "any comment in file header.";
- ft->comment = xmalloc(sizeof(comment));
- strcpy(ft->comment, comment);
- }
+ append_comment(&ft->comments, "any comment in file header.");
/* If your format doesn't have a header then samples_in_file
* can be determined by the file size.
--- a/src/smp.c
+++ b/src/smp.c
@@ -243,9 +243,8 @@
;
sprintf(smp->comment, "%.*s: %.*s", namelen+1, header.name,
commentlen+1, header.comments);
- ft->comment = smp->comment;
+ append_comments(&ft->comments, smp->comment);
- sox_report("SampleVision file name and comments: %s", ft->comment);
/* Extract out the sample size (always intel format) */
sox_readdw(ft, &(smp->NoOfSamps));
/* mark the start of the sample data */
@@ -336,6 +335,7 @@
{
smp_t smp = (smp_t) ft->priv;
struct smpheader header;
+ char * comment = cat_comments(ft->comments);
/* If you have to seek around the output file */
if (! ft->seekable)
@@ -352,7 +352,8 @@
memcpy(header.Id, SVmagic, sizeof(header.Id));
memcpy(header.version, SVvers, sizeof(header.version));
sprintf(header.comments, "%-*s", COMMENTLEN - 1, "Converted using Sox.");
- sprintf(header.name, "%-*.*s", NAMELEN, NAMELEN, ft->comment);
+ sprintf(header.name, "%-*.*s", NAMELEN, NAMELEN, comment);
+ free(comment);
/* Write file header */
if(sox_writebuf(ft, &header, HEADERSIZE) != HEADERSIZE)
--- a/src/sox.c
+++ b/src/sox.c
@@ -92,7 +92,7 @@
sox_signalinfo_t signal;
double volume;
double replay_gain;
- char const * comment;
+ comments_t comments;
sox_format_t * ft; /* libSoX file descriptor */
sox_size_t volume_clips;
@@ -232,6 +232,7 @@
"",
"-c, --channels CHANNELS number of channels in audio data",
"-C, --compression FACTOR compression factor for output format",
+"--add-comment TEXT Append output file comment",
"--comment TEXT Specify comment text for the output file",
"--comment-file FILENAME file containing comment text for the output file",
"--endian little|big|swap set endianness; swap means opposite to default",
@@ -404,23 +405,21 @@
exit(1);
}
-static void set_replay_gain(char const * comment, file_t f)
+static void set_replay_gain(comments_t comments, file_t f)
{
rg_mode rg = replay_gain_mode;
int try = 2; /* Will try to find the other GAIN if preferred one not found */
+ size_t i, n = num_comments(comments);
if (rg != RG_off) while (try--) {
- char const * p = comment;
char const * target =
rg == RG_track? "REPLAYGAIN_TRACK_GAIN=" : "REPLAYGAIN_ALBUM_GAIN=";
- do {
- if (strncasecmp(p, target, strlen(target)) == 0) {
- f->replay_gain = atof(p + strlen(target));
+ for (i = 0; i < n; ++i) {
+ if (strncasecmp(comments[i], target, strlen(target)) == 0) {
+ f->replay_gain = atof(comments[i] + strlen(target));
return;
}
- while (*p && *p!= '\n') ++p;
- while (*p && strchr("\r\n\t\f ", *p)) ++p;
- } while (*p);
+ }
rg ^= RG_track ^ RG_album;
}
}
@@ -642,12 +641,12 @@
/* Check for misplaced input/output-specific options */
for (i = 0; i < input_count; ++i) {
if (files[i]->signal.compression != HUGE_VAL)
- usage("A compression factor can only be given for an output file");
- if (files[i]->comment != NULL)
- usage("A comment can only be given for an output file");
+ usage("A compression factor can be given only for an output file");
+ if (files[i]->comments != NULL)
+ usage("Comments can be given only for an output file");
}
if (ofile->volume != HUGE_VAL)
- usage("-v can only be given for an input file;\n"
+ usage("-v can be given only for an input file;\n"
"\tuse `vol' to set the output file volume");
signal(SIGINT, SIG_IGN); /* So child pipes aren't killed by track skip */
@@ -680,8 +679,7 @@
(files[j]->ft->handler->flags & SOX_FILE_DEVICE) != 0 &&
(files[j]->ft->handler->flags & SOX_FILE_PHONY) == 0)
show_progress = SOX_OPTION_YES;
- if (files[j]->ft->comment)
- set_replay_gain(files[j]->ft->comment, f);
+ set_replay_gain(files[j]->ft->comments, f);
}
signal(SIGINT, SIG_DFL);
@@ -749,11 +747,11 @@
return 0;
}
-static char * read_comment_file(char const * const filename)
+static void read_comment_file(comments_t * comments, char const * const filename)
{
- sox_bool file_error;
- int file_length = 0;
- char * result;
+ int c;
+ size_t text_length = 100;
+ char * text = xmalloc(text_length + 1);
FILE * file = fopen(filename, "rt");
if (file == NULL) {
@@ -760,26 +758,26 @@
sox_fail("Cannot open comment file %s", filename);
exit(1);
}
- file_error = fseeko(file, (off_t)0, SEEK_END);
- if (!file_error) {
- file_length = ftello(file);
- file_error |= file_length < 0;
- if (!file_error) {
- result = xmalloc((unsigned)file_length + 1);
- rewind(file);
- file_error |= fread(result, (unsigned)file_length, 1, file) != 1;
+ do {
+ size_t i = 0;
+
+ while ((c = getc(file)) != EOF && !strchr("\r\n", c)) {
+ if (i == text_length)
+ text = xrealloc(text, (text_length <<= 1) + 1);
+ text[i++] = c;
}
- }
- if (file_error) {
- sox_fail("Error reading comment file %s", filename);
- exit(1);
- }
- fclose(file);
+ if (ferror(file)) {
+ sox_fail("Error reading comment file %s", filename);
+ exit(1);
+ }
+ if (i) {
+ text[i] = '\0';
+ append_comment(comments, text);
+ }
+ } while (c != EOF);
- while (file_length && result[file_length - 1] == '\n')
- --file_length;
- result[file_length] = '\0';
- return result;
+ fclose(file);
+ free(text);
}
static char *getoptstr = "+abc:defghilmnoqr:st:uv:wxABC:DLMNRSUV::X12348";
@@ -786,6 +784,7 @@
static struct option long_options[] =
{
+ {"add-comment" , required_argument, NULL, 0},
{"buffer" , required_argument, NULL, 0},
{"combine" , required_argument, NULL, 0},
{"comment-file" , required_argument, NULL, 0},
@@ -870,6 +869,11 @@
case 0: /* Long options with no short equivalent. */
switch (option_index) {
case 0:
+ if (optarg)
+ append_comment(&f->comments, optarg);
+ break;
+
+ case 1:
#define SOX_BUFMIN 16
if (sscanf(optarg, "%i %c", &i, &dummy) != 1 || i <= SOX_BUFMIN) {
sox_fail("Buffer size `%s' must be > %d", optarg, SOX_BUFMIN);
@@ -878,19 +882,22 @@
sox_globals.bufsiz = i;
break;
- case 1:
+ case 2:
combine_method = enum_option(option_index, combine_methods);
break;
- case 2:
- f->comment = read_comment_file(optarg);
- break;
-
case 3:
- f->comment = xstrdup(optarg);
+ append_comment(&f->comments, "");
+ read_comment_file(&f->comments, optarg);
break;
case 4:
+ append_comment(&f->comments, "");
+ if (optarg)
+ append_comment(&f->comments, optarg);
+ break;
+
+ case 5:
switch (enum_option(option_index, endian_options)) {
case ENDIAN_little: f->signal.reverse_bytes = SOX_IS_BIGENDIAN; break;
case ENDIAN_big: f->signal.reverse_bytes = SOX_IS_LITTLEENDIAN; break;
@@ -898,23 +905,23 @@
}
break;
- case 5:
+ case 6:
interactive = sox_true;
break;
- case 6:
+ case 7:
usage_effect(optarg);
break;
- case 7:
+ case 8:
sox_effects_globals.plot = enum_option(option_index, plot_methods);
break;
- case 8:
+ case 9:
replay_gain_mode = enum_option(option_index, rg_modes);
break;
- case 9:
+ case 10:
display_SoX_version(stdout);
exit(0);
break;
@@ -1090,11 +1097,14 @@
if (f->volume != HUGE_VAL)
fprintf(stderr, "Level adjust : %g (linear gain)\n" , f->volume);
- if (!(f->ft->handler->flags & SOX_FILE_DEVICE) && f->ft->comment) {
- if (strchr(f->ft->comment, '\n'))
- fprintf(stderr, "Comments : \n%s\n", f->ft->comment);
- else
- fprintf(stderr, "Comment : '%s'\n", f->ft->comment);
+ if (!(f->ft->handler->flags & SOX_FILE_DEVICE) && f->ft->comments) {
+ if (num_comments(f->ft->comments) > 1) {
+ comments_t p = f->ft->comments;
+ fprintf(stderr, "Comments : \n");
+ do fprintf(stderr, "%s\n", *p);
+ while (*++p);
+ }
+ else fprintf(stderr, "Comment : '%s'\n", f->ft->comments[0]);
}
fprintf(stderr, "\n");
}
@@ -1410,12 +1420,19 @@
sox_loopinfo_t loops[SOX_MAX_NLOOPS];
double factor;
int i;
- char const *comment = NULL;
+ comments_t comments = copy_comments(files[0]->ft->comments);
+ comments_t p = ofile->comments;
- if (ofile->comment == NULL)
- comment = files[0]->ft->comment ? files[0]->ft->comment : "Processed by SoX";
- else if (*ofile->comment != '\0')
- comment = ofile->comment;
+ if (!comments && !p)
+ append_comment(&comments, "Processed by SoX");
+ else if (p) {
+ if (!(*p)[0]) {
+ delete_comments(&comments);
+ ++p;
+ }
+ while (*p)
+ append_comment(&comments, *p++);
+ }
/*
* copy loop info, resizing appropriately
@@ -1435,10 +1452,11 @@
ofile->filename,
&ofile->signal,
ofile->filetype,
- comment,
+ comments,
olen,
&files[0]->ft->instr,
loops);
+ delete_comments(&comments);
if (!ofile->ft)
/* sox_open_write() will call sox_warn for most errors.
--- a/src/sox.h
+++ b/src/sox.h
@@ -302,6 +302,8 @@
#define SOX_MAX_FILE_PRIVSIZE 1000
#define SOX_MAX_NLOOPS 8
+typedef char * * comments_t;
+
struct sox_format {
/* Placing priv at the start of this structure ensures that it gets aligned
* in memory in the optimal way for any structure to be cast over it. */
@@ -316,7 +318,7 @@
sox_size_t clips; /* increment if clipping occurs */
char *filename; /* file name */
char *filetype; /* type of file */
- char *comment; /* comment string */
+ comments_t comments; /* comment strings */
FILE *fp; /* File stream pointer */
int sox_errno; /* Failure error codes */
char sox_errstr[256]; /* Extend Failure text */
@@ -361,7 +363,7 @@
const char *path,
const sox_signalinfo_t *info,
const char *filetype,
- const char *comment,
+ comments_t comments,
sox_size_t length,
const sox_instrinfo_t *instr,
const sox_loopinfo_t *loops);
--- a/src/sox_i.h
+++ b/src/sox_i.h
@@ -132,10 +132,13 @@
char *strdup(const char *s);
#endif
+
+
+/*---------------------------- Declared in misc.c ----------------------------*/
+
/* Read and write basic data types from "ft" stream. Uses ft->swap for
* possible byte swapping.
*/
-/* declared in misc.c */
size_t sox_readbuf(sox_format_t * ft, void *buf, sox_size_t len);
int sox_skipbytes(sox_format_t * ft, sox_size_t n);
int sox_padbytes(sox_format_t * ft, sox_size_t n);
@@ -199,7 +202,10 @@
uint32_t sox_swap3(uint32_t udw);
double sox_swapdf(double d);
-/* util.c */
+
+
+/*---------------------------- Declared in util.c ----------------------------*/
+
typedef void (*sox_output_message_handler_t)(unsigned level, const char *filename, const char *fmt, va_list ap);
void sox_output_message(FILE *file, const char *filename, const char *fmt, va_list ap);
@@ -224,6 +230,15 @@
;
#endif
+size_t num_comments(comments_t comments);
+void append_comment(comments_t * comments, char const * comment);
+void append_comments(comments_t * comments, char const * comment);
+comments_t copy_comments(comments_t comments);
+void delete_comments(comments_t * comments);
+char * cat_comments(comments_t comments);
+
+
+
#ifdef WORDS_BIGENDIAN
#define SOX_IS_BIGENDIAN 1
#define SOX_IS_LITTLEENDIAN 0
@@ -274,11 +289,10 @@
extern const char sox_writerr[];
extern uint8_t const cswap[256];
-/*-----------------------------------------------------------------------------
- * File Handlers
- *-----------------------------------------------------------------------------
- */
+
+/*------------------------------ File Handlers -------------------------------*/
+
/* Psion record header check, defined in misc.c and used in prc.c and auto.c */
extern const char prc_header[41];
int prc_checkheader(sox_format_t * ft, char *head);
@@ -315,11 +329,10 @@
#define sox_rawstopread sox_format_nothing
#define sox_rawstopwrite sox_format_nothing
-/*-----------------------------------------------------------------------------
- * Effects
- *-----------------------------------------------------------------------------
- */
+
+/*--------------------------------- Effects ----------------------------------*/
+
int sox_usage(sox_effect_t * effp);
typedef const sox_effect_handler_t *(*sox_effect_fn_t)(void);
extern sox_effect_fn_t sox_effect_fns[];
@@ -359,4 +372,5 @@
sox_sample_t **ibufc, **obufc; /* Channel interleave buffers */
sox_effects_globals_t global_info;
};
+
#endif
--- a/src/soxconfig.h.cmake
+++ b/src/soxconfig.h.cmake
@@ -1,4 +1,4 @@
-#define PACKAGE_VERSION "14.0.1"
+#define PACKAGE_VERSION "14.0.2"
#cmakedefine EXTERNAL_GSM 1
#cmakedefine HAVE_ALSA 1
--- a/src/soxio.c
+++ b/src/soxio.c
@@ -277,7 +277,7 @@
const char *path,
const sox_signalinfo_t *info,
const char *filetype,
- const char *comment,
+ comments_t comments,
sox_size_t length,
const sox_instrinfo_t *instr,
const sox_loopinfo_t *loops)
@@ -347,7 +347,7 @@
ft->seekable = is_seekable(ft);
}
- ft->comment = xstrdup(comment);
+ ft->comments = copy_comments(comments);
if (loops)
for (i = 0; i < SOX_MAX_NLOOPS; i++)
@@ -532,10 +532,7 @@
fclose(ft->fp);
free(ft->filename);
free(ft->filetype);
- /* Currently, since startread() mallocs comments, stopread
- * is expected to also free it. */
- if (ft->mode == 'w')
- free(ft->comment);
+ delete_comments(&ft->comments);
free(ft);
return rc;
--- /dev/null
+++ b/src/test-comments
@@ -1,0 +1,93 @@
+#!/bin/sh -x
+
+tmp=/tmp/`basename $0`-$$
+
+check () {
+ f=$1; shift
+ : > $tmp.expected
+ lines=0
+ while [ $# != 0 ]; do
+ echo "$1" >> $tmp.expected
+ shift
+ lines=`expr $lines + 1`
+ done
+ ./sox -V $f -n 2> $tmp.info
+ if [ $lines -eq 1 ]; then
+ grep "^Comment " $tmp.info|sed "s/[^']*'//"|sed "s/'$//" > $tmp.comments
+ else
+ head -n -1 $tmp.info|tac|head -n -`grep -n ^Comments $tmp.info|sed "s/:.*//"`|tac>$tmp.comments
+ fi
+ cmp $tmp.comments $tmp.expected || exit 1
+}
+
+check_file () {
+ ./sox -V $1 -n 2> $tmp.info
+ head -n -1 $tmp.info|tac|head -n -`grep -n ^Comments $tmp.info|sed "s/:.*//"`|tac>$tmp.comments
+ cmp $tmp.comments $2 || exit 1
+}
+
+com0="Processed by SoX"
+com1="foo bar"
+com2="bar foo"
+
+./sox monkey.au $tmp.au # Apply default comment
+check $tmp.au "$com0"
+
+cp $tmp.au $tmp.comment.au
+
+cat > $tmp.i << .
+TITLE=The First Track
+ARTIST=A Band Of Musicians
+ALBUM=A Collection Of Songs
+DATE=2008
+TRACKNUMBER=01
+TRACKTOTAL=14
+GENRE=Music
+REPLAYGAIN_TRACK_PEAK=1.00515676
+REPLAYGAIN_TRACK_GAIN=-3.97 dB
+REPLAYGAIN_ALBUM_PEAK=1.00515676
+REPLAYGAIN_ALBUM_GAIN=-2.88 dB
+.
+
+./sox monkey.au --comment-file $tmp.i $tmp.comments.au
+check_file $tmp.comments.au $tmp.i
+
+./sox monkey.au --comment= $tmp.au # Don't apply default comment
+check $tmp.au
+
+./sox monkey.au --add-comment "$com1" $tmp.au
+check $tmp.au "$com1"
+
+./sox $tmp.comment.au --add-comment "$com1" $tmp.au
+check $tmp.au "$com0" "$com1"
+
+./sox monkey.au --add-comment "$com1" --add-comment "$com2" $tmp.au
+check $tmp.au "$com1" "$com2"
+
+./sox $tmp.comment.au --add-comment "$com1" --add-comment "$com2" $tmp.au
+check $tmp.au "$com0" "$com1" "$com2"
+
+./sox $tmp.comments.au --comment= $tmp.au
+check $tmp.au
+
+./sox $tmp.comments.au --comment "$com1" $tmp.au
+check $tmp.au "$com1"
+
+./sox $tmp.comments.au --add-comment "$com1" $tmp.au
+cp $tmp.i $tmp.j
+echo "$com1" >> $tmp.j
+check_file $tmp.au $tmp.j
+
+./sox $tmp.comments.au --add-comment "$com1" --add-comment "$com2" $tmp.au
+echo "$com2" >> $tmp.j
+check_file $tmp.au $tmp.j
+
+# FIXME: smp aiff mp3
+./sox $tmp.comments.au $tmp.flac
+./sox $tmp.flac $tmp.sf
+./sox $tmp.sf $tmp.ogg
+./sox $tmp.ogg $tmp.au
+check_file $tmp.au $tmp.i
+
+rm -f $tmp.*
+exit 0
--- a/src/util.c
+++ b/src/util.c
@@ -11,9 +11,11 @@
*/
#include "sox_i.h"
+#include <assert.h>
#include <string.h>
#include <stdarg.h>
+
void sox_output_message(FILE *file, const char *filename, const char *fmt, va_list ap)
{
char const * slash_pos = LAST_SLASH(filename);
@@ -139,4 +141,83 @@
return end;
}
return NULL;
+}
+
+
+
+/*--------------------------------- Comments ---------------------------------*/
+
+size_t num_comments(comments_t comments)
+{
+ size_t result = 0;
+ if (!comments)
+ return 0;
+ while (*comments++)
+ ++result;
+ return result;
+}
+
+void append_comment(comments_t * comments, char const * comment)
+{
+ size_t n = num_comments(*comments);
+ *comments = xrealloc(*comments, (n + 2) * sizeof(**comments));
+ assert(comment);
+ (*comments)[n++] = xstrdup(comment);
+ (*comments)[n] = 0;
+}
+
+void append_comments(comments_t * comments, char const * comment)
+{
+ char * end;
+ if (comment) {
+ while ((end = strchr(comment, '\n'))) {
+ size_t len = end - comment;
+ char * c = xmalloc((len + 1) * sizeof(*c));
+ strncpy(c, comment, len);
+ c[len] = '\0';
+ append_comment(comments, c);
+ comment += len + 1;
+ free(c);
+ }
+ if (*comment)
+ append_comment(comments, comment);
+ }
+}
+
+comments_t copy_comments(comments_t comments)
+{
+ comments_t result = 0;
+
+ if (comments) while (*comments)
+ append_comment(&result, *comments++);
+ return result;
+}
+
+void delete_comments(comments_t * comments)
+{
+ comments_t p = *comments;
+
+ if (p) while (*p)
+ free(*p++);
+ free(*comments);
+ *comments = 0;
+}
+
+char * cat_comments(comments_t comments)
+{
+ comments_t p = comments;
+ size_t len = 0;
+ char * result;
+
+ if (p) while (*p)
+ len += strlen(*p++) + 1;
+
+ result = xcalloc(len? len : 1, sizeof(*result));
+
+ if ((p = comments) && *p) {
+ strcpy(result, *p);
+ while (*++p)
+ strcat(strcat(result, "\n"), *p);
+ }
+ return result;
}
--- a/src/vorbis.c
+++ b/src/vorbis.c
@@ -15,9 +15,6 @@
* any purpose. This copyright notice must be maintained.
* Lance Norskog And Sundry Contributors are not responsible for
* the consequences of using this software.
- *
- * TODO: When reading in comments, it doesn't understand how to read
- * more than one comment and doesn't know how to parse KEY=value.
*/
#include "sox_i.h"
@@ -43,37 +40,39 @@
/* Private data for Ogg Vorbis file */
typedef struct vorbis_enc {
- ogg_stream_state os;
- ogg_page og;
- ogg_packet op;
+ ogg_stream_state os;
+ ogg_page og;
+ ogg_packet op;
- vorbis_dsp_state vd;
- vorbis_block vb;
- vorbis_info vi;
+ vorbis_dsp_state vd;
+ vorbis_block vb;
+ vorbis_info vi;
} vorbis_enc_t;
typedef struct vorbisstuff {
-/* Decoding data */
- OggVorbis_File *vf;
- char *buf;
- sox_size_t buf_len;
- sox_size_t start;
- sox_size_t end; /* Unsent data samples in buf[start] through buf[end-1] */
- int current_section;
- int eof;
+ /* Decoding data */
+ OggVorbis_File *vf;
+ char *buf;
+ sox_size_t buf_len;
+ sox_size_t start;
+ sox_size_t end; /* Unsent data samples in buf[start] through buf[end-1] */
+ int current_section;
+ int eof;
- vorbis_enc_t *vorbis_enc_data;
+ vorbis_enc_t *vorbis_enc_data;
} *vorbis_t;
/******** Callback functions used in ov_open_callbacks ************/
-static int myclose (void *datasource UNUSED)
+static int myclose(void *datasource UNUSED)
{
- /* Do nothing so sox can close the file for us */
- return 0;
+ /* Do nothing so sox can close the file for us */
+ return 0;
}
-static int _fseeko64_wrap(FILE *f, ogg_int64_t off, int whence) {
+static int _fseeko64_wrap(FILE * f, ogg_int64_t off, int whence)
+{
int ret = fseeko(f, off, whence);
+
if (ret == EBADF)
ret = -1;
return ret;
@@ -91,115 +90,84 @@
*/
static int startread(sox_format_t * ft)
{
- vorbis_t vb = (vorbis_t) ft->priv;
- vorbis_info *vi;
- vorbis_comment *vc;
- sox_size_t comment_size;
- int i, offset;
+ vorbis_t vb = (vorbis_t) ft->priv;
+ vorbis_info *vi;
+ vorbis_comment *vc;
+ int i;
- ov_callbacks callbacks = {
- (size_t (*)(void *, size_t, size_t, void *)) fread,
- (int (*)(void *, ogg_int64_t, int)) _fseeko64_wrap,
- (int (*)(void *)) myclose,
- (long (*)(void *)) ftell
- };
+ ov_callbacks callbacks = {
+ (size_t(*)(void *, size_t, size_t, void *)) fread,
+ (int (*)(void *, ogg_int64_t, int)) _fseeko64_wrap,
+ (int (*)(void *)) myclose,
+ (long (*)(void *)) ftell
+ };
- /* Allocate space for decoding structure */
- vb->vf = (OggVorbis_File *)xmalloc(sizeof(OggVorbis_File));
+ /* Allocate space for decoding structure */
+ vb->vf = (OggVorbis_File *) xmalloc(sizeof(OggVorbis_File));
- /* Init the decoder */
- if (ov_open_callbacks((void *)ft->fp,vb->vf,NULL,0,callbacks) < 0)
- {
- sox_fail_errno(ft,SOX_EHDR,
- "Input not an Ogg Vorbis audio stream");
- return (SOX_EOF);
- }
+ /* Init the decoder */
+ if (ov_open_callbacks((void *) ft->fp, vb->vf, NULL, 0, callbacks) < 0) {
+ sox_fail_errno(ft, SOX_EHDR, "Input not an Ogg Vorbis audio stream");
+ return (SOX_EOF);
+ }
- /* Get info about the Ogg Vorbis stream */
- vi = ov_info(vb->vf, -1);
- vc = ov_comment(vb->vf, -1);
+ /* Get info about the Ogg Vorbis stream */
+ vi = ov_info(vb->vf, -1);
+ vc = ov_comment(vb->vf, -1);
- /* Record audio info */
- ft->signal.rate = vi->rate;
- ft->signal.size = SOX_SIZE_16BIT;
- ft->signal.encoding = SOX_ENCODING_VORBIS;
- ft->signal.channels = vi->channels;
+ /* Record audio info */
+ ft->signal.rate = vi->rate;
+ ft->signal.size = SOX_SIZE_16BIT;
+ ft->signal.encoding = SOX_ENCODING_VORBIS;
+ ft->signal.channels = vi->channels;
- /* ov_pcm_total doesn't work on non-seekable files so
- * skip that step in that case. Also, it reports
- * "frame"-ish results so we must * channels.
- */
- if (ft->seekable)
- ft->length = ov_pcm_total(vb->vf, -1) * ft->signal.channels;
+ /* ov_pcm_total doesn't work on non-seekable files so
+ * skip that step in that case. Also, it reports
+ * "frame"-ish results so we must * channels.
+ */
+ if (ft->seekable)
+ ft->length = ov_pcm_total(vb->vf, -1) * ft->signal.channels;
- /* Record comments */
- if (vc->comments == 0)
- ft->comment = NULL;
- else
- {
- comment_size = 0;
+ /* Record comments */
+ for (i = 0; i < vc->comments; i++)
+ append_comment(&ft->comments, vc->user_comments[i]);
- for (i = 0; i < vc->comments; i++)
- comment_size += vc->comment_lengths[i] + 1;
+ /* Setup buffer */
+ vb->buf_len = DEF_BUF_LEN;
+ vb->buf = xcalloc(vb->buf_len, sizeof(char));
+ vb->start = vb->end = 0;
- ft->comment = (char *)xcalloc(comment_size, sizeof(char));
+ /* Fill in other info */
+ vb->eof = 0;
+ vb->current_section = -1;
- offset = 0;
- for (i = 0; i < vc->comments; i++)
- {
- strncpy(ft->comment + offset, vc->user_comments[i],
- (size_t)vc->comment_lengths[i]);
- offset += vc->comment_lengths[i];
- ft->comment[offset] = '\n';
- offset++;
- }
- /* On last comment, end string by overwriting last \n */
- if (offset > 0)
- offset--;
- ft->comment[offset] = 0;
- }
+ return (SOX_SUCCESS);
+}
- /* Setup buffer */
- vb->buf_len = DEF_BUF_LEN;
- vb->buf = xcalloc(vb->buf_len, sizeof(char));
- vb->start = vb->end = 0;
- /* Fill in other info */
- vb->eof = 0;
- vb->current_section = -1;
-
- return (SOX_SUCCESS);
-}
-
-
/* Refill the buffer with samples. Returns BUF_EOF if the end of the
- vorbis data was reached while the buffer was being filled,
- BUF_ERROR is something bad happens, and BUF_DATA otherwise */
-static int refill_buffer (vorbis_t vb)
+ * vorbis data was reached while the buffer was being filled,
+ * BUF_ERROR is something bad happens, and BUF_DATA otherwise */
+static int refill_buffer(vorbis_t vb)
{
- int num_read;
+ int num_read;
- if (vb->start == vb->end) /* Samples all played */
- vb->start = vb->end = 0;
+ if (vb->start == vb->end) /* Samples all played */
+ vb->start = vb->end = 0;
- while (vb->end < vb->buf_len)
- {
- num_read = ov_read(vb->vf, vb->buf + vb->end,
- (int)(vb->buf_len - vb->end), 0, 2, 1,
- &vb->current_section);
-
- if (num_read == 0)
- return (BUF_EOF);
- else if (num_read == OV_HOLE)
- sox_warn("Warning: hole in stream; probably harmless");
- else if (num_read < 0)
- return (BUF_ERROR);
- else
- vb->end += num_read;
-
- }
-
- return (BUF_DATA);
+ while (vb->end < vb->buf_len) {
+ num_read = ov_read(vb->vf, vb->buf + vb->end,
+ (int) (vb->buf_len - vb->end), 0, 2, 1, &vb->current_section);
+ if (num_read == 0)
+ return (BUF_EOF);
+ else if (num_read == OV_HOLE)
+ sox_warn("Warning: hole in stream; probably harmless");
+ else if (num_read < 0)
+ return (BUF_ERROR);
+ else
+ vb->end += num_read;
+ }
+ return (BUF_DATA);
}
@@ -210,35 +178,32 @@
* Return number of samples read.
*/
-static sox_size_t read(sox_format_t * ft, sox_sample_t *buf, sox_size_t len)
+static sox_size_t read(sox_format_t * ft, sox_sample_t * buf, sox_size_t len)
{
- vorbis_t vb = (vorbis_t) ft->priv;
- sox_size_t i;
- int ret;
- sox_sample_t l;
+ vorbis_t vb = (vorbis_t) ft->priv;
+ sox_size_t i;
+ int ret;
+ sox_sample_t l;
- for(i = 0; i < len; i++) {
- if (vb->start == vb->end)
- {
- if (vb->eof)
- break;
- ret = refill_buffer(vb);
- if (ret == BUF_EOF || ret == BUF_ERROR)
- {
- vb->eof = 1;
- if (vb->end == 0)
- break;
- }
- }
+ for (i = 0; i < len; i++) {
+ if (vb->start == vb->end) {
+ if (vb->eof)
+ break;
+ ret = refill_buffer(vb);
+ if (ret == BUF_EOF || ret == BUF_ERROR) {
+ vb->eof = 1;
+ if (vb->end == 0)
+ break;
+ }
+ }
- l = (vb->buf[vb->start+1]<<24)
- | (0xffffff & (vb->buf[vb->start]<<16));
- *(buf + i) = l;
- vb->start += 2;
- }
-
- return i;
+ l = (vb->buf[vb->start + 1] << 24)
+ | (0xffffff & (vb->buf[vb->start] << 16));
+ *(buf + i) = l;
+ vb->start += 2;
+ }
+ return i;
}
/*
@@ -247,23 +212,24 @@
*/
static int stopread(sox_format_t * ft)
{
- vorbis_t vb = (vorbis_t) ft->priv;
+ vorbis_t vb = (vorbis_t) ft->priv;
- free(vb->buf);
- ov_clear(vb->vf);
+ free(vb->buf);
+ ov_clear(vb->vf);
- return (SOX_SUCCESS);
+ return (SOX_SUCCESS);
}
/* Write a page of ogg data to a file. Taken directly from encode.c in
- oggenc. Returns the number of bytes written. */
-static int oe_write_page(ogg_page *page, sox_format_t * ft)
+ * oggenc. Returns the number of bytes written. */
+static int oe_write_page(ogg_page * page, sox_format_t * ft)
{
- int written;
- written = sox_writebuf(ft, page->header,(sox_size_t)page->header_len);
- written += sox_writebuf(ft, page->body,(sox_size_t)page->body_len);
+ int written;
- return written;
+ written = sox_writebuf(ft, page->header, (sox_size_t) page->header_len);
+ written += sox_writebuf(ft, page->body, (sox_size_t) page->body_len);
+
+ return written;
}
/* Write out the header packets. Derived mostly from encode.c in oggenc.
@@ -274,158 +240,158 @@
ogg_packet header_comments;
ogg_packet header_codebooks;
vorbis_comment vc;
- char * comment = NULL;
+ int i, ret = HEADER_OK;
memset(&vc, 0, sizeof(vc));
- if (ft->comment && *ft->comment) { /* Make the comment structure */
- ++vc.comments;
- vc.user_comments = xcalloc(1, sizeof(*vc.user_comments));
- vc.comment_lengths = xcalloc(1, sizeof(*vc.comment_lengths));
-
- /* Add a FIELD=value pair if not one already in the comment */
- comment = xcalloc(1, strlen(ft->comment) + strlen("COMMENT=") + 1);
- if (!strchr(ft->comment,'='))
- strcpy(comment, "COMMENT=");
-
- vc.user_comments[0] = strcat(comment, ft->comment);
- vc.comment_lengths[0] = strlen(comment);
+ vc.comments = num_comments(ft->comments);
+ if (vc.comments) { /* Make the comment structure */
+ vc.comment_lengths = xcalloc(vc.comments, sizeof(*vc.comment_lengths));
+ vc.user_comments = xcalloc(vc.comments, sizeof(*vc.user_comments));
+ for (i = 0; i < vc.comments; ++i) {
+ static const char prepend[] = "Comment=";
+ char * text = xcalloc(strlen(prepend) + strlen(ft->comments[i]) + 1, sizeof(*text));
+ /* Prepend `Comment=' if no field-name already in the comment */
+ if (!strchr(ft->comments[i], '='))
+ strcpy(text, prepend);
+ vc.user_comments[i] = strcat(text, ft->comments[i]);
+ vc.comment_lengths[i] = strlen(text);
+ }
}
- vorbis_analysis_headerout( /* Build the packets */
+ vorbis_analysis_headerout( /* Build the packets */
&ve->vd, &vc, &header_main, &header_comments, &header_codebooks);
- ogg_stream_packetin(&ve->os,&header_main); /* And stream them out */
- ogg_stream_packetin(&ve->os,&header_comments);
- ogg_stream_packetin(&ve->os,&header_codebooks);
+ ogg_stream_packetin(&ve->os, &header_main); /* And stream them out */
+ ogg_stream_packetin(&ve->os, &header_comments);
+ ogg_stream_packetin(&ve->os, &header_codebooks);
- while (ogg_stream_flush(&ve->os, &ve->og)) {
- int ret = oe_write_page(&ve->og, ft);
- if (!ret) {
- free(comment);
- return HEADER_ERROR;
- }
- }
- free(comment);
- return HEADER_OK;
+ while (ogg_stream_flush(&ve->os, &ve->og) && ret == HEADER_OK)
+ if (!oe_write_page(&ve->og, ft))
+ ret = HEADER_ERROR;
+ for (i = 0; i < vc.comments; ++i)
+ free(vc.user_comments[i]);
+ free(vc.user_comments);
+ free(vc.comment_lengths);
+ return ret;
}
static int startwrite(sox_format_t * ft)
{
- vorbis_t vb = (vorbis_t) ft->priv;
- vorbis_enc_t *ve;
- long rate;
- double quality = 3; /* Default compression quality gives ~112kbps */
+ vorbis_t vb = (vorbis_t) ft->priv;
+ vorbis_enc_t *ve;
+ long rate;
+ double quality = 3; /* Default compression quality gives ~112kbps */
- ft->signal.size = SOX_SIZE_16BIT;
- ft->signal.encoding = SOX_ENCODING_VORBIS;
+ ft->signal.size = SOX_SIZE_16BIT;
+ ft->signal.encoding = SOX_ENCODING_VORBIS;
- /* Allocate memory for all of the structures */
- ve = vb->vorbis_enc_data = (vorbis_enc_t *)xmalloc(sizeof(vorbis_enc_t));
+ /* Allocate memory for all of the structures */
+ ve = vb->vorbis_enc_data = (vorbis_enc_t *) xmalloc(sizeof(vorbis_enc_t));
- vorbis_info_init(&ve->vi);
+ vorbis_info_init(&ve->vi);
- /* TODO */
- rate = ft->signal.rate;
- if (rate)
- sox_fail_errno(ft, SOX_EHDR, "Error setting up Ogg Vorbis encorder - make sure you've specied a sane rate and number of channels");
+ /* TODO */
+ rate = ft->signal.rate;
+ if (rate)
+ sox_fail_errno(ft, SOX_EHDR,
+ "Error setting-up Ogg Vorbis encoder; check sample-rate & # of channels");
- /* Use encoding to average bit rate of VBR as specified by the -C option */
- if (ft->signal.compression != HUGE_VAL)
- {
- if (ft->signal.compression < -1 || ft->signal.compression > 10)
- {
- sox_fail_errno(ft,SOX_EINVAL,
- "Vorbis compression quality nust be between -1 and 10");
- return SOX_EOF;
- }
- quality = ft->signal.compression;
- }
- vorbis_encode_init_vbr(&ve->vi, (int)ft->signal.channels, (int)ft->signal.rate, (float)(quality / 10));
+ /* Use encoding to average bit rate of VBR as specified by the -C option */
+ if (ft->signal.compression != HUGE_VAL) {
+ if (ft->signal.compression < -1 || ft->signal.compression > 10) {
+ sox_fail_errno(ft, SOX_EINVAL,
+ "Vorbis compression quality nust be between -1 and 10");
+ return SOX_EOF;
+ }
+ quality = ft->signal.compression;
+ }
+ vorbis_encode_init_vbr(&ve->vi, (int) ft->signal.channels,
+ (int) ft->signal.rate, (float) (quality / 10));
- vorbis_analysis_init(&ve->vd, &ve->vi);
- vorbis_block_init(&ve->vd, &ve->vb);
+ vorbis_analysis_init(&ve->vd, &ve->vi);
+ vorbis_block_init(&ve->vd, &ve->vb);
- ogg_stream_init(&ve->os, rand()); /* Random serial number */
+ ogg_stream_init(&ve->os, rand()); /* Random serial number */
- if (write_vorbis_header(ft, ve) == HEADER_ERROR)
- {
- sox_fail_errno(ft,SOX_EHDR,
- "Error writing header for Ogg Vorbis audio stream");
- return (SOX_EOF);
- }
+ if (write_vorbis_header(ft, ve) == HEADER_ERROR) {
+ sox_fail_errno(ft, SOX_EHDR,
+ "Error writing header for Ogg Vorbis audio stream");
+ return (SOX_EOF);
+ }
- return(SOX_SUCCESS);
+ return (SOX_SUCCESS);
}
-static sox_size_t write(sox_format_t * ft, const sox_sample_t *buf, sox_size_t len)
+static sox_size_t write(sox_format_t * ft, const sox_sample_t * buf,
+ sox_size_t len)
{
- vorbis_t vb = (vorbis_t) ft->priv;
- vorbis_enc_t *ve = vb->vorbis_enc_data;
- sox_size_t samples = len / ft->signal.channels;
- float **buffer = vorbis_analysis_buffer(&ve->vd, (int)samples);
- sox_size_t i, j;
- int ret;
- int eos = 0;
+ vorbis_t vb = (vorbis_t) ft->priv;
+ vorbis_enc_t *ve = vb->vorbis_enc_data;
+ sox_size_t samples = len / ft->signal.channels;
+ float **buffer = vorbis_analysis_buffer(&ve->vd, (int) samples);
+ sox_size_t i, j;
+ int ret;
+ int eos = 0;
- /* Copy samples into vorbis buffer */
- for (i = 0; i < samples; i++)
- for (j = 0; j < ft->signal.channels; j++)
- buffer[j][i] = buf[i*ft->signal.channels + j]
- / ((float)SOX_SAMPLE_MAX);
+ /* Copy samples into vorbis buffer */
+ for (i = 0; i < samples; i++)
+ for (j = 0; j < ft->signal.channels; j++)
+ buffer[j][i] = buf[i * ft->signal.channels + j]
+ / ((float) SOX_SAMPLE_MAX);
- vorbis_analysis_wrote(&ve->vd, (int)samples);
+ vorbis_analysis_wrote(&ve->vd, (int) samples);
- while(vorbis_analysis_blockout(&ve->vd,&ve->vb)==1)
- {
- /* Do the main analysis, creating a packet */
- vorbis_analysis(&ve->vb, &ve->op);
- vorbis_bitrate_addblock(&ve->vb);
+ while (vorbis_analysis_blockout(&ve->vd, &ve->vb) == 1) {
+ /* Do the main analysis, creating a packet */
+ vorbis_analysis(&ve->vb, &ve->op);
+ vorbis_bitrate_addblock(&ve->vb);
- /* Add packet to bitstream */
- while (vorbis_bitrate_flushpacket(&ve->vd, &ve->op))
- {
- ogg_stream_packetin(&ve->os,&ve->op);
+ /* Add packet to bitstream */
+ while (vorbis_bitrate_flushpacket(&ve->vd, &ve->op)) {
+ ogg_stream_packetin(&ve->os, &ve->op);
- /* If we've gone over a page boundary, we can do actual
- * output, so do so (for however many pages are available)
- */
+ /* If we've gone over a page boundary, we can do actual
+ * output, so do so (for however many pages are available)
+ */
- while(!eos)
- {
- int result = ogg_stream_pageout(&ve->os,&ve->og);
- if(!result) break;
+ while (!eos) {
+ int result = ogg_stream_pageout(&ve->os, &ve->og);
- ret = oe_write_page(&ve->og, ft);
- if(!ret)
- return 0;
+ if (!result)
+ break;
+
+ ret = oe_write_page(&ve->og, ft);
+ if (!ret)
+ return 0;
- if(ogg_page_eos(&ve->og))
- eos = 1;
- }
- }
- }
+ if (ogg_page_eos(&ve->og))
+ eos = 1;
+ }
+ }
+ }
- return (len);
+ return (len);
}
static int stopwrite(sox_format_t * ft)
{
- vorbis_t vb = (vorbis_t) ft->priv;
- vorbis_enc_t *ve = vb->vorbis_enc_data;
+ vorbis_t vb = (vorbis_t) ft->priv;
+ vorbis_enc_t *ve = vb->vorbis_enc_data;
- /* Close out the remaining data */
- write(ft, NULL, 0);
+ /* Close out the remaining data */
+ write(ft, NULL, 0);
- ogg_stream_clear(&ve->os);
- vorbis_block_clear(&ve->vb);
- vorbis_dsp_clear(&ve->vd);
- vorbis_info_clear(&ve->vi);
+ ogg_stream_clear(&ve->os);
+ vorbis_block_clear(&ve->vb);
+ vorbis_dsp_clear(&ve->vd);
+ vorbis_info_clear(&ve->vi);
- return (SOX_SUCCESS);
+ return (SOX_SUCCESS);
}
-static int seek(sox_format_t * ft, sox_size_t offset)
+static int seek(sox_format_t * ft, sox_size_t offset)
{
- vorbis_t vb = (vorbis_t)ft->priv;
+ vorbis_t vb = (vorbis_t) ft->priv;
+
return ov_pcm_seek(vb->vf, offset / ft->signal.channels)? SOX_EOF:SOX_SUCCESS;
}
@@ -433,7 +399,7 @@
const sox_format_handler_t *sox_vorbis_format_fn(void)
{
- static const char * names[] = {"vorbis", "ogg", NULL};
+ static const char *names[] = {"vorbis", "ogg", NULL};
static sox_format_handler_t handler = {
names, SOX_FILE_SEEK,
startread, read, stopread,
--- a/src/wav.c
+++ b/src/wav.c
@@ -41,6 +41,7 @@
unsigned short samplesPerBlock;
unsigned short blockAlign;
sox_size_t dataStart; /* need to for seeking */
+ char * comment;
int ignoreSize; /* ignoreSize allows us to process 32-bit WAV files that are
* greater then 2 Gb and can't be represented by the
* 32-bit size field. */
@@ -898,9 +899,9 @@
if (sox_seeki(ft, (sox_ssize_t)len, SEEK_CUR) == SOX_SUCCESS &&
findChunk(ft, "LIST", &len) != SOX_EOF)
{
- ft->comment = (char*)xmalloc(256);
+ wav->comment = (char*)xmalloc(256);
/* Initialize comment to a NULL string */
- ft->comment[0] = 0;
+ wav->comment[0] = 0;
while(!sox_eof(ft))
{
if (sox_reads(ft,magic,4) == SOX_EOF)
@@ -934,12 +935,12 @@
break;
}
sox_reads(ft,text,len);
- if (strlen(ft->comment) + strlen(text) < 254)
+ if (strlen(wav->comment) + strlen(text) < 254)
{
- if (ft->comment[0] != 0)
- strcat(ft->comment,"\n");
+ if (wav->comment[0] != 0)
+ strcat(wav->comment,"\n");
- strcat(ft->comment,text);
+ strcat(wav->comment,text);
}
if (strlen(text) < len)
sox_seeki(ft, (sox_ssize_t)(len - strlen(text)), SEEK_CUR);
@@ -953,12 +954,12 @@
break;
}
sox_reads(ft,text,len);
- if (strlen(ft->comment) + strlen(text) < 254)
+ if (strlen(wav->comment) + strlen(text) < 254)
{
- if (ft->comment[0] != 0)
- strcat(ft->comment,"\n");
+ if (wav->comment[0] != 0)
+ strcat(wav->comment,"\n");
- strcat(ft->comment,text);
+ strcat(wav->comment,text);
}
if (strlen(text) < len)
sox_seeki(ft, (sox_ssize_t)(len - strlen(text)), SEEK_CUR);
@@ -1107,8 +1108,8 @@
free(wav->packet);
free(wav->samples);
free(wav->iCoefs);
- free(ft->comment);
- ft->comment = NULL;
+ free(wav->comment);
+ wav->comment = NULL;
switch (ft->signal.encoding)
{