shithub: sox

Download patch

ref: 4f2944e51b8a9017b27ddf3267c775fe81d26025
parent: 69055b9b71576c2ea851f330fc9c71e00bd6f3f3
author: cbagwell <cbagwell>
date: Fri Sep 1 12:08:24 EDT 2000

Updated ALSA driver, fixed .au comments to be null terminated, and
updated handlers.c so that ST_EFF_CHAN type effects also included
ST_EFF_MCHAN so that all stereo data would be passed into them.

--- a/sox.1
+++ b/sox.1
@@ -259,7 +259,7 @@
 Run in preview mode and run fast.  This will somewhat speed up
 sox when the output format has a different number of channels and
 a different rate than the input file.  Currently, this defaults to
-using the \fBrate\fR effect instead of the \fBresample\fR for sample
+using the \fBrate\fR effect instead of the \fBresample\fR effect for sample
 rate changes.
 .TP 10
 \fB-v \fIvolume\fR
@@ -1032,18 +1032,6 @@
 .I dB
 the amplitude is change logarithmically.
 0.0 is constant while +6 doubles the amplitude.
-.P
-.I Sox
-enforces certain effects.
-If the two files have different sampling
-rates, the requested effect must be one of
-.B polyphase, rate, 
-or
-.B resample.
-If the two files have different numbers of channels,
-the 
-.B avg
-or other channel mixing effect must be requested.
 .SH BUGS
 The syntax is horrific.  Thats the breaks when trying to handle all things from the command line.
 .P
--- a/src/alsa.c
+++ b/src/alsa.c
@@ -13,15 +13,16 @@
  * based on info grabed from aplay.c in alsa-utils package.
  */
 
-#include <unistd.h>
-#include <stdlib.h>
 #include <string.h>
-#include <stdio.h>
 #include <fcntl.h>
 #include <linux/asound.h>
 #include <sys/ioctl.h>
 #include "st.h"
 
+static int get_format(P3(ft_t ft, int formats, int *fmt));
+
+#if 0 /* Start old API */
+
 /*
  * Do anything required before you start reading samples.
  * Read file header.
@@ -45,68 +46,14 @@
     ft->file.size = c_info.buffer_size;
     if ((ft->file.buf = malloc (ft->file.size)) == NULL) {
 	st_fail("unable to allocate output buffer of size %d", ft->file.size);
-	return (ST_EOF);
+	return(ST_EOF);
     }
     if (ft->info.rate < c_info.min_rate) ft->info.rate = 2 * c_info.min_rate;
     else if (ft->info.rate > c_info.max_rate) ft->info.rate = c_info.max_rate;
     if (ft->info.channels == -1) ft->info.channels = c_info.min_channels;
     else if (ft->info.channels > c_info.max_channels) ft->info.channels = c_info.max_channels;
-    if (ft->info.size == -1) {
-	if ((c_info.hw_formats & SND_PCM_FMT_U8) || (c_info.hw_formats & SND_PCM_FMT_S8))
-	    ft->info.size = ST_SIZE_BYTE;
-	else
-	    ft->info.size = ST_SIZE_WORD;
-    }
-    if (ft->info.encoding == -1) {
-	if ((c_info.hw_formats & SND_PCM_FMT_S16_LE) || (c_info.hw_formats & SND_PCM_FMT_S8))
-	    ft->info.encoding = ST_ENCODING_SIGN2;
-	else
-	    ft->info.encoding = ST_ENCODING_UNSIGNED;
-    }
-    if (ft->info.size == ST_SIZE_BYTE) {
-	switch (ft->info.encoding)
-	{
-	    case ST_ENCODING_SIGN2:
-		if (!(c_info.hw_formats & SND_PCM_FMT_S8))
-		{
-		    st_fail("ALSA driver does not support signed byte samples");
-		    return(ST_EOF);
-		}
-		fmt = SND_PCM_SFMT_S8;
-		break;
-	    case ST_ENCODING_UNSIGNED:
-		if (!(c_info.hw_formats & SND_PCM_FMT_U8))
-		{
-		    st_fail("ALSA driver does not support unsigned byte samples");
-		    return(ST_EOF);
-		}
-		fmt = SND_PCM_SFMT_U8;
-		break;
-	    default:
-		st_fail("Hardware does not support %s output", st_encodings_str[ft->info.encoding]);
-		return(ST_EOF);
-		break;
-	}
-    }
-    else {
-	switch (ft->info.encoding)
-	{
-	    case ST_ENCODING_SIGN2:
-		if (!(c_info.hw_formats & SND_PCM_FMT_S16_LE))
-		    st_fail("ALSA driver does not support signed word samples");
-		fmt = SND_PCM_SFMT_S16_LE;
-		break;
-	    case ST_ENCODING_UNSIGNED:
-		if (!(c_info.hw_formats & SND_PCM_FMT_U16_LE))
-		    st_fail("ALSA driver does not support unsigned word samples");
-		fmt = SND_PCM_SFMT_U16_LE;
-		break;
-	    default:
-		st_fail("Hardware does not support %s output", st_encodings_str[ft->info.encoding]);
-		return(ST_EOF);
-		break;
-	}
-    }
+    if (get_format(ft, c_info.hw_formats, &fmt) < 0)
+	return(ST_EOF);
 
     memset(&format, 0, sizeof(format));
     format.format = fmt;
@@ -154,14 +101,148 @@
     else if (ft->info.rate > p_info.max_rate) ft->info.rate = p_info.max_rate;
     if (ft->info.channels == -1) ft->info.channels = p_info.min_channels;
     else if (ft->info.channels > p_info.max_channels) ft->info.channels = p_info.max_channels;
+    if (get_format(ft, p_info.hw_formats, &fmt) < 0)
+	return(ST_EOF);
+
+    memset(&format, 0, sizeof(format));
+    format.format = fmt;
+    format.rate = ft->info.rate;
+    format.channels = ft->info.channels;
+    ioctl(fileno(ft->fp), SND_PCM_IOCTL_PLAYBACK_FORMAT, &format);
+
+    size = ft->file.size;
+    bps = format.rate * format.channels;
+    if (ft->info.size == ST_SIZE_WORD) bps <<= 1;
+    bps >>= 2;
+    while (size > bps) size >>= 1;
+    if (size < 16) size = 16;
+    memset(&p_params, 0, sizeof(p_params));
+    p_params.fragment_size = size;
+    p_params.fragments_max = -1;
+    p_params.fragments_room = 1;
+    ioctl(fileno(ft->fp), SND_PCM_IOCTL_PLAYBACK_PARAMS, &p_params);
+
+    /* Change to non-buffered I/O */
+    setvbuf(ft->fp, NULL, _IONBF, sizeof(char) * ft->file.size);
+
+    return(ST_SUCCESS);
+}
+
+#else /* Start new API */
+
+int st_alsastartread(ft)
+ft_t ft;
+{
+    int bps, fmt, size;
+    snd_pcm_channel_info_t c_info;
+    snd_pcm_channel_params_t c_params;
+
+    memset(&c_info, 0, sizeof(c_info));
+    ioctl(fileno(ft->fp), SND_PCM_IOCTL_CHANNEL_INFO, &c_info);
+    ft->file.count = 0;
+    ft->file.pos = 0;
+    ft->file.eof = 0;
+    ft->file.size = c_info.buffer_size;
+    if ((ft->file.buf = malloc (ft->file.size)) == NULL) {
+	st_fail("unable to allocate output buffer of size %d", ft->file.size);
+	return(ST_EOF);
+    }
+    if (ft->info.rate < c_info.min_rate) ft->info.rate = 2 * c_info.min_rate;
+    else if (ft->info.rate > c_info.max_rate) ft->info.rate = c_info.max_rate;
+    if (ft->info.channels == -1) ft->info.channels = c_info.min_voices;
+    else if (ft->info.channels > c_info.max_voices) ft->info.channels = c_info.max_voices;
+    if (get_format(ft, c_info.formats, &fmt) < 0)
+	return (ST_EOF);
+
+    memset(&c_params, 0, sizeof(c_params));
+    c_params.format.format = fmt;
+    c_params.format.rate = ft->info.rate;
+    c_params.format.voices = ft->info.channels;
+    c_params.start_mode = SND_PCM_START_DATA;
+    c_params.stop_mode = SND_PCM_STOP_STOP;
+    bps = c_params.format.rate * c_params.format.voices;
+    if (ft->info.size == ST_SIZE_WORD) bps <<= 1;
+    bps >>= 2;
+    size = 1;
+    while ((size << 1) < bps) size <<= 1;
+    if (size > ft->file.size) size = ft->file.size;
+    c_params.mode = SND_PCM_MODE_BLOCK;
+    c_params.buf.block.frag_size = size;
+    c_params.buf.block.frags_min = 32;
+    c_params.buf.block.frags_min = 1;
+    ioctl(fileno(ft->fp), SND_PCM_IOCTL_CHANNEL_PARAMS, &c_params);
+    ioctl(fileno(ft->fp), SND_PCM_IOCTL_CHANNEL_PREPARE);
+
+    /* Change to non-buffered I/O */
+    setvbuf(ft->fp, NULL, _IONBF, sizeof(char) * ft->file.size);
+
+    sigintreg(ft);	/* Prepare to catch SIGINT */
+
+    return (ST_SUCCESS);
+}
+
+int st_alsastartwrite(ft)
+ft_t ft;
+{
+    int bps, fmt, size;
+    snd_pcm_channel_info_t p_info;
+    snd_pcm_channel_params_t p_params;
+
+    memset(&p_info, 0, sizeof(p_info));
+    ioctl(fileno(ft->fp), SND_PCM_IOCTL_CHANNEL_INFO, &p_info);
+    ft->file.pos = 0;
+    ft->file.eof = 0;
+    ft->file.size = p_info.buffer_size;
+    if ((ft->file.buf = malloc (ft->file.size)) == NULL) {
+	st_fail("unable to allocate output buffer of size %d", ft->file.size);
+	return(ST_EOF);
+    }
+    if (ft->info.rate < p_info.min_rate) ft->info.rate = 2 * p_info.min_rate;
+    else if (ft->info.rate > p_info.max_rate) ft->info.rate = p_info.max_rate;
+    if (ft->info.channels == -1) ft->info.channels = p_info.min_voices;
+    else if (ft->info.channels > p_info.max_voices) ft->info.channels = p_info.max_voices;
+    if (get_format(ft, p_info.formats, &fmt) < 0)
+	return(ST_EOF);
+
+    memset(&p_params, 0, sizeof(p_params));
+    p_params.format.format = fmt;
+    p_params.format.rate = ft->info.rate;
+    p_params.format.voices = ft->info.channels;
+    p_params.start_mode = SND_PCM_START_FULL;
+    p_params.stop_mode = SND_PCM_STOP_STOP;
+    bps = p_params.format.rate * p_params.format.voices;
+    if (ft->info.size == ST_SIZE_WORD) bps <<= 1;
+    bps >>= 2;
+    size = 1;
+    while ((size << 1) < bps) size <<= 1;
+    if (size > ft->file.size) size = ft->file.size;
+    p_params.mode = SND_PCM_MODE_BLOCK;
+    p_params.buf.block.frag_size = size;
+    p_params.buf.block.frags_max = -1; /* Little trick (playback only) */
+    p_params.buf.block.frags_min = 1;
+    ioctl(fileno(ft->fp), SND_PCM_IOCTL_CHANNEL_PARAMS, &p_params);
+    ioctl(fileno(ft->fp), SND_PCM_IOCTL_CHANNEL_PREPARE);
+
+    /* Change to non-buffered I/O */
+    setvbuf(ft->fp, NULL, _IONBF, sizeof(char) * ft->file.size);
+
+    return(ST_SUCCESS);
+}
+
+#endif /* End API */
+
+static int get_format(ft, formats, fmt)
+ft_t ft;
+int formats, *fmt;
+{
     if (ft->info.size == -1) {
-	if ((p_info.hw_formats & SND_PCM_FMT_U8) || (p_info.hw_formats & SND_PCM_FMT_S8))
+	if ((formats & SND_PCM_FMT_U8) || (formats & SND_PCM_FMT_S8))
 	    ft->info.size = ST_SIZE_BYTE;
 	else
 	    ft->info.size = ST_SIZE_WORD;
     }
     if (ft->info.encoding == -1) {
-	if ((p_info.hw_formats & SND_PCM_FMT_S16_LE) || (p_info.hw_formats & SND_PCM_FMT_S8))
+	if ((formats & SND_PCM_FMT_S16) || (formats & SND_PCM_FMT_S8))
 	    ft->info.encoding = ST_ENCODING_SIGN2;
 	else
 	    ft->info.encoding = ST_ENCODING_UNSIGNED;
@@ -170,24 +251,22 @@
 	switch (ft->info.encoding)
 	{
 	    case ST_ENCODING_SIGN2:
-		if (!(p_info.hw_formats & SND_PCM_FMT_S8))
-		{
+		if (!(formats & SND_PCM_FMT_S8)) {
 		    st_fail("ALSA driver does not support signed byte samples");
-		    return (ST_EOF);
+		    return -1;
 		}
-		fmt = SND_PCM_SFMT_S8;
+		*fmt = SND_PCM_SFMT_S8;
 		break;
 	    case ST_ENCODING_UNSIGNED:
-		if (!(p_info.hw_formats & SND_PCM_FMT_U8))
-		{
+		if (!(formats & SND_PCM_FMT_U8)) {
 		    st_fail("ALSA driver does not support unsigned byte samples");
-		    return (ST_EOF);
+		    return -1;
 		}
-		fmt = SND_PCM_SFMT_U8;
+		*fmt = SND_PCM_SFMT_U8;
 		break;
 	    default:
 		st_fail("Hardware does not support %s output", st_encodings_str[ft->info.encoding]);
-		return(ST_EOF);
+		return -1;
 		break;
 	}
     }
@@ -195,50 +274,26 @@
 	switch (ft->info.encoding)
 	{
 	    case ST_ENCODING_SIGN2:
-		if (!(p_info.hw_formats & SND_PCM_FMT_S16_LE))
-		{
+		if (!(formats & SND_PCM_FMT_S16)) {
 		    st_fail("ALSA driver does not support signed word samples");
-		    return (ST_EOF);
+		    return -1;
 		}
-		fmt = SND_PCM_SFMT_S16_LE;
+		*fmt = SND_PCM_SFMT_S16_LE;
 		break;
 	    case ST_ENCODING_UNSIGNED:
-		if (!(p_info.hw_formats & SND_PCM_FMT_U16_LE))
-		{
+		if (!(formats & SND_PCM_FMT_U16)) {
 		    st_fail("ALSA driver does not support unsigned word samples");
-		    return(ST_EOF);
+		    return -1;
 		}
-		fmt = SND_PCM_SFMT_U16_LE;
+		*fmt = SND_PCM_SFMT_U16_LE;
 		break;
 	    default:
 		st_fail("Hardware does not support %s output", st_encodings_str[ft->info.encoding]);
-		return(ST_EOF);
+		return -1;
 		break;
 	}
     }
-
-    memset(&format, 0, sizeof(format));
-    format.format = fmt;
-    format.rate = ft->info.rate;
-    format.channels = ft->info.channels;
-    ioctl(fileno(ft->fp), SND_PCM_IOCTL_PLAYBACK_FORMAT, &format);
-
-    size = ft->file.size;
-    bps = format.rate * format.channels;
-    if (ft->info.size == ST_SIZE_WORD) bps <<= 1;
-    bps >>= 2;
-    while (size > bps) size >>= 1;
-    if (size < 16) size = 16;
-    memset(&p_params, 0, sizeof(p_params));
-    p_params.fragment_size = size;
-    p_params.fragments_max = -1;
-    p_params.fragments_room = 1;
-    ioctl(fileno(ft->fp), SND_PCM_IOCTL_PLAYBACK_PARAMS, &p_params);
-
-    /* Change to non-buffered I/O */
-    setvbuf(ft->fp, NULL, _IONBF, sizeof(char) * ft->file.size);
-
-    return(ST_SUCCESS);
+    return 0;
 }
 
 #endif
--- a/src/au.c
+++ b/src/au.c
@@ -210,7 +210,8 @@
 	/* Skip the info string in header; print it if verbose */
 	hdr_size -= SUN_HDRSIZE; /* #bytes already read */
 	if (hdr_size > 0) {
-		buf = (char *) malloc(hdr_size + 1);
+                /* Allocate comment buffer */
+		buf = (char *) malloc(hdr_size+1);		
 		for(i = 0; i < hdr_size; i++) {
 		    	st_readb(ft, &(buf[i]));
 			if (feof(ft->fp))
@@ -219,7 +220,14 @@
 				return(ST_EOF);
 			}
 		}
-		buf[i] = '\0';
+		/* Buffer should already be null terminated but
+		 * just in case we malloced an extra byte and 
+		 * force the last byte to be 0 anyways.
+		 * This should help work with a greater array of
+		 * software.
+		 */
+	        buf[hdr_size] = '\0';
+
 		ft->comment = buf;
 		st_report("Input file %s: Sun header info: %s", ft->filename, buf);
 	}
@@ -369,6 +377,7 @@
 	ULONG encoding;
 	ULONG sample_rate;
 	ULONG channels;
+	int   x;
 
 	if((encoding = st_ausunencoding(ft->info.size, ft->info.encoding)) == -1) {
 		st_report("Unsupported output encoding/size for Sun/NeXT header or .AU format not specified.");
@@ -383,9 +392,13 @@
 	magic = SUN_MAGIC;
 	st_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 = "";
-	hdr_size = SUN_HDRSIZE + strlen(ft->comment);
+		ft->comment = "SOX";
+
+	hdr_size = SUN_HDRSIZE + strlen(ft->comment) + 1; /*+1 = null-term. */
 	st_writedw(ft, hdr_size);
 
 	st_writedw(ft, data_size);
@@ -399,5 +412,12 @@
 	st_writedw(ft, channels);
 
 	st_writes(ft, ft->comment);
+
+	/* Info must be 4 bytes at least and null terminated. */
+	x = strlen(ft->comment);
+	for (;x < 3; x++)
+	    st_writeb(ft, 0);
+
+	st_writeb(ft, 0);
 }
 
--- a/src/handlers.c
+++ b/src/handlers.c
@@ -642,7 +642,7 @@
 	{"null", 0, 			/* stand-in, never gets called */
 		st_nothing, st_nothing, st_nothing, 
 		st_null_drain, st_nothing},
-	{"avg", ST_EFF_CHAN, 
+	{"avg", ST_EFF_MCHAN | ST_EFF_CHAN, 
 		st_avg_getopts, st_avg_start, st_avg_flow, 
 		st_null_drain, st_avg_stop},
 	{"band", 0, 
@@ -699,13 +699,13 @@
 	{"mask", ST_EFF_MCHAN, 
 		st_mask_getopts, st_nothing, st_mask_flow, 
 		st_null_drain, st_nothing},
-	{"pan", ST_EFF_CHAN, 
+	{"pan", ST_EFF_MCHAN | ST_EFF_CHAN, 
 		st_pan_getopts, st_pan_start, st_pan_flow, 
 		st_null_drain, st_pan_stop},
 	{"phaser", 0,
 	        st_phaser_getopts, st_phaser_start, st_phaser_flow,
 	        st_phaser_drain, st_phaser_stop},
-	{"pick", ST_EFF_CHAN, 
+	{"pick", ST_EFF_MCHAN | ST_EFF_CHAN, 
 		st_pick_getopts, st_pick_start, st_pick_flow, 
 		st_null_drain, st_pick_stop},
 	{"pitch", 0,
@@ -729,7 +729,7 @@
 	{"speed", 0, 
 		st_speed_getopts, st_speed_start, 
 		st_speed_flow, st_speed_drain, st_speed_stop},
-	{"split", ST_EFF_CHAN, 
+	{"split", ST_EFF_MCHAN | ST_EFF_CHAN, 
 		st_split_getopts, st_split_start, st_split_flow, 
 		st_null_drain, st_split_stop},
 	{"stat", ST_EFF_MCHAN | ST_EFF_REPORT,
--- a/src/resample.c
+++ b/src/resample.c
@@ -285,7 +285,7 @@
 	Nx = Nproc - r->Xread; /* space for right-wing future-data */
 	if (Nx <= 0)
 	{
-		st_fail("Nx not positive: %d", Nx);
+		st_fail("resample: Can not handle this sample rate change. Nx not positive: %d", Nx);
 		return (ST_EOF);
 	}
 	if (Nx > *isamp)