diff -ru --exclude CVS sox.20031125/sox.c sox-12.17.5cvs/sox.c
--- sox.20031125/sox.c	2002-12-31 02:08:48.000000000 +0100
+++ sox-12.17.5cvs/sox.c	2003-12-16 12:28:07.000000000 +0100
@@ -49,6 +49,17 @@
 #endif
 #endif
 
+#include <sys/time.h>		/* for gettimeofday() */
+#include <fcntl.h>		/* for fcntl() */
+
+#if defined(INTERACTIVE)
+#include <ncurses.h>
+#include <time.h>
+#if defined(RZM)
+#include <ctype.h>
+#endif
+#endif
+
 /*
  * SOX main program.
  *
@@ -68,6 +79,9 @@
 static st_sample_t ibufr[ST_BUFSIZ/2];
 static st_sample_t obufl[ST_BUFSIZ/2];
 static st_sample_t obufr[ST_BUFSIZ/2];
+#if defined(INTERACTIVE)
+WINDOW	*win;
+#endif
 
 /* local forward declarations */
 static void doopts(ft_t, int, char **);
@@ -77,13 +91,21 @@
 static void open_output(ft_t);
 static void usage(char *) NORET;
 static int filetype(int);
+void parse_eff(int argc, char **argv, struct st_effect user_efftab[], int *pnuser_effects);
 static void process(void);
 static void statistics(void);
 static st_sample_t volumechange(st_sample_t *buf, st_ssize_t ct, double vol);
-static void checkeffect(void);
+static void checkeffect(int *pneffects);
 static int flow_effect_out(void);
 static int flow_effect(int);
 static int drain_effect(int);
+#if defined(INTERACTIVE)
+static void init_curses(WINDOW **pwin, ft_t ft);
+static void stop_curses(WINDOW *win);
+static void draw_fixed(WINDOW *win, float ttime);
+static void draw_pos(WINDOW *win, float pos);
+int interactive(WINDOW *win);
+#endif
 
 #ifdef SOXMIX
 #define MAX_INPUT_FILES 2
@@ -116,7 +138,7 @@
  * In efftab's, location 0 is always the input stream.
  *
  * If one was to support effects for quad-channel files, there would
- * need to be an effect tabel for each channel.
+ * need to be an effect table for each channel.
  */
 
 static struct st_effect efftab[MAX_EFF]; /* left/mono channel effects */
@@ -125,12 +147,12 @@
 
 static struct st_effect user_efftab[MAX_USER_EFF];
 static int nuser_effects;
+static float speed = 1;
 
 int main(argc, argv)
 int argc;
 char **argv;
 {
-        int argc_effect;
         ft_t ft;
         int parsing_output = 0;
 	int i;
@@ -236,7 +258,7 @@
             }
         }
 
-        /* Make sure we got at least the required # of input filename */
+        /* Make sure we got at least the required # of input filenames */
         if (input_count < REQUIRED_INPUT_FILES ||
             !informat[REQUIRED_INPUT_FILES-1] ||
             !informat[REQUIRED_INPUT_FILES-1]->filename)
@@ -245,41 +267,7 @@
         if (!outformat || (!outformat->filename && writing))
             usage("No output file?");
 
-        /* Loop through the reset of the arguments looking for effects */
-        nuser_effects = 0;
-
-        while (optind < argc)
-        {
-            if (nuser_effects >= MAX_USER_EFF)
-            {
-                st_fail("To many effects specified.\n");
-            }
-
-            argc_effect = st_geteffect_opt(&user_efftab[nuser_effects],
-                                           argc - optind, &argv[optind]);
-
-            if (argc_effect == ST_EOF)
-            {
-                int i1;
-                fprintf(stderr, "%s: Known effects: ",myname);
-                for (i1 = 0; st_effects[i1].name; i1++)
-                    fprintf(stderr, "%s ", st_effects[i1].name);
-                fprintf(stderr, "\n\n");
-                st_fail("Effect '%s' is not known!", argv[optind]);
-            }
-
-
-            /* Skip past effect name */
-            optind++;
-
-            (*user_efftab[nuser_effects].h->getopts)(&user_efftab[nuser_effects],
-                                                     argc_effect,
-                                                     &argv[optind]);
-
-            /* Skip past the effect arguments */
-            optind += argc_effect;
-            nuser_effects++;
-        }
+	parse_eff(argc, argv, user_efftab, &nuser_effects);
 
         if (dovolume)
             st_report("Volume factor: %f\n", volume);
@@ -559,13 +547,123 @@
 }
 #endif
 
+/* Loop through the rest of the arguments looking for effects */
+void parse_eff(int argc, char **argv, struct st_effect user_efftab[], int *pnuser_effects) {
+        int argc_effect;
+
+        *pnuser_effects = 0;
+
+        while (optind < argc)
+        {
+            if (*pnuser_effects >= MAX_USER_EFF)
+            {
+                st_fail("To many effects specified.\n");
+            }
+
+            argc_effect = st_geteffect_opt(&user_efftab[*pnuser_effects],
+                                           argc - optind, &argv[optind]);
+
+            if (argc_effect == ST_EOF)
+            {
+                int i1;
+                fprintf(stderr, "%s: Known effects: ",myname);
+                for (i1 = 0; st_effects[i1].name; i1++)
+                    fprintf(stderr, "%s ", st_effects[i1].name);
+                fprintf(stderr, "\n\n");
+                st_fail("Effect '%s' is not known!", argv[optind]);
+            }
+
+
+            /* Skip past effect name */
+            optind++;
+
+            (*user_efftab[*pnuser_effects].h->getopts)(&user_efftab[*pnuser_effects],
+                                                     argc_effect,
+                                                     &argv[optind]);
+	    /* initializing from command line */
+	    /* if (strcmp( (user_efftab[*pnuser_effects])->name, "stretch") == 0)
+	    	speed = 1.0 / ((float)(user_efftab[*pnuser_effects]->priv));	*/
+
+            /* Skip past the effect arguments */
+            optind += argc_effect;
+            (*pnuser_effects)++;
+        }
+}
+
+/* Start all effects */
+void start_all_eff(struct st_effect efftab[], struct st_effect efftabR[], int neffects) {
+    int e;
+
+    for(e = 1; e < neffects; e++) {
+        (* efftab[e].h->start)(&efftab[e]);
+        if (efftabR[e].name)
+            (* efftabR[e].h->start)(&efftabR[e]);
+    }
+}
+
+/* Reserve an output buffer for all effects */
+void resbuf_all_eff(struct st_effect efftab[], struct st_effect efftabR[], int neffects) {
+    int e;
+
+    for(e = 0; e < neffects; e++)
+    {
+        efftab[e].obuf = (st_sample_t *) malloc(ST_BUFSIZ * 
+		                                sizeof(st_sample_t));
+        if (efftab[e].obuf == NULL)
+        {
+            st_fail("could not allocate memory");
+        }
+        if (efftabR[e].name)
+        {
+            efftabR[e].obuf = (st_sample_t *) malloc(ST_BUFSIZ * 
+		                                     sizeof(st_sample_t));
+            if (efftabR[e].obuf == NULL)
+            {
+                st_fail("could not allocate memory");
+            }
+        }
+    }
+}
+
+/* Release output buffers of all effects */
+void relbuf_all_eff(struct st_effect efftab[], struct st_effect efftabR[], int neffects) {
+    int e;
+
+    for(e = 0; e < neffects; e++)
+    {
+        free(efftab[e].obuf);
+        if (efftabR[e].obuf)
+	    free(efftabR[e].obuf);
+    }
+}
+
+/* Drain all effects */
+void drain_all_eff(int neffects) {
+    int e;
+
+    for(e = 1; e < neffects; e++) {
+        drain_effect(e);
+    }
+}
+
+/* Stop all effects */
+void stop_all_eff(struct st_effect efftab[], struct st_effect efftabR[], int neffects) {
+    int e;
+
+    for (e = 1; e < neffects; e++) {
+        (* efftab[e].h->stop)(&efftab[e]);
+        if (efftabR[e].name)
+            (* efftabR[e].h->stop)(&efftabR[e]);
+    }
+}
+
 /*
  * Process input file -> effect table -> output file
  *      one buffer at a time
  */
 
 static void process(void) {
-    int e, f, flowstatus;
+    int e, f, flowstatus = 0;
 #ifdef SOXMIX
     int s;
     st_ssize_t ilen[MAX_INPUT_FILES];
@@ -642,34 +740,13 @@
     }
 
     /* build efftab */
-    checkeffect();
+    checkeffect(&neffects);
 
     /* Start all effects */
-    for(e = 1; e < neffects; e++) {
-        (* efftab[e].h->start)(&efftab[e]);
-        if (efftabR[e].name)
-            (* efftabR[e].h->start)(&efftabR[e]);
-    }
+    start_all_eff(efftab, efftabR, neffects);
 
     /* Reserve an output buffer for all effects */
-    for(e = 0; e < neffects; e++)
-    {
-        efftab[e].obuf = (st_sample_t *) malloc(ST_BUFSIZ * 
-		                                sizeof(st_sample_t));
-        if (efftab[e].obuf == NULL)
-        {
-            st_fail("could not allocate memory");
-        }
-        if (efftabR[e].name)
-        {
-            efftabR[e].obuf = (st_sample_t *) malloc(ST_BUFSIZ * 
-		                                     sizeof(st_sample_t));
-            if (efftabR[e].obuf == NULL)
-            {
-                st_fail("could not allocate memory");
-            }
-        }
-    }
+    resbuf_all_eff(efftab, efftabR, neffects);
 
 #ifdef SOXMIX
     for (f = 0; f < MAX_INPUT_FILES; f++)
@@ -690,8 +767,15 @@
         informat[f]->st_errno = 0;
     outformat->st_errno = 0;
 
+
+#if defined(INTERACTIVE)
+    init_curses(&win, informat[0]);
+#endif
+
+
     /* Run input data through effects and get more until olen == 0 */
     do {
+	int	jump = 0;
 
 #ifndef SOXMIX
         efftab[0].olen = (*informat[0]->h->read)(informat[0],
@@ -749,7 +833,12 @@
         for(e = 1; e < neffects; e++)
             efftab[e].odone = efftab[e].olen = 0;
 
-        flowstatus = flow_effect_out();
+	/* play only if we do not skip just now */
+        if (!jump) flowstatus = flow_effect_out();
+
+#if defined(INTERACTIVE)
+	jump = interactive(win);
+#endif
 
         /* Negative flowstatus says no more output will ever be generated. */
         if (flowstatus < 0 || outformat->st_errno)
@@ -757,6 +846,11 @@
 
     } while (1); /* break; efftab[0].olen == 0 */
 
+#if defined(INTERACTIVE)
+	interactive(win);
+	stop_curses(win);
+#endif
+
 #ifdef SOXMIX
     /* Free input buffers now that they are not used */
     for (f = 0; f < MAX_INPUT_FILES; f++)
@@ -786,23 +880,14 @@
     }
     
     /* Free output buffers now that they won't be used */
-    for(e = 0; e < neffects; e++)
-    {
-        free(efftab[e].obuf);
-        if (efftabR[e].obuf)
-	    free(efftabR[e].obuf);
-    }
+    relbuf_all_eff(efftab, efftabR, neffects);
 
     /* Very Important:
      * Effect stop is called BEFORE files close.
      * Effect may write out more data after.
      */
 
-    for (e = 1; e < neffects; e++) {
-        (* efftab[e].h->stop)(&efftab[e]);
-        if (efftabR[e].name)
-            (* efftabR[e].h->stop)(&efftabR[e]);
-    }
+    stop_all_eff(efftab, efftabR, neffects);
 
     for (f = 0; f < input_count; f++)
     {
@@ -984,10 +1069,10 @@
  *      Puts user-specified effect in right place.
  */
 static void
-checkeffect()
+checkeffect(int *pneffects)
 {
         int i;
-        int needchan = 0, needrate = 0, haschan = 0, hasrate = 0;
+        int needchan = 0, needrate = 0, haschan = 0, hasrate = 0, neffects;
         int effects_mask = 0;
 
         needrate = (informat[0]->info.rate != outformat->info.rate);
@@ -1147,6 +1232,9 @@
 
             neffects++;
         }
+
+	/* local into parameter */
+	*pneffects = neffects;
 }
 
 static void statistics(void) {
@@ -1248,3 +1336,184 @@
     if (outformat)
 	free(outformat);
 }
+
+
+#if defined(INTERACTIVE)
+
+#define	PTRROW	5
+
+void
+init_curses(WINDOW **pwin, ft_t ft) {
+	*pwin = initscr();
+        cbreak();
+        noecho();
+	leaveok(*pwin, TRUE);	/* reducing cursor motions */
+	nodelay(*pwin, TRUE );	/* enable */
+	keypad(stdscr, TRUE);	/* KEY_LEFT etc. */
+	curs_set(0);
+	draw_fixed(win, st_filelength(ft) / (ft->info.rate * ft->info.size * ft->info.channels));
+}
+
+void
+stop_curses(WINDOW *win) {
+	mvwprintw(win, PTRROW+2, 0, "X");
+	curs_set(1);
+}
+
+char *
+hhmmss(int time) {
+	static char	stime[30];
+	struct tm	*tm;
+	time_t		timec = time;
+
+	tm = gmtime(&timec);
+	/* mday-1 cos it is Jan 1st '70 */
+	snprintf(stime, sizeof(stime), "%3d:%02d:%02d", (tm->tm_mday-1) * 24 + tm->tm_hour, tm->tm_min, tm->tm_sec);
+	return stime;
+}
+
+void
+draw_fixed(WINDOW *win, float ttime) {
+	int	col;
+
+	mvwprintw(win, 0, 0, "Time				total: %s", hhmmss(ttime));
+	mvwprintw(win, 1, 0, "Speed");
+	mvwprintw(win, 2, 0, "%s -> %s", informat[0]->filename, outformat->filename);
+	for (col = 0; col <= COLS; col++) {
+		mvwprintw(win, PTRROW-1, col, "_");
+		mvwprintw(win, PTRROW+1, col, "^");
+	}
+}
+
+void
+draw_pos(WINDOW *win, float pos) {
+	static int	wpos = 0;
+	int		npos;
+
+	/* upper-left: (0,0) */
+	npos = (int)(pos * (COLS) + 0.0);
+/* mvwprintw(win, 2, 60, "w/npos: %d->%d", wpos, npos); */
+	if ( (npos != wpos) || (npos == 0) ) {
+		mvwprintw(win, PTRROW, wpos, " ");
+		wpos = npos;
+		mvwprintw(win, PTRROW, wpos, "O");
+	}
+}
+
+/* rm20031122211133s.wav */
+/* 0123456789012345	 */
+
+void
+rzm_off_time(WINDOW *win, float time) {
+	char	*name = informat[0]->filename, *nname;
+	int	ind;
+
+	/* get to the last slash */
+	while (nname = index(name, '/')) name = nname + 1;
+	
+	if ( (strncmp(name, "rm", 2) !=0) && (strncmp(name, "sv", 2) !=0) ) return;
+	for (ind = 2; ind <= 15; ind++) if ( !isdigit(*((name)+ind)) ) return;
+	/* only if differs much */
+	/* if ( (name[15] <= '5') && (name[14] == '0') && (name[13] == '0') && (name[12] == '0') ) return;	*/
+	time += (name[15]-48) + (name[14]-48) * 10 +
+		(name[13]-48) * 60 + (name[12]-48) * 600 +
+		(name[11]-48) * 3600 + (name[10]-48) * 36000 ;
+	mvwprintw(win, 0, COLS-20, "file time: %s", hhmmss(time));
+}
+
+void
+restart_effect(float speed) {
+	char		buffer[100], *argv[2] = { buffer, NULL };
+
+	drain_effect(1);
+	(*efftab[1].h->stop)(&efftab[1]);
+	snprintf(buffer, sizeof(buffer), "%5.3f", 1/speed);
+	(*efftab[1].h->getopts)(&efftab[1], 1, &argv[0]);
+	(*efftab[1].h->start)(&efftab[1]);
+}
+
+
+void
+restart_all_eff(struct st_effect efftab[], struct st_effect efftabR[], int *pneffects, int argc, char **argv) {
+	int neffects = *pneffects;
+
+	/* anything left - don't know if necessary */
+	drain_all_eff(neffects);
+	/* releasing output buffers */
+	relbuf_all_eff(efftab, efftabR, neffects);
+	/* releasing effects' internal output buffers */
+	stop_all_eff(efftab, efftabR, neffects);
+	optind = 0;
+	parse_eff(argc, argv, user_efftab, &nuser_effects);
+	/* build efftab */
+	checkeffect(&neffects);
+	/* Start all effects */
+	start_all_eff(efftab, efftabR, neffects);
+	/* Reserve an output buffer for all effects */
+	resbuf_all_eff(efftab, efftabR, neffects);
+
+	/* local into parameter */
+	*pneffects = neffects;
+}
+
+/* interactive control */
+int
+interactive(WINDOW *win) {
+	int		jump, c, chspeed;
+	char		buf[100], *argv[10];
+	static float	time = 0, ptime, pos = 0;
+	double		dtv;
+	struct timeval	tv;
+	static struct timeval	ptv = { 0, 0 };
+
+	gettimeofday(&tv, NULL);
+	if (!ptv.tv_sec) ptv = tv;
+	dtv = (tv.tv_sec - ptv.tv_sec) * 1000.0 + (tv.tv_usec - ptv.tv_usec)/1000.0;
+
+	time += (float)(informat[0]->file.count) / informat[0]->info.rate;
+	/* time += (float)(efftab[0].olen) / informat[0]->info.rate; /* gsm? */
+
+	pos = time * informat[0]->info.rate / informat[0]->length;
+	draw_pos(win, pos);
+
+	chspeed = 0;
+	ptime = time;
+	while ( (c = wgetch(win)) != ERR) {
+		/* mvwprintw(win, 0, COLS-20, "%c (%d)", c, c); */
+		switch (c) {
+			case '[':		time -= 1; if (time < 0) time = 0; break;
+			case ']':		time += 1; break;
+			case KEY_LEFT:		time -= 30; if (time < 0) time = 0; break;
+			case KEY_RIGHT:		time += 30; break;
+			case KEY_SLEFT:		time -= 600; if (time < 0) time = 0; break;
+			case KEY_SRIGHT:	time += 600; break;
+			case KEY_DOWN:		speed -= 0.1; if (speed <= 0) speed = 0.1; chspeed = 1; break;
+			case KEY_UP:		speed += 0.1; if (speed > 5) speed = 5; chspeed = 1; break;
+			case KEY_NPAGE:		speed -= 0.2; if (speed <= 0) speed = 0.1; chspeed = 1; break;
+			case KEY_PPAGE:		speed += 0.2; if (speed > 5) speed = 5; chspeed = 1; break;
+			case ' ':		speed = 1; chspeed = 1; break;
+			case '':		redrawwin(win); break;
+			default:		break;
+		}
+	}
+	jump = (time != ptime);
+
+	if (jump) (*informat[0]->h->seek)(informat[0], time*informat[0]->info.rate);
+	if (chspeed) {
+		mvwprintw(win, 1, 8, "%.1f", speed);
+		/* restart_effect(speed); */
+		argv[0] = "stretch";
+		snprintf(buf, sizeof(buf), "%f", 1/speed);
+		argv[1] = buf;
+		argv[2] = NULL;
+		restart_all_eff(efftab, efftabR, &neffects, 2, argv);
+	}
+
+	mvwprintw(win, 0, 8, "%s  %4.1f%%", hhmmss(time), 100*pos);
+#if defined(RZM)
+	rzm_off_time(win, time);
+#endif /* RZM */
+	return jump;
+}
+
+#endif	/* defined(INTERACTIVE) */
diff -ru --exclude CVS sox.20031125/st_i.h sox-12.17.5cvs/st_i.h
--- sox.20031125/st_i.h	2003-08-24 23:27:39.000000000 +0200
+++ sox-12.17.5cvs/st_i.h	2003-12-08 22:28:04.000000000 +0100
@@ -131,7 +131,11 @@
  * to perform file I/O.  It can be useful to pass in similar sized
  * data to get max performance.
  */
+#if !defined(INTERACTIVE)
 #define ST_BUFSIZ 8192
+#else
+#define ST_BUFSIZ 1024
+#endif
 
 /*=============================================================================
  * File Handlers
diff -ru --exclude CVS sox.20031125/util.c sox-12.17.5cvs/util.c
--- sox.20031125/util.c	2001-11-23 04:42:57.000000000 +0100
+++ sox-12.17.5cvs/util.c	2003-12-08 22:23:31.000000000 +0100
@@ -34,6 +34,11 @@
  * the ST library.
  */
 char *myname = 0;
+#if defined(INTERACTIVE)
+int namelen;
+#endif
+
+char	bufrep[100];
 
 void st_report(const char *fmt, ...)
 {
@@ -42,36 +47,73 @@
         if (! verbose)
                 return;
 
+#if !defined(INTERACTIVE)
         fprintf(stderr, "%s: ", myname);
         va_start(args, fmt);
         vfprintf(stderr, fmt, args);
         va_end(args);
         fprintf(stderr, "\n");
+#else
+	namelen = 0;
+	if (myname) {
+		snprintf(bufrep, sizeof(bufrep), "%s: ", myname);
+		namelen = strlen(myname);
+	}
+        va_start(args, fmt);
+	vsnprintf(bufrep + namelen, sizeof(bufrep) - namelen, fmt, args);
+        va_end(args);
+#endif
 }
 
+
+char	bufwarn[100];
+
 void st_warn(const char *fmt, ...)
 {
         va_list args;
 
+#if !defined(INTERACTIVE)
         fprintf(stderr, "%s: ", myname);
         va_start(args, fmt);
-
         vfprintf(stderr, fmt, args);
         va_end(args);
         fprintf(stderr, "\n");
+#else
+	namelen = 0;
+	if (myname) {
+		snprintf(bufrep, sizeof(bufrep), "%s: ", myname);
+		namelen = strlen(myname);
+	}
+        va_start(args, fmt);
+	vsnprintf(bufrep + namelen, sizeof(bufrep) - namelen, fmt, args);
+        va_end(args);
+#endif
 }
 
+
+char	buffail[100];
+
 void st_fail(const char *fmt, ...)
 {
         va_list args;
         extern void cleanup();
 
+#if !defined(INTERACTIVE)
         fprintf(stderr, "%s: ", myname);
-
         va_start(args, fmt);
         vfprintf(stderr, fmt, args);
         va_end(args);
         fprintf(stderr, "\n");
+#else
+	namelen = 0;
+	if (myname) {
+		snprintf(bufrep, sizeof(bufrep), "%s: ", myname);
+		namelen = strlen(myname);
+	}
+        va_start(args, fmt);
+	vsnprintf(bufrep + namelen, sizeof(bufrep) - namelen, fmt, args);
+        va_end(args);
+#endif
         cleanup();
         exit(2);
 }
