shithub: sox

Download patch

ref: d6f4cbe9d7570431dd9b56210cd0da17976a442b
parent: 9443899c13d7a00b1d8dc07fb14735379ea8f2d1
author: cbagwell <cbagwell>
date: Fri Sep 17 23:15:04 EDT 2004

Attempt seek()'s when using trim effect for speed.

--- a/Changelog
+++ b/Changelog
@@ -46,6 +46,9 @@
   o When effects output data and reported ST_EOF at the
     same time, that buffer was discarded as well as
     data from any chained effect.
+  o Added patch from Eric Benson that attempts to do a seek()
+    if the first effect is trim.  This greatly speeds up
+    processing large files.
 
 sox-12.17.5
 -----------
--- a/src/aiff.c
+++ b/src/aiff.c
@@ -73,14 +73,22 @@
 
 int st_aiffseek(ft_t ft, st_size_t offset) 
 {
-        aiff_t aiff = (aiff_t ) ft->priv;
+    aiff_t aiff = (aiff_t ) ft->priv;
+    st_size_t new_offset, align;
 
-        ft->st_errno = st_seek(ft,offset*ft->info.size + aiff->dataStart,SEEK_SET);
+    new_offset = offset * ft->info.size;
+    /* Make sure requests aligns to a channel offset */
+    align = new_offset % (ft->info.channels*ft->info.size);
+    if (align != 0)
+        new_offset += align;
+    new_offset += aiff->dataStart;
 
-        if( ft->st_errno == ST_SUCCESS )
-                aiff->nsamples = ft->length - offset;
+    ft->st_errno = st_seek(ft, new_offset, SEEK_SET);
 
-        return(ft->st_errno);
+    if (ft->st_errno == ST_SUCCESS)
+        aiff->nsamples = ft->length - new_offset;
+
+    return(ft->st_errno);
 }
 
 int st_aiffstartread(ft_t ft) 
--- a/src/au.c
+++ b/src/au.c
@@ -103,14 +103,27 @@
 
 int st_auseek(ft_t ft, st_size_t offset) 
 {
-        au_t au = (au_t ) ft->priv;
+    au_t au = (au_t ) ft->priv;
 
-        if (au->dec_routine != NULL)
-                st_fail_errno(ft,ST_ENOTSUP,"Sorry, DEC unsupported");
-        else 
-                return st_seek(ft,offset*ft->info.size + au->dataStart,SEEK_SET);
+    if (au->dec_routine != NULL)
+    {
+        st_fail_errno(ft,ST_ENOTSUP,"Sorry, DEC unsupported");
+    }
+    else 
+    {
+        st_size_t new_offset, align;
 
-        return(ft->st_errno);
+        new_offset = offset * ft->info.size;
+        /* Make sure requests aligns to a channel offset */
+        align = new_offset % (ft->info.channels*ft->info.size);
+        if (align != 0)
+            new_offset += align;
+        new_offset += au->dataStart;
+
+        ft->st_errno = st_seek(ft, new_offset, SEEK_SET);
+    }
+
+    return(ft->st_errno);
 }
 
 int st_austartread(ft_t ft) 
--- a/src/prc.c
+++ b/src/prc.c
@@ -44,9 +44,17 @@
 
 int st_prcseek(ft_t ft, st_size_t offset)
 {
-        prc_t prc = (prc_t ) ft->priv;
+    prc_t prc = (prc_t ) ft->priv;
+    st_size_t new_offset, align;
 
-        return st_seek(ft,offset*ft->info.size + prc->dataStart,SEEK_SET);
+    new_offset = offset * ft->info.size;
+    /* Make sure requests aligns to a channel offset */
+    align = new_offset % (ft->info.channels*ft->info.size);
+    if (align != 0)
+        new_offset += align;
+    new_offset += prc->dataStart;
+
+    return st_seek(ft, new_offset, SEEK_SET);
 }
 
 int st_prcstartread(ft_t ft)
@@ -82,10 +90,10 @@
         }
 
         st_readw(ft, &(len));
-	p->length=len;
-	st_report("Found length=%d",len);
+        p->length=len;
+        st_report("Found length=%d",len);
 
-	/* dummy read rest */
+        /* dummy read rest */
         st_read(ft, head,1,14+2+2);
 
         ft->info.encoding = ST_ENCODING_ALAW;
@@ -159,7 +167,7 @@
 {
         prc_t p = (prc_t ) ft->priv;
         p->length += samp * ft->info.size;
-	st_report("length now = %d", p->length);
+        st_report("length now = %d", p->length);
         return st_rawwrite(ft, buf, samp);
 }
 
@@ -180,7 +188,7 @@
                 return(ST_EOF);
         }
         prcwriteheader(ft);
-	return ST_SUCCESS;
+        return ST_SUCCESS;
 }
 
 static void prcwriteheader(ft_t ft)
--- a/src/raw.c
+++ b/src/raw.c
@@ -83,6 +83,8 @@
 
 int st_rawseek(ft_t ft, st_size_t offset)
 {
+    st_size_t new_offset, align;
+
     switch(ft->info.size) {
         case ST_SIZE_BYTE:
         case ST_SIZE_WORD:
@@ -94,7 +96,13 @@
             return ft->st_errno;
     }
 
-    ft->st_errno = st_seek(ft,offset*ft->info.size,SEEK_SET);
+    new_offset = offset * ft->info.size;
+    /* Make sure requests aligns to a channel offset */
+    align = new_offset % (ft->info.channels*ft->info.size);
+    if (align != 0)
+        new_offset += align;
+
+    ft->st_errno = st_seek(ft, new_offset, SEEK_SET);
 
     return ft->st_errno;
 }
--- a/src/sf.c
+++ b/src/sf.c
@@ -70,10 +70,17 @@
 
 int st_sfseek(ft_t ft, st_size_t offset)
 {
-        sf_t sf = (sf_t ) ft->priv;
+    st_size_t new_offset, align;
 
-        return st_seek(ft,offset*ft->info.size + sf->dataStart,SEEK_SET);
+    sf_t sf = (sf_t ) ft->priv;
+    new_offset = offset * ft->info.size;
+    /* Make sure requests aligns to a channel offset */
+    align = new_offset % (ft->info.channels*ft->info.size);
+    if (align != 0)
+        new_offset += align;
+    new_offset += sf->dataStart;
 
+    return st_seek(ft, new_offset, SEEK_SET);
 }
 
 /*
--- a/src/smp.c
+++ b/src/smp.c
@@ -171,14 +171,22 @@
 
 int st_smpseek(ft_t ft, st_size_t offset) 
 {
-        smp_t smp = (smp_t) ft->priv;
+    int new_offset, align;
+    smp_t smp = (smp_t) ft->priv;
 
-        ft->st_errno = st_seek(ft,offset*ft->info.size + smp->dataStart,SEEK_SET);
+    new_offset = offset * ft->info.size;
+    /* Make sure requests aligns to a channel offset */
+    align = new_offset % (ft->info.channels*ft->info.size);
+    if (align != 0)
+        new_offset += align;
+    new_offset += smp->dataStart;
 
-        if( ft->st_errno == ST_SUCCESS )
-                smp->NoOfSamps = ft->length - offset;
+    ft->st_errno = st_seek(ft, new_offset, SEEK_SET);
 
-        return(ft->st_errno);
+    if( ft->st_errno == ST_SUCCESS )
+        smp->NoOfSamps = ft->length - new_offset;
+
+    return(ft->st_errno);
 }
 /*
  * Do anything required before you start reading samples.
--- a/src/sndrtool.c
+++ b/src/sndrtool.c
@@ -16,17 +16,17 @@
 #include <errno.h>
 #endif
 #ifdef HAVE_UNISTD_H
-#include <unistd.h>	/* For SEEK_* defines if not found in stdio */
+#include <unistd.h>     /* For SEEK_* defines if not found in stdio */
 #endif
 
 /* Private data used by writer */
 typedef struct sndpriv {
         st_size_t nsamples;
-	st_size_t dataStart;
+        st_size_t dataStart;
 } *snd_t;
 
-#ifndef	SEEK_CUR
-#define	SEEK_CUR	1
+#ifndef SEEK_CUR
+#define SEEK_CUR        1
 #endif
 
 static void  sndtwriteheader(ft_t ft, st_size_t nsamples);
@@ -33,10 +33,17 @@
 
 int st_sndseek(ft_t ft, st_size_t offset) 
 {
-	snd_t snd = (snd_t ) ft->priv;
+    st_size_t new_offset, align;
+    snd_t snd = (snd_t ) ft->priv;
 
-	return st_seek(ft,offset*ft->info.size + snd->dataStart,SEEK_SET);
+    new_offset = offset * ft->info.size;
+    /* Make sure requests aligns to a channel offset */
+    align = new_offset % (ft->info.channels*ft->info.size);
+    if (align != 0)
+        new_offset += align;
+    new_offset += snd->dataStart;
 
+    return st_seek(ft, new_offset, SEEK_SET);
 }
 /*======================================================================*/
 /*                         SNDSTARTREAD                                */
@@ -44,69 +51,69 @@
 
 int st_sndtstartread(ft_t ft)
 {
-	snd_t snd = (snd_t ) ft->priv;
+        snd_t snd = (snd_t ) ft->priv;
 
         char buf[97];
 
         unsigned short rate;
-	int rc;
+        int rc;
 
-	/* Needed for rawread() */
-	rc = st_rawstartread(ft);
-	if (rc)
-	    return rc;
+        /* Needed for rawread() */
+        rc = st_rawstartread(ft);
+        if (rc)
+            return rc;
 
-	/* sndt is in little endian format so 
-	 * swap bytes on big endian machines.
-	 */
-	if (ST_IS_BIGENDIAN)
-	{
-		ft->swap = ft->swap ? 0 : 1;
-	}
+        /* sndt is in little endian format so 
+         * swap bytes on big endian machines.
+         */
+        if (ST_IS_BIGENDIAN)
+        {
+                ft->swap = ft->swap ? 0 : 1;
+        }
 
-	rate = 0;
+        rate = 0;
 
-	/* determine file type */
+        /* determine file type */
         /* if first 5 bytes == SOUND then this is probably a sndtool sound */
         /* if first word (16 bits) == 0 
          and second word is between 4000 & 25000 then this is sounder sound */
         /* otherwise, its probably raw, not handled here */
 
-	if (fread(buf, 1, 2, ft->fp) != 2)
-	{
-		st_fail_errno(ft,errno,"SND: unexpected EOF");
-		return(ST_EOF);
-	}
-	if (strncmp(buf,"\0\0",2) == 0)
-	{
-	/* sounder */
-	st_readw(ft, &rate);
-	if (rate < 4000 || rate > 25000 )
-	{
-		st_fail_errno(ft,ST_EFMT,"SND: sample rate out of range");
-		return(ST_EOF);
-	}
-	fseek(ft->fp,4,SEEK_CUR);
-	}
-	else
-	{
-	/* sndtool ? */
-	fread(&buf[2], 1, 6, ft->fp);
-	if (strncmp(buf,"SOUND",5))
-	{
-		st_fail_errno(ft,ST_EFMT,"SND: unrecognized SND format");
-		return(ST_EOF);
-	}
-	fseek(ft->fp,12,SEEK_CUR);
-	st_readw(ft, &rate);
-	fseek(ft->fp,6,SEEK_CUR);
-	if (st_reads(ft, buf, 96) == ST_EOF)
-	{
-		st_fail_errno(ft,ST_EHDR,"SND: unexpected EOF in SND header");
-		return(ST_EOF);
-	}
-	st_report("%s",buf);
-	}
+        if (fread(buf, 1, 2, ft->fp) != 2)
+        {
+                st_fail_errno(ft,errno,"SND: unexpected EOF");
+                return(ST_EOF);
+        }
+        if (strncmp(buf,"\0\0",2) == 0)
+        {
+        /* sounder */
+        st_readw(ft, &rate);
+        if (rate < 4000 || rate > 25000 )
+        {
+                st_fail_errno(ft,ST_EFMT,"SND: sample rate out of range");
+                return(ST_EOF);
+        }
+        fseek(ft->fp,4,SEEK_CUR);
+        }
+        else
+        {
+        /* sndtool ? */
+        fread(&buf[2], 1, 6, ft->fp);
+        if (strncmp(buf,"SOUND",5))
+        {
+                st_fail_errno(ft,ST_EFMT,"SND: unrecognized SND format");
+                return(ST_EOF);
+        }
+        fseek(ft->fp,12,SEEK_CUR);
+        st_readw(ft, &rate);
+        fseek(ft->fp,6,SEEK_CUR);
+        if (st_reads(ft, buf, 96) == ST_EOF)
+        {
+                st_fail_errno(ft,ST_EHDR,"SND: unexpected EOF in SND header");
+                return(ST_EOF);
+        }
+        st_report("%s",buf);
+        }
 
 ft->info.channels = 1;
 ft->info.rate = rate;
@@ -124,21 +131,21 @@
 /*======================================================================*/
 int st_sndtstartwrite(ft_t ft)
 {
-	snd_t p = (snd_t ) ft->priv;
-	int rc;
+        snd_t p = (snd_t ) ft->priv;
+        int rc;
 
-	/* Needed for rawwrite() */
-	rc = st_rawstartwrite(ft);
-	if (rc)
-	    return rc;
+        /* Needed for rawwrite() */
+        rc = st_rawstartwrite(ft);
+        if (rc)
+            return rc;
 
-	/* sndt is in little endian format so
-	 * swap bytes on big endian machines
-	 */
-	if (ST_IS_BIGENDIAN)
-	{
-		ft->swap = ft->swap ? 0 : 1;
-	}
+        /* sndt is in little endian format so
+         * swap bytes on big endian machines
+         */
+        if (ST_IS_BIGENDIAN)
+        {
+                ft->swap = ft->swap ? 0 : 1;
+        }
 
 /* write header */
 ft->info.channels = 1;
@@ -155,20 +162,20 @@
 /*======================================================================*/
 int st_sndrstartwrite(ft_t ft)
 {
-	int rc;
+        int rc;
 
-	/* Needed for rawread() */
-	rc = st_rawstartread(ft);
-	if (rc)
-	    return rc;
+        /* Needed for rawread() */
+        rc = st_rawstartread(ft);
+        if (rc)
+            return rc;
 
-	/* sndr is in little endian format so
-	 * swap bytes on big endian machines
-	 */
-	if (ST_IS_BIGENDIAN)
-	{
-		ft->swap = ft->swap ? 0 : 1;
-	}
+        /* sndr is in little endian format so
+         * swap bytes on big endian machines
+         */
+        if (ST_IS_BIGENDIAN)
+        {
+                ft->swap = ft->swap ? 0 : 1;
+        }
 
 /* write header */
 ft->info.channels = 1;
@@ -190,9 +197,9 @@
 
 st_ssize_t st_sndtwrite(ft_t ft, st_sample_t *buf, st_ssize_t len)
 {
-	snd_t p = (snd_t ) ft->priv;
-	p->nsamples += len;
-	return st_rawwrite(ft, buf, len);
+        snd_t p = (snd_t ) ft->priv;
+        p->nsamples += len;
+        return st_rawwrite(ft, buf, len);
 }
 
 /*======================================================================*/
@@ -201,24 +208,24 @@
 
 int st_sndtstopwrite(ft_t ft)
 {
-	snd_t p = (snd_t ) ft->priv;
-	int rc;
+        snd_t p = (snd_t ) ft->priv;
+        int rc;
 
-	/* Flush remaining buffer out */
-	rc = st_rawstopwrite(ft);
-	if (rc)
-	    return rc;
+        /* Flush remaining buffer out */
+        rc = st_rawstopwrite(ft);
+        if (rc)
+            return rc;
 
-	/* fixup file sizes in header */
-	if (fseek(ft->fp, 0L, 0) != 0){
-		st_fail_errno(ft,errno,"can't rewind output file to rewrite SND header");
-		return ST_EOF;
-	}
-		
-	sndtwriteheader(ft, p->nsamples);
-		
-
-	return(ST_SUCCESS);
+        /* fixup file sizes in header */
+        if (fseek(ft->fp, 0L, 0) != 0){
+                st_fail_errno(ft,errno,"can't rewind output file to rewrite SND header");
+                return ST_EOF;
+        }
+                
+        sndtwriteheader(ft, p->nsamples);
+                
+
+        return(ST_SUCCESS);
 }
 
 /*======================================================================*/
--- a/src/sox.c
+++ b/src/sox.c
@@ -526,6 +526,59 @@
     return ST_SUCCESS;
 }
 
+void optimize_trim(void)
+{
+    int f;
+
+    /* Speed hack.  If the "trim" effect is the first effect then
+     * peak inside its "effect descriptor" and see what the
+     * start location is.  This has to be done after the start()
+     * is called to have the correct location.
+     */
+    if (neffects > 1 && strcmp(efftab[1].name, "trim") == 0)
+    {
+        int ok_to_seek = 1;
+        int seek_worked = 1;
+
+        /* Make sure all support seeking */
+        for (f = 0; f < input_count; f++)
+        {
+            if (!(file_desc[f]->h->flags & ST_FILE_SEEK) || 
+                !file_desc[f]->seekable)
+                ok_to_seek = 0;
+        }
+        if (ok_to_seek)
+        {
+            for (f = 0; f < input_count; f++)
+            {
+                if (file_desc[f]->h->seek(file_desc[f], 
+                                          st_trim_get_seek(&efftab[1])) == ST_EOF)
+                {
+                    seek_worked = 0;
+                    break;
+                }
+            }
+            /* If any seek didn't work then try our best to go back
+             * to the beginning of file and do it the slow way.
+             * This can easily happen if some input files are shorter
+             * then the rest.  Code below will fill in silence
+             * for those cases.
+             */
+            if (!seek_worked)
+            {
+                for (f = 0; f < input_count; f++)
+                {
+                    file_desc[f]->h->seek(file_desc[f], 0);
+                }
+            }
+            else
+            {
+                st_trim_clear_start(&efftab[1]);
+            }
+        }
+    }
+}
+
 /*
  * Process input file -> effect table -> output file
  *      one buffer at a time
@@ -639,6 +692,9 @@
             }
         }
     }
+
+    /* Try to save some time if first effect is "trim" by seeking */
+    optimize_trim();
 
 #ifdef SOXMIX
     for (f = 0; f < MAX_INPUT_FILES; f++)
--- a/src/st_i.h
+++ b/src/st_i.h
@@ -595,6 +595,8 @@
 int st_trim_flow(eff_t effp, st_sample_t *ibuf, st_sample_t *obuf,
                  st_size_t *isamp, st_size_t *osamp);
 int st_trim_stop(eff_t effp);
+st_size_t st_trim_get_seek(eff_t effp);
+void st_trim_clear_start(eff_t effp);
 
 int st_vibro_getopts(eff_t effp, int argc, char **argv);
 int st_vibro_start(eff_t effp);
--- a/src/trim.c
+++ b/src/trim.c
@@ -207,7 +207,14 @@
     return (ST_SUCCESS);
 }
 
+st_size_t st_trim_get_seek(eff_t effp)
+{
+    trim_t trim = (trim_t)effp->priv;
+    return trim->start;
+}
 
-
-
-
+void st_trim_clear_start(eff_t effp)
+{
+    trim_t trim = (trim_t)effp->priv;
+    trim->start = 0;
+}
--- a/src/wav.c
+++ b/src/wav.c
@@ -1638,23 +1638,31 @@
 
 int st_wavseek(ft_t ft, st_size_t offset) 
 {
-        wav_t   wav = (wav_t) ft->priv;
+    wav_t   wav = (wav_t) ft->priv;
+    int new_offset, align;
 
-        switch (wav->formatTag)
-        {
+    switch (wav->formatTag)
+    {
         case WAVE_FORMAT_IMA_ADPCM:
         case WAVE_FORMAT_ADPCM:
 #ifdef ENABLE_GSM
         case WAVE_FORMAT_GSM610:
 #endif
-                st_fail_errno(ft,ST_ENOTSUP,"Only PCM Supported");
+            st_fail_errno(ft,ST_ENOTSUP,"Only PCM Supported");
             break;
         default:
-                ft->st_errno = st_seek(ft,offset*ft->info.size + wav->dataStart, SEEK_SET);
-        }
+            new_offset = offset * ft->info.size;
+            /* Make sure requests aligns to a channel offset */
+            align = new_offset % (ft->info.channels*ft->info.size);
+            if (align != 0)
+                new_offset += align;
+            new_offset += wav->dataStart;
 
-        if( ft->st_errno == ST_SUCCESS )
-                wav->numSamples = ft->length - offset;
+            ft->st_errno = st_seek(ft, new_offset, SEEK_SET);
+    }
 
-        return(ft->st_errno);
+    if( ft->st_errno == ST_SUCCESS )
+        wav->numSamples = ft->length - new_offset;
+
+    return(ft->st_errno);
 }
--- a/src/wve.c
+++ b/src/wve.c
@@ -29,9 +29,17 @@
 
 int st_wveseek(ft_t ft, st_size_t offset)
 {
-        wve_t wve = (wve_t ) ft->priv;
+    int new_offset, align;
+    wve_t wve = (wve_t ) ft->priv;
 
-        return st_seek(ft,offset*ft->info.size + wve->dataStart,SEEK_SET);
+    new_offset = offset * ft->info.size;
+    /* Make sure requests aligns to a channel offset */
+    align = new_offset % (ft->info.channels*ft->info.size);
+    if (align != 0)
+        new_offset += align;
+    new_offset += wve->dataStart;
+
+    return st_seek(ft, offset, SEEK_SET);
 }
 
 int st_wvestartread(ft_t ft)