shithub: sox

Download patch

ref: af257fcf44a4bb60b8ecb593fae7fcb16290c525
parent: c58705f3fb68ede18ec726e3852c3a0cc2057337
author: cbagwell <cbagwell>
date: Thu Sep 9 22:54:18 EDT 2004

Fadeout bugfix and new crossfade script

--- a/Changelog
+++ b/Changelog
@@ -32,6 +32,10 @@
     the input file, it changes volume before effects engine
     and when specified with output file, its done after effects
     engine.
+  o Added crossfade_cat.sh script that will concatenate to
+    audio files and do a crossfade between them.
+  o Fixed bug in fade effect were it was impossible to do a
+    fadeout starting from the beginning of the audio file.
 
 sox-12.17.5
 -----------
--- /dev/null
+++ b/scripts/crossfade_cat.sh
@@ -1,0 +1,85 @@
+#!/bin/bash
+#
+# crossfade_cat.sh
+#
+# Original script from Kester Clegg.  Mods by Chris Bagwell to show
+# more examples of sox features.
+# Concatenates two files together with a crossfade of $1 seconds.
+# Filenames are specified as $2 and $3.
+#
+# By default, script fades out first file and fades in second file.
+# This makes sure that we can mix the two files together with
+# no clipping of audio.  If that option is overridden then the
+# user must make sure no clipping can occur themselves.
+#
+# $4 is optional and specifies if a fadeout should be performed on
+# first file.
+# $5 is optional and specifies if a fadein should be performed on
+# second file.
+#
+# Crossfaded file is created as "mix.wav".
+
+SOX=/home/cbagwell/sox/src/sox
+SOXMIX=/home/cbagwell/sox/src/soxmix
+
+if [ "$3" == "" ]; then
+    echo "Usage: $0 crossfade_seconds first_file second_file [ fadeout ] [ fadein ]"
+    echo
+    echo "If a fadeout or fadein is not desire then specify \"no\" for that option"
+    exit 1
+fi
+
+fade_length=$1
+first_file=$2
+second_file=$3
+
+fade_first="yes"
+if [ "$4" != "" ]; then
+    fade_first=$4
+fi
+
+fade_second="yes"
+if [ "$5" != "" ]; then
+    fade_second=$5
+fi
+
+fade_first_opts=
+if [ "$fade_first" == "yes" ]; then
+    fade_first_opts="fade h 0 0:0:$fade_length"
+fi
+
+fade_second_opts=
+if [ "$fade_second" == "yes" ]; then
+    fade_second_opts="fade h 0:0:$fade_length"
+fi
+
+echo "crossfade and concatenate files"
+echo
+echo  "Finding length of $first_file..."
+first_length=`$SOX "$first_file" 2>&1 -e stat | grep Length | cut -d : -f 2 | cut -d . -f 1 | cut -f 1`
+echo "Length is $first_length"
+
+trim_length=`expr $first_length - $fade_length`
+
+# Get crossfade section from first file and optionally do the fade out
+echo "Obtaining $fade_length seconds of fade out portion from $first_file..."
+$SOX "$first_file" -s -w fadeout.wav trim $trim_length $fade_first_opts
+# Get the crossfade section from the second file and optionally do the fade in
+echo "Obtaining $fade_length seconds of fade in portion from $second_file..."
+$SOX "$second_file" -s -w fadein.wav trim 0 $fade_length $fade_second_opts
+# Mix the crossfade files together at full volume
+echo "Crossfading..."
+$SOXMIX -v 1.0 fadeout.wav -v 1.0 fadein.wav crossfade.wav
+
+echo "Trimming off crossfade sections from original files..."
+
+$SOX "$first_file" -s -w song1.wav trim 0 $trim_length
+$SOX "$second_file" -s -w song2.wav trim $fade_length
+$SOX song1.wav crossfade.wav song2.wav mix.wav
+
+echo -e "Removing temporary files...\n" 
+rm fadeout.wav fadein.wav crossfade.wav song1.wav song2.wav
+mins=`expr $trim_length / 60`
+secs=`expr $trim_length % 60`
+echo "The crossfade in mix.wav occurs at around $mins mins $secs secs"
+
--- a/sox.1
+++ b/sox.1
@@ -840,8 +840,9 @@
 
 For fade-outs, the audio data will be truncated at the stop-time and
 the volume will be ramped from full volume down to 0 starting at
-\fIfade-out-length\fR seconds before the \fIstop-time\fR.  No fade-out
-is performed if these options are not specified.
+\fIfade-out-length\fR seconds before the \fIstop-time\fR.  If fade-out-length
+is not specified, it defaults to the same value as fade-in-length.
+No fade-out is performed if the stop-time is not specified.
 .br
 All times can be specified in either periods of time or sample counts.
 To specify time periods use the format hh:mm:ss.frac format.  To specify
--- a/sox.txt
+++ b/sox.txt
@@ -668,8 +668,10 @@
 
 		 For  fade-outs, the audio data will be truncated at the stop-
 		 time and the volume will be ramped from full volume down to 0
-		 starting at fade-out-length seconds before the stop-time.  No
-		 fade-out is performed if these options are not specified.
+		 starting at fade-out-length seconds before the stop-time.  If
+		 fade-out-length is not specified, it  defaults	 to  the  same
+		 value	as  fade-in-length.   No  fade-out is performed if the
+		 stop-time is not specified.
 		 All times can be specified in either periods of time or  sam-
 		 ple   counts.	  To  specify  time  periods  use  the	format
 		 hh:mm:ss.frac format.	To specify using sample counts,	 spec-
--- a/src/fade.c
+++ b/src/fade.c
@@ -30,10 +30,11 @@
     st_size_t in_start,  in_stop, out_start, out_stop, samplesdone;
     char *in_stop_str, *out_start_str, *out_stop_str;
     char in_fadetype, out_fadetype;
+    char do_out;
     int endpadwarned;
 } *fade_t;
 
-#define FADE_USAGE "Usage: fade [ type ] fade-in-length [ stop-time [ fade-out-length ] ]\nTimes in seconds.\nFade type one of q, h, t, l or p.\n"
+#define FADE_USAGE "Usage: fade [ type ] fade-in-length [ stop-time [ fade-out-length ] ]\nTimes is hh:mm:ss.fac format.\nFade type one of q, h, t, l or p.\n"
 
 /* prototypes */
 static double fade_gain(st_size_t index, st_size_t range, char fadetype);
@@ -86,10 +87,10 @@
     strcpy(fade->in_stop_str,argv[0]);
     /* Do a dummy parse to see if it will fail */
     if (st_parsesamples(0, fade->in_stop_str, &fade->in_stop, 't') !=
-	    ST_SUCCESS)
+            ST_SUCCESS)
     {
-	st_fail(FADE_USAGE);
-	return(ST_EOF);
+        st_fail(FADE_USAGE);
+        return(ST_EOF);
     }
 
     fade->out_start_str = fade->out_stop_str = 0;
@@ -107,13 +108,13 @@
             }
              strcpy(fade->out_stop_str,argv[t_argno]);
 
-	     /* Do a dummy parse to see if it will fail */
-	     if (st_parsesamples(0, fade->out_stop_str, 
-			 &fade->out_stop, 't') != ST_SUCCESS)
-	     {
-		 st_fail(FADE_USAGE);
-		 return(ST_EOF);
-	     }
+             /* Do a dummy parse to see if it will fail */
+             if (st_parsesamples(0, fade->out_stop_str, 
+                         &fade->out_stop, 't') != ST_SUCCESS)
+             {
+                 st_fail(FADE_USAGE);
+                 return(ST_EOF);
+             }
         }
         else
         {
@@ -125,13 +126,13 @@
             }
              strcpy(fade->out_start_str,argv[t_argno]);
 
-	     /* Do a dummy parse to see if it will fail */
-	     if (st_parsesamples(0, fade->out_start_str, 
-			 &fade->out_start, 't') != ST_SUCCESS)
-	     {
-		 st_fail(FADE_USAGE);
-		 return(ST_EOF);
-	     }
+             /* Do a dummy parse to see if it will fail */
+             if (st_parsesamples(0, fade->out_start_str, 
+                         &fade->out_start, 't') != ST_SUCCESS)
+             {
+                 st_fail(FADE_USAGE);
+                 return(ST_EOF);
+             }
         }
     } /* End for(t_argno) */
 
@@ -155,9 +156,11 @@
         return(ST_EOF);
     }
 
+    fade->do_out = 0;
     /* See if user specified a stop time */
     if (fade->out_stop_str)
     {
+        fade->do_out = 1;
         if (st_parsesamples(effp->ininfo.rate, fade->out_stop_str,
                             &fade->out_stop, 't') != ST_SUCCESS)
         {
@@ -164,31 +167,30 @@
             st_fail(FADE_USAGE);
             return(ST_EOF);
         }
-	fade->out_stop += fade->out_start;
 
-	/* See if user wants to fade out. */
-	if (fade->out_start_str)
-	{
-	    if (st_parsesamples(effp->ininfo.rate, fade->out_start_str,
-			&fade->out_start, 't') != ST_SUCCESS)
-	    {
-		st_fail(FADE_USAGE);
-		return(ST_EOF);
-	    }
-	    /* Fade time is relative to stop time. */
-	    fade->out_start = fade->out_stop - fade->out_start;
+        /* See if user wants to fade out. */
+        if (fade->out_start_str)
+        {
+            if (st_parsesamples(effp->ininfo.rate, fade->out_start_str,
+                        &fade->out_start, 't') != ST_SUCCESS)
+            {
+                st_fail(FADE_USAGE);
+                return(ST_EOF);
+            }
+            /* Fade time is relative to stop time. */
+            fade->out_start = fade->out_stop - fade->out_start;
 
-	}
-	else
-	    /* If user doesn't want to fade out then set to stop
-	     * time.
-	     */
-	    fade->out_start = fade->out_stop;
+        }
+        else
+            /* If no start time specified, assume everything
+             * after fadein.
+             */
+            fade->out_start = fade->in_stop;
     }
     else
-	/* If not specified then user doesn't wants to process all 
-	 * of file.  Use a value of zero to indicate this.
-	 */
+        /* If not specified then user doesn't wants to process all 
+         * of file.  Use a value of zero to indicate this.
+         */
         fade->out_stop = 0;
 
     /* Sanity check for fade times vs total time */
@@ -211,7 +213,7 @@
  * Return number of samples processed.
  */
 int st_fade_flow(eff_t effp, st_sample_t *ibuf, st_sample_t *obuf, 
-	         st_size_t *isamp, st_size_t *osamp)
+                 st_size_t *isamp, st_size_t *osamp)
 {
     fade_t fade = (fade_t) effp->priv;
     /* len is total samples, chcnt counts channels */
@@ -239,12 +241,12 @@
             } /* endif fade-in */
 
             if (fade->samplesdone >= fade->in_stop &&
-                (fade->out_start == 0 || fade->samplesdone < fade->out_start))
+                (!fade->do_out || fade->samplesdone < fade->out_start))
             { /* steady gain phase */
                 *obuf = t_ibuf;
             } /* endif  steady phase */
 
-            if (fade->out_start != 0 && fade->samplesdone >= fade->out_start)
+            if (fade->do_out && fade->samplesdone >= fade->out_start)
             { /* fade-out phase, decrease gain */
                 *obuf = t_ibuf *
                     fade_gain(fade->out_stop - fade->samplesdone,