diff -Nru sox.20050917/README.interactive sox.20050917-inst6/README.interactive
--- sox.20050917/README.interactive	1970-01-01 01:00:00.000000000 +0100
+++ sox.20050917-inst6/README.interactive	2007-02-21 22:26:07.000000000 +0100
@@ -0,0 +1,181 @@
+				INTERACTIVE SOX
+
+Interactive sox is a preliminary work. The main goal was to have an audio
+player which:
+
+- works interactively and is controlled with keys (not mouse)
+- can do smaller and bigger jumps, forward and reverse
+- can change speed
+- can change pitch _simultaneously_ with the change of speed (sox stretch
+  effect)
+- can be controlled by scripts (as e.g. alsaplayer)
+- can use tags which later can be used for automatic processing of the file
+
+Almost all these assumptions are fulfilled by sox - except the interactivity
+part (and the control part which is trivial). The interactivity itself was easy
+to implement. More difficult was to handle changes of speed. It has been done
+by stopping the effects, changing parameters and restarting effects. On a
+modern 400 MHz CPU supercomputer this processing is fast enough to not to be
+noticed.
+
+Since Jan 2007 the patch includes GSM seeking functionality. There is no need
+to uncompress WAV/GSM files before using them interactively.
+
+Since Feb 2007 the program shows the time difference between now and the
+currently played file. The file name must be in form aaaa...-YYYYmmddHHMMSS...
+
+Another addition: gain change by +-0.5 dB, keys: f, v.
+
+
+				REMARKS
+
+To increase responsiveness one can try:
+echo "sox 1 256" > ! /proc/asound/card0/pcm0p/oss
+
+Another way could be adding something  -r 44100 -c 4 -w  on output to drain the
+buffers faster.
+
+I use myplay and rmplay scripts (see scripts subdirectory). The first one is a
+simple wrapper for interactive sox. The second playes consecutive files
+matching the pattern and detects Q (finish), and B (go to the previous file)
+commands.
+
+
+				PICTURE
+
+        sox Version 12.17.9, interactive sox v. 20070202rzm
+        ftp://sunsite.icm.edu.pl/private/rzm/patches/
+`1234567890-=<- speeds 0.5 - 3.2              f v             gain +-0.5 dB
+up down         speed +-0.1 times             p[ause]
+'               prev speed                    ^L              redraw
+<- { [ ] } ->   back/forw by 1, 4, 30 s       t[ag begin] T[ag end]
+b[egin] e[nd]   of file                       < >             prev/next tag
+B[egin] q[uit]  prev/next file                d[elete tag]    up to 5 s ago
+Q[uit]          full stop                     D[elete tag]    last before cursor
+
+Time      0:27:08  45.2%        total:   1:00:01                      file time:   2:27:09
+Speed:   3.0    Gain:   -18.0 dB                                      delay:    3 19:49:17
+rm20070218020001.wav -> /dev/dsp
+
+__________________________________________________________________________________________
+                                      O
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+
+				KEYS
+
+Keys, position:
+[ ]		jump -+ 1 second
+{ }		jump -+ 3 seconds
+<- ->		jump -+ 30 s
+Shift <- ->	jump -+ 600 s	[does not work]
+b e		jump to 0th s or to 60th s from the end
+
+Speed:
+Down Up		change stretch -+ 0.1
+PgDown PgUp	change stretch -+ 0.2
+'		use previous speed
+`1234567890-= Backspace (upper row)	set stretch to 0.6 ... 3.2
+
+p		pause
+^L resize	redraw
+q Q B		quit writing that character into ~/.sox/state; wrapper script
+		should read and delete the file first then can interpret the
+		characters e.g. as: 
+		q	play next file
+		Q	quit without playing anything else
+		B	play previous file starting close to the end (30 s from
+			the end?)
+
+Tags (for previous, current, and next file) are displayed on the screen and
+kept in ~/.sox/tags/filename:
+HH:MM:SS.S [b|e]
+b and e mean beginning and ending tags so we may be able to cut range
+automatically.
+
+Home t		set beginning tag at current position
+End T		set ending tag
+P,< N.>		jump to previous/next tag
+d		delete current tag (current: left behind up to 2 s)
+
+f		increase gain by 0.5 dB
+v		decrease gain by 0.5 dB
+
+
+				TODO
+
+- problems with stretch (toooo fast) when using  -r 44100 -c 4 -w  on output
+- socket communication (instead of pipe)
+- output should not appear on the screen but should be redirected to the socket
+  so we can drop ncurses dependancy to keep the Windows compatibility
+- frontend script communicating via the socket
+- implement:
+	Option  --cursor tagN   start at tag number N
+	Control: Cn written to .soxi pipe - jump to tag n
+- with Linux kernel 2.6 there are problems with interactivity: it looks like
+  buffers are larger than in 2.4. I am not able to emulate 2.4 responsiveness.
+  It looks like
+  echo "sox 1 256" > ! /proc/asound/card0/pcm0p/oss
+  (sox can use only 1 [buffer?] fragment of size 256 B) helps. Adding  -w -c 4
+  options helps too (uses more space in the buffer?).
+- interface for other effects
+- configure --with-interactive switch
+- --with-communication and a command line option to turn it on
+- comments for tags; print time difference between beginning and ending tags
+- level meter
+
+
+				CHANGES
+
+20031128 start - ncurses interface
+20031205 RZM specific display
+20031208 working on stop-start; functions parse_eff(), start_all_eff(),
+	resbuf_all_eff(), relbuf_all_eff(), drain_all_eff(), stop_all_eff(),
+	checkeffect(int *pneffects), restart_all_eff() make this easier
+	interactive() after insteadof before flow_effect_out()
+	ST_BUFSIZ in interactive mode lowered from 8 KB to 1 KB
+20031216 rzm_off_time() changes
+	util.c functions writing to buffer instead of screen in interactive mode
+20040708 -I option
+	rzm_off_time() changes
+	more keys, top row speed scale
+	making both -DINTERACTIVE and -I working
+2005xxxx separate interactive.[ch]
+	#define ST_BUFSIZ 128
+	wav.c - preliminary work on seekable GSM
+
+20050528
+- ported to CVS sox 20050207 (discovered that sound split into 2 or 4 channels loses beginnings of buffer [?])
+- added communication interface via ~/.soxi
+	The key as in src/interactive.c:interactive() can be sent via the
+	~/.soxi pipe. The codes are available in /usr/include/curses.h . E.g.
+		#define KEY_RIGHT       0405            /* right-arrow key */
+	can be sent with echo interpreting octal codes (0405 == 0x105, bytes in
+	octal: 01 05, also note swapped bytes):
+		echo -n '\05\01' >> ~/.soxi
+	Alternative way:
+	cat << EOF | uudecode >> ~rzm/.soxi
+	begin-base64 644 -
+	BQE=
+	====
+	EOF
+- added pause ("p", echo -n 'p\0')
+
+20050912 Chris Bagwell likes my patch
+
+20050917
+- repatching current version of sox
+- more general name for error messages buffering (CB request)
+
+200510xx tagging
+
+20061230 - 20070103 GSM seeking; myplay and rmplay included
+
+20070107 tag_display_not_beinteractive.patch - -DINTERACTIVE crashing without -I option
+
+20070202, 20070203, 20070208 interactive-print-delay.patch - printing the time difference for files with names in aaaa...-YYYYmmddHHMMSS... format
+
+20070221 vol effect; scripts changes; preliminary support for start without any effects; short keys description on the screen; print PAUSE
+The program contains embedded start stretch and gain values. If the interactive
+sox starts with effects (manually or via myplay script) the values should match
+the compiled in numbers to make the program behaviour consistent.
diff -Nru sox.20050917/scripts/myplay sox.20050917-inst6/scripts/myplay
--- sox.20050917/scripts/myplay	1970-01-01 01:00:00.000000000 +0100
+++ sox.20050917-inst6/scripts/myplay	2007-02-21 20:37:16.000000000 +0100
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+eatbuf="-r 44100 -c 4 -w"
+
+if [ ! -f "$1" ]; then
+	exit 1
+fi
+
+log=~/log
+touch $log
+start=`date '+%s'`
+echo "start $1 "`date` >> $log
+
+~/bin/sox -I "$1" $eatbuf -t ossdsp /dev/dsp stretch 1.0 vol 0 dB
+#TODO: read total pauses length in seconds?
+
+end=`date '+%s'`
+tdiff=$(( $end - $start ))
+echo "stop  $1 "`date` $tdiff >> $log
diff -Nru sox.20050917/scripts/rmplay sox.20050917-inst6/scripts/rmplay
--- sox.20050917/scripts/rmplay	1970-01-01 01:00:00.000000000 +0100
+++ sox.20050917-inst6/scripts/rmplay	2007-02-21 13:27:20.000000000 +0100
@@ -0,0 +1,53 @@
+#!/bin/sh
+
+# player script for sox - Rafał Maszkowski <rzm@icm.edu.pl>
+
+# ...      created by rzm@icm.edu.pl
+# 20060323 rm $active  on Q
+# 20060331 exit before rm when Q pressed
+# 20060512 exit if no file
+# 20070103 simplified for sox.20050917-inst5 with GSM seek; no-file-exit was
+#          wrong - the next code block was looking for a file and exiting if
+#          none found
+
+# $1 - start, optional
+
+active=.rmplay.$$
+touch $active
+
+# accept calling without argument
+if [ "$1" != "" ]; then
+	file=$1
+else
+	file=`ls rm[12]*[0-9].wav | head -1`
+	if [ $file == "" ]; then
+		echo No files to play. Exiting...
+		exit
+	fi
+fi
+
+while true; do
+	echo $file > $active
+	myplay $file
+	state=`cat ~/.sox/state`
+	if [ "$state" = "Q" ]; then echo $state pressed, exiting...; rm -f $active; exit; fi
+	back=0
+	if [ "$state" = "B" ]; then back=1; fi
+
+	file=`ls rm[12]*[0-9].wav | awk --assign file="$file" --assign back="$back" 'BEGIN {
+		curr = 0
+	} {
+		if (curr) {
+			if (back) { print before
+			} else {    print $1 }
+			exit
+		}
+		if ($1 == file) { curr=1; before = prev }
+		prev = $1
+	}'`
+	if [ "$file" == "" ]; then
+		echo No more files to play. Exiting...
+		rm -f $active
+		exit 2
+	fi
+done
diff -Nru sox.20050917/scripts/sox sox.20050917-inst6/scripts/sox
--- sox.20050917/scripts/sox	1970-01-01 01:00:00.000000000 +0100
+++ sox.20050917-inst6/scripts/sox	2007-02-21 20:23:21.000000000 +0100
@@ -0,0 +1,2 @@
+#!/bin/sh
+/home/rzm/src/sox.20050917-inst6/src/sox $*
diff -Nru sox.20050917/src/interactive.c sox.20050917-inst6/src/interactive.c
--- sox.20050917/src/interactive.c	1970-01-01 01:00:00.000000000 +0100
+++ sox.20050917-inst6/src/interactive.c	2007-02-21 22:28:28.000000000 +0100
@@ -0,0 +1,427 @@
+#if defined(INTERACTIVE)
+
+#include "interactive.h"
+
+#define	PTRROW	5
+
+WINDOW		*win;
+extern int	optind;
+extern unsigned long read_samples;
+float		stretch = 3.0;
+float		gain = -10;
+int		beinteractive = 0;	/* interactive mode */
+int		pfile = -1;		/* communication file descriptor */
+int		pausecount = 0;		/* total pause on 200000000 ns units */
+int		quit = 0;		/* quitting */
+char		prevstate;		/* state of the last quit (Q, q, b) */
+
+#if defined(COMMUNICATION)
+int
+init_pipe() {
+	char		spfile[100], *home;
+	int		pfile, err;
+	struct stat	fstat;
+
+	home = getenv("HOME");
+	if (home) strncpy(spfile, home, sizeof(spfile)-1);
+	strcat(spfile, "/.soxi");
+
+	err = 0;
+	if ( ((err = stat(spfile, &fstat)) != 0) && (errno != ENOENT) )
+		printf("sox stat(%s, ) error: %s (%d)\n", spfile, strerror(errno), errno);
+	if ( (err = -1) && (errno == ENOENT) ) {
+		mkfifo(spfile, 0600);
+	} else {
+		if ( !S_ISFIFO(fstat.st_mode) ) printf("sox %s is not a pipe\n", spfile);
+	}
+
+	pfile = open(spfile, O_RDONLY|O_NONBLOCK);
+	if (pfile == -1) printf("sox cannot open(%s, O_RDONLY|O_NONBLOCK)\n", spfile);
+	return pfile;
+}
+
+
+short
+read_pipe(int pfile) {
+	short	c = 0;
+	int	err;
+
+	while (1) {
+		err = read(pfile, &c, 2);
+		if (err == -1) {
+			return -1;
+			if (errno != EAGAIN) printf("c: %04X, errno: %d - %s\n", c, errno, strerror(errno));
+		} else {
+			return c;
+			if (err > 0) printf("size: %d, c: %04X\n", err, c);
+		}
+	}
+}
+#endif
+
+
+static char
+state_read() {
+	char	*home, statefile[FILENAME_MAX], c;
+	FILE	*file;
+
+        home = getenv("HOME");
+        if (home) strncpy(statefile, home, FILENAME_MAX);
+        strcat(statefile, "/.sox/state");
+        statefile[FILENAME_MAX-1] = '\0';         /* just in case it is a veeery long name */
+        if ( (file = fopen(statefile, "r")) == NULL) return ' ';
+	fscanf(file, "%c", &c);
+	fclose(file);
+	return c;
+}
+
+static void
+state_write(char c) {
+	char	*home, statefile[FILENAME_MAX];
+	FILE	*file;
+
+        home = getenv("HOME");
+        if (home) strncpy(statefile, home, FILENAME_MAX);
+        strcat(statefile, "/.sox");
+        mkdir(statefile, 0755);   /* create the directory just in case */
+        strcat(statefile, "/state");
+        statefile[FILENAME_MAX-1] = '\0';         /* just in case it is a veeery long name */
+        if ( (file = fopen(statefile, "w")) == NULL) return;
+	fprintf(file, "%c", c);
+	fclose(file);
+}
+
+
+void
+init_curses(WINDOW **pwin, ft_t informat0, ft_t outformat) {
+	*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(informat0) / (informat0->info.rate * informat0->info.size * informat0->info.channels),	*/
+		informat0->length / informat0->info.rate /* / informat0->info.channels  ? */ ,
+		informat0, outformat);
+#if defined(COMMUNICATION)
+	pfile = init_pipe();
+	prevstate = state_read();
+	state_write(' ');
+#endif
+}
+
+void
+stop_curses(WINDOW *win) {
+	mvwprintw(win, Y0 + PTRROW+2, 0, "X");
+	mvwprintw(win, Y0 + PTRROW+5, 0, " ");
+	pauseprint(Y0 + PTRROW + 5);
+	mvwprintw(win, Y0 + PTRROW+6, 0, " ");
+	curs_set(1);
+	endwin();
+}
+
+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;
+}
+
+char *
+delay(int y, int m, int d, int dd, int ptime) {
+	static char	stime[30];
+	struct tm	playtm, *tm;
+	time_t		playt, curt, difft, difftd;
+
+	bzero(&playtm, sizeof(playtm));
+	playtm.tm_year = y - 1900; playtm.tm_mon = m - 1; playtm.tm_mday = d + dd;
+	playtm.tm_sec = ptime;
+	playt = mktime(&playtm);
+
+	curt = time(NULL);
+	
+	difft = curt - playt; difftd = difft/86400; difft -= 86400 * difftd;
+	tm = gmtime(&difft);
+	/* mday-1 cos it is Jan 1st '70 */
+	snprintf(stime, sizeof(stime), "%4ld %02d:%02d:%02d", difftd, tm->tm_hour, tm->tm_min, tm->tm_sec);
+	return stime;
+}
+
+void
+draw_fixed(WINDOW *win, float ttime, ft_t informat0, ft_t outformat) {
+	int	col;
+
+mvwprintw(win, 2, 0, "`1234567890-=<- speeds 0.5 - 3.2              f v             gain +-0.5 dB\nup down         speed +-0.1 times             p[ause]\n'               prev speed                    ^L              redraw\n<- { [ ] } ->   back/forw by 1, 4, 30 s       t[ag begin] T[ag end]\nb[egin] e[nd]   of file                       < >             prev/next tag\nB[egin] q[uit]  prev/next file                d[elete tag]    up to 5 s ago\nQ[uit]          full stop                     D[elete tag]    last before cursor"); 
+	mvwprintw(win, Y0 + 0, 0, "Time				total: %s", hhmmss(ttime));
+	mvwprintw(win, Y0 + 1, 0, "Speed:%6.1f    Gain:%8.1f dB", stretch, gain);
+	mvwprintw(win, Y0 + 2, 0, "%s -> %s", informat0->filename, outformat->filename);
+	mvwprintw(win, 0, 0, "        sox %s, interactive sox v. %s", st_version(), VERSION_ISOX);
+	mvwprintw(win, 1, 0, "        %s", ISOX_URL);
+	for (col = 0; col <= COLS; col++) {
+		mvwprintw(win, Y0 + PTRROW-1, col, "_");
+		mvwprintw(win, Y0 + 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, Y0 + 2, 60, "w/npos: %d->%d", wpos, npos); */
+	if ( (npos != wpos) || (npos == 0) ) {
+		mvwprintw(win, Y0 + PTRROW, wpos, " ");
+		wpos = npos;
+		mvwprintw(win, Y0 + PTRROW, wpos, "O");
+	}
+}
+
+/* This procedure is specific for recordings with names in the following formats:
+rm20031122211133s.wav	2004.10.27.rn18....
+  0123456789012345	0123 56 89   34						*/
+
+void
+rzm_off_time(WINDOW *win, float time, ft_t informat0) {
+	char	*name = informat0->filename, *nname;
+	int	ind, rmmp3ind[] = { 0, 1, 2, 3, 5, 6, 8, 9, 13, 14 }, mp3 = 1, y = 0, m = 0, d = 0, dd = 0;
+
+	for (ind = 0; ind < sizeof(rmmp3ind)/sizeof(rmmp3ind[0]); ind++)	/* recognizing mp3 */
+		if ( !isdigit(name[rmmp3ind[ind]]) ) mp3 = 0;
+
+	if (mp3) {
+		int	hour, min = 00;	/* minutes after full hour */
+		hour = (name[14]-48) + (name[13]-48) * 10;
+		switch (hour) {		/* we do not know the exact time but usually the program starts at: */
+			case 13: case 18:	min = 10; break;
+			case 21:		min = 45; break;
+		}
+		time += min * 60 + hour * 3600;
+
+		y = name[3]-48 + 10 * (name[2]-48 + 10 * (name[1]-48 + 10 * (name[0]-48) ));
+		m = name[6]-48 + 10 * (name[5]-48);
+		d = name[9]-48 + 10 * (name[8]-48);
+
+		/* modulo 1 day, e.g. for rn24... */
+		if (time >= 86400) {
+			dd = (int)(time / 86400);
+			time -= 86400.0 * dd;
+		}
+	} else {
+
+		/* not an mp3; get to the last slash */
+		while ( (nname = index(name, '/')) ) name = nname + 1;
+	
+		while ( !isdigit(name[0]) ) {
+			name++;
+			if (name[0] == '\0') return;
+		}
+
+		for (ind = 0; ind <= 13; ind++) if ( !isdigit(name[ind]) ) return; /* digits where they should be? */
+
+		time += (name[13]-48) + (name[12]-48) * 10 +
+		(name[11]-48) * 60 + (name[10]-48) * 600 +
+		(name[9]-48) * 3600 + (name[8]-48) * 36000 ;
+
+		y = name[3]-48 + 10 * (name[2]-48 + 10 * (name[1]-48 + 10 * (name[0]-48) ));
+		m = name[5]-48 + 10 * (name[4]-48);
+		d = name[7]-48 + 10 * (name[6]-48);
+	}
+
+	mvwprintw(win, Y0 + 0, COLS-20, "file time: %s", hhmmss(time));
+	mvwprintw(win, Y0 + 1, COLS-20, "delay: %s", delay(y, m, d, dd, time));
+}
+
+void
+restart_effect(float stretch, struct st_effect efftab[]) {
+	char		buffer[100], *argv[2] = { buffer, NULL };
+
+	drain_effect(1);
+	(*efftab[1].h->stop)(&efftab[1]);
+	snprintf(buffer, sizeof(buffer), "%5.3f", 1/stretch);
+	(*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, 
+	struct st_effect user_efftab[], int nuser_effects, int argc, char **argv) {
+	int neffects = *pneffects;
+
+	/* anything left - don't know if necessary */
+	drain_all_eff(neffects);
+	/* releasing output buffers */
+	release_effect_buf();
+	/* releasing effects' internal output buffers */
+	stop_effects();
+neffects = 3;	/* we return # of effects but sox can be started without any so 1st time we release the original # of eff. */
+	optind = 0;
+	parse_effects(argc, argv);
+	/* build efftab */
+	check_effects();
+	/* Start all effects */
+	start_effects();
+	/* Reserve an output buffer for all effects */
+	reserve_effect_buf();
+
+	/* local into parameter */
+	*pneffects = neffects;
+}
+
+
+void
+pauseprint(int pos) {
+	mvwprintw(win, pos, 0, "Total pauses: %lf s\n", pausecount * 0.2);
+}
+
+
+short
+read_char(WINDOW *win, int pfile) {
+	short	c = 0;
+
+#if defined(COMMUNICATION)
+	if (pfile != -1) {
+		c = read_pipe(pfile);
+		if ( (c != -1) && (c != 0) ) return c;
+	}
+#endif
+	c = wgetch(win);
+	return c;
+}
+
+
+/* interactive control */
+int
+interactive(WINDOW *win, ft_t informat0, ft_t outformat, struct st_effect efftab[], struct st_effect efftabR[], int *pneffects,
+		struct st_effect user_efftab[], int nuser_effects, int *pquit) {
+	int		jump, c, chstretch, chgain, argc;
+	static int	pause = 0;
+	char		stretchbuf[100], gainbuf[100], *argv[10];
+	float		tmpstretch;
+	static float	time = 0, ptime, pos = 0, oldstretch = -1;
+	static struct timespec	sl = { 0, 200000000 };
+#if defined(TAGGING)
+	int		passtag;
+	static int	prevpasstag;
+	float		ntime;
+#endif
+
+	if (oldstretch == -1) oldstretch = stretch;
+
+	time = (double)(read_samples) / (double)(informat0->info.rate);
+	pos = (double)(read_samples) / (double)(informat0->length);
+	draw_pos(win, pos);
+
+	chstretch = chgain = 0;
+	ptime = time;
+pause:
+	while ( (c = read_char(win, pfile)) != ERR) {
+		/* mvwprintw(win, Y0 + 0, COLS-20, "%c (%d)", c, c); */
+		switch (c) {
+			case '[':	time -= 2; if (time < 0) time = 0; break;
+			case ']':	time += 1; break;
+			case '{':	time -= 4; if (time < 0) time = 0; break;
+			case '}':	time += 3; 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 'b':	time = 0; break;
+			case 'e':	time = (double)(informat0->length) / (double)(informat0->info.rate) - 60;
+					if (time < 0) time = 0; break;
+
+			case KEY_DOWN:	stretch -= 0.1; if (stretch <= 0) stretch = 0.1; chstretch = 1; break;
+			case KEY_UP:	stretch += 0.1; if (stretch > 5) stretch = 5; chstretch = 1; break;
+			case KEY_NPAGE:	stretch -= 0.2; if (stretch <= 0) stretch = 0.1; chstretch = 1; break;
+			case KEY_PPAGE:	stretch += 0.2; if (stretch > 5) stretch = 5; chstretch = 1; break;
+			case '\'':	tmpstretch = oldstretch; oldstretch = stretch; stretch = tmpstretch; chstretch = 1; break;
+			case 'p':	if (pause) mvwprintw(win, Y0 + 1, 6, "%6.1f", stretch); pause = !pause; break;
+
+			/* upper keys row scale - except SPACE */
+			case '`':	oldstretch = stretch; stretch = 0.6; chstretch = 1; break;
+			case '1':	oldstretch = stretch; stretch = 0.7; chstretch = 1; break;
+			case '2':	oldstretch = stretch; stretch = 0.9; chstretch = 1; break;
+			case ' ':	oldstretch = stretch; stretch = 1;   chstretch = 1; break;
+			case '3':	oldstretch = stretch; stretch = 1.1; chstretch = 1; break;
+			case '4':	oldstretch = stretch; stretch = 1.3; chstretch = 1; break;
+			case '5':	oldstretch = stretch; stretch = 1.6; chstretch = 1; break;
+			case '6':	oldstretch = stretch; stretch = 1.8; chstretch = 1; break;
+			case '7':	oldstretch = stretch; stretch = 2.0; chstretch = 1; break;
+			case '8':	oldstretch = stretch; stretch = 2.2; chstretch = 1; break;
+			case '9':	oldstretch = stretch; stretch = 2.4; chstretch = 1; break;
+			case '0':	oldstretch = stretch; stretch = 2.6; chstretch = 1; break;
+			case '-':	oldstretch = stretch; stretch = 2.8; chstretch = 1; break;
+			case '=':	oldstretch = stretch; stretch = 3.0; chstretch = 1; break;
+			case '\177':	oldstretch = stretch; stretch = 3.2; chstretch = 1; break;
+
+			case 'f': case 'F': gain += DGAIN; chgain = 1; break;
+			case 'v': case 'V': gain -= DGAIN; chgain = 1; break;
+
+#if defined(TAGGING)
+			case 't': case KEY_HOME:	tag_add(time, 'b'); tag_display(win, time); break;
+			case 'T': case KEY_END:		tag_add(time, 'e'); tag_display(win, time); break;
+			case ',': case '<': case 'P':	ntime = tag_jump(time, 'P');
+							if (ntime != -1.0) time = ntime; break;
+			case '.': case '>': case 'N':	ntime = tag_jump(time, 'N');
+							if (ntime != -1.0) time = ntime; break;
+			case 'd':			tag_delete(time, 5 /* s */); tag_display(win, time); break;
+			case 'D':			tag_delete(time, 5000 /* s */); tag_display(win, time); break;
+#endif
+
+			case KEY_RESIZE:
+			case '':	/* redrawwin(win); */ init_curses(&win, informat0, outformat); break;
+			case 'q': case 'Q': case 'B':	*pquit = 1; state_write(c); break;
+			default:	break;
+		}
+	}
+
+#if defined(TAGGING)
+	/* redraw tags if we are between different tags than before
+	   tags just before and after current time are bold-faced */
+	passtag = tag_search(time);
+	if (passtag != prevpasstag) tag_display(win, time);
+	prevpasstag = passtag;
+#endif
+
+	if (pause) { mvwprintw(win, Y0 + 1, 7, "PAUSE"); nanosleep(&sl, NULL); pausecount++; goto pause; }
+
+	jump = (time != ptime);
+
+	if (jump) {
+		(*informat0->h->seek)(informat0, time*informat0->info.rate);
+		read_samples = time * (double)(informat0->info.rate);
+	}
+	if (chstretch || chgain) {
+		/* change stretch (pitch corrected speed) */
+		mvwprintw(win, Y0 + 1, 6, "%6.1f", stretch);
+		/* restart_effect(stretch); */
+		argv[0] = "stretch";
+		snprintf(stretchbuf, sizeof(stretchbuf), "%.3f", 1/stretch);
+		argv[1] = stretchbuf;
+		/* change gain */
+		mvwprintw(win, Y0 + 1, 21, "%8.1f dB", gain);
+		argv[2] = "vol";
+		snprintf(gainbuf, sizeof(gainbuf), "%.3f", gain);
+		argv[3] = gainbuf;
+		argv[4] = "dB";
+		argv[5] = NULL; argc = 5;
+		restart_all_eff(efftab, efftabR, pneffects, user_efftab, nuser_effects, argc, argv);
+	}
+
+	mvwprintw(win, Y0 + 0, 8, "%s  %4.1f%%", hhmmss(time), 100*pos);
+#if defined(RZM)
+	rzm_off_time(win, time, informat0);
+#endif /* RZM */
+	return jump;
+}
+
+#endif	/* defined(INTERACTIVE) */
diff -Nru sox.20050917/src/interactive.h sox.20050917-inst6/src/interactive.h
--- sox.20050917/src/interactive.h	1970-01-01 01:00:00.000000000 +0100
+++ sox.20050917-inst6/src/interactive.h	2007-02-21 18:21:33.000000000 +0100
@@ -0,0 +1,58 @@
+/* interactive.h - various structures and defines used by interactive interface. */
+
+#ifndef INTERACTIVE_H_INCLUDED
+#define INTERACTIVE_H_INCLUDED
+
+#include "st.h"
+#include "st_i.h"
+
+#include <ncurses.h>
+#include <time.h>
+#include <sys/time.h>
+#include <strings.h>
+
+/* pipe */
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <ctype.h>
+
+#define	VERSION_ISOX	"20070202rzm"
+#define	ISOX_URL	"ftp://sunsite.icm.edu.pl/private/rzm/patches/"
+
+#if defined(TAGGING)
+#include "tag.h"
+#endif
+
+#define Y0      10      /* first row    */
+
+#define	DGAIN	0.5
+
+extern WINDOW  *win;
+extern int	beinteractive, quit;	/* interactive mode */
+
+void init_curses(WINDOW **pwin, ft_t informat0, ft_t outformat);
+void stop_curses(WINDOW *win);
+void draw_fixed(WINDOW *win, float ttime, ft_t informat0, ft_t outformat);
+void draw_pos(WINDOW *win, float pos);
+void pauseprint();
+int interactive(WINDOW *win, ft_t informat0, ft_t outformat, struct st_effect efftab[], struct st_effect efftabR[], int *pneffects,
+	struct st_effect user_efftab[], int nuser_effects, int *pquit);
+
+/* should be in sox.h ? */
+int drain_effect(int);
+void drain_all_eff(int neffects);
+void relbuf_all_eff(struct st_effect efftab[], struct st_effect efftabR[], int neffects);
+void stop_all_eff(struct st_effect efftab[], struct st_effect efftabR[], int neffects);
+void parse_eff(int argc, char **argv, struct st_effect user_efftab[], int *pnuser_effects);
+void checkeffect(int *pneffects);
+void start_all_eff(struct st_effect efftab[], struct st_effect efftabR[], int neffects);
+void resbuf_all_eff(struct st_effect efftab[], struct st_effect efftabR[], int neffects);
+
+#endif /* INTERACTIVE_H_INCLUDED */
+
diff -Nru sox.20050917/src/Makefile.in sox.20050917-inst6/src/Makefile.in
--- sox.20050917/src/Makefile.in	2005-09-17 18:13:03.000000000 +0200
+++ sox.20050917-inst6/src/Makefile.in	2007-02-21 13:27:20.000000000 +0100
@@ -25,10 +25,10 @@
 LN_S    = @LN_S@
 
 # Build macros.
-CFLAGS	= @CFLAGS@ -I$(srcdir) -I$(builddir)
+CFLAGS	= @CFLAGS@ -I$(srcdir) -I$(builddir) -DINTERACTIVE -DRZM -DCOMMUNICATION -DTAGGING
 CPPFLAGS = @CPPFLAGS@
 LDFLAGS	= -L. @LDFLAGS@
-LIBS	= -lst @LIBS@
+LIBS	= -lst @LIBS@ -lncurses
 
 # Other macros.
 
@@ -67,7 +67,7 @@
 SUNAUOBJ_1  = sunaudio.o
 ALSAOBJ_0   =
 ALSAOBJ_1   = alsa.o
-EXTRAOBJS   = $(OSSOBJ_$(NEED_OSS)) $(SUNAUOBJ_$(NEED_SUNAU)) $(ALSAOBJ_$(NEED_ALSA)) $(GSMOBJ_$(GSM_SUPPORT))
+EXTRAOBJS   = $(OSSOBJ_$(NEED_OSS)) $(SUNAUOBJ_$(NEED_SUNAU)) $(ALSAOBJ_$(NEED_ALSA)) $(GSMOBJ_$(GSM_SUPPORT)) interactive.o tag.o
 
 LIBOBJS = $(FOBJ) $(EOBJ) handlers.o stio.o misc.o util.o getopt.o $(EXTRAOBJS)
 
diff -Nru sox.20050917/src/sox.c sox.20050917-inst6/src/sox.c
--- sox.20050917/src/sox.c	2005-09-17 18:13:04.000000000 +0200
+++ sox.20050917-inst6/src/sox.c	2007-02-21 13:27:20.000000000 +0100
@@ -59,6 +59,13 @@
 #define strdup _strdup
 #endif
 
+#if defined(INTERACTIVE)
+#include <interactive.h>
+#endif
+#if defined(TAGGING)
+#include <tag.h>
+#endif
+
 /*
  * SOX main program.
  *
@@ -71,11 +78,12 @@
 static int clipped = 0;         /* Volume change clipping errors */
 static int writing = 1;         /* are we writing to a file? assume yes. */
 static int soxpreview = 0;      /* preview mode */
+int bufferr = 0;		/* buffer error messages */
 
-static int quite = 0;
+static int quiet = 0;
 static int status = 0;
 static unsigned long input_samples = 0;
-static unsigned long read_samples = 0;
+unsigned long read_samples = 0;
 static unsigned long output_samples = 0;
 
 static st_sample_t ibufl[ST_BUFSIZ/2];    /* Left/right interleave buffers */
@@ -102,16 +110,9 @@
 static void update_status(void);
 static void statistics(void);
 static st_sample_t volumechange(st_sample_t *buf, st_ssize_t ct, double vol);
-static void parse_effects(int argc, char **argv);
-static void check_effects(void);
-static void start_effects(void);
-static void reserve_effect_buf(void);
 static int flow_effect_out(void);
 static int flow_effect(int);
 static int drain_effect_out(void);
-static int drain_effect(int);
-static void release_effect_buf(void);
-static void stop_effects(void);
 
 #define MAX_INPUT_FILES 32
 #define MAX_FILES MAX_INPUT_FILES + 1
@@ -245,6 +246,8 @@
     }
 
     /* Loop through the reset of the arguments looking for effects */
+    /* in interactive mode assure that there is  stretch 1  effect ?
+       and add it if missing - otherwise we need to have always on the command line */
     parse_effects(argc, argv);
 
     process();
@@ -260,9 +263,9 @@
 }
 
 #ifdef HAVE_GETOPT_H
-static char *getoptstr = "+r:v:t:c:phsuUAaigbwlfdxVSq";
+static char *getoptstr = "+r:v:t:c:phsuUAaigbwlfdxVSqI";
 #else
-static char *getoptstr = "r:v:t:c:phsuUAaigbwlfdxVSq";
+static char *getoptstr = "r:v:t:c:phsuUAaigbwlfdxVSqI";
 #endif
 
 static void doopts(file_options_t *fo, int argc, char **argv)
@@ -366,13 +369,23 @@
 
             case 'S':
                 status = 1;
-                quite = 0;
+                quiet = 0;
                 break;
 
             case 'q':
                 status = 0;
-                quite = 1;
+                quiet = 1;
                 break;
+
+#if defined(INTERACTIVE)
+	    case 'I':
+		beinteractive = 1;
+		bufferr = 1;
+                status = 0;
+                quiet = 1;
+		break;
+#endif
+
         }
     }
 }
@@ -391,6 +404,38 @@
     return ST_SUCCESS;
 }
 
+/* Drain all effects */
+void drain_all_eff(int neffects) {
+    int f;
+    /* Drain the effects out first to last,
+     * pushing residue through subsequent effects */
+    /* oh, what a tangled web we weave */
+    for(f = 1; f < neffects; f++)
+    {
+        while (1) {
+
+            if (drain_effect(f) == 0)
+                break;          /* out of while (1) */
+
+            /* Change the volume of this output data if needed. */
+            if (writing && file_opts[file_count-1]->volume != 1.0)
+                clipped += volumechange(efftab[neffects-1].obuf, 
+                                        efftab[neffects-1].olen,
+                                        file_opts[file_count-1]->volume);
+
+            /* FIXME: Need to look at return code and abort on failure */
+            if (writing && efftab[neffects-1].olen > 0)
+                (*file_desc[file_count-1]->h->write)(file_desc[file_count-1], 
+                                                     efftab[neffects-1].obuf,
+                                                     (st_ssize_t)efftab[neffects-1].olen);
+
+            if (efftab[f].olen != ST_BUFSIZ)
+                break;
+        }
+    }
+}
+
+
 void optimize_trim(void)
 {
     /* Speed hack.  If the "trim" effect is the first effect then
@@ -478,7 +523,7 @@
             strcmp(file_desc[file_count-1]->filetype, "ossdsp") == 0 ||
             strcmp(file_desc[file_count-1]->filetype, "sunau") == 0)
         {
-            if (!quite)
+            if (!quiet)
                 status = 1;
         }
 
@@ -544,10 +589,19 @@
     for(e = 1; e < neffects; e++)
         efftab[e].odone = efftab[e].olen = 0;
 
+#if defined(INTERACTIVE)
+    if (beinteractive) init_curses(&win, file_desc[0], file_desc[file_count-1]);
+#endif
+#if defined(TAGGING)
+    tag_init(file_desc[0]->filename);
+    tag_display(win, 0);
+#endif
+
     /* Run input data through effects and get more until olen == 0 
      * (or ST_EOF).
      */
     do {
+	int	jump = 0;
 #ifndef SOXMIX
         efftab[0].olen = 
         ilen = (*file_desc[current_input]->h->read)(file_desc[current_input],
@@ -664,7 +718,7 @@
 
         /* If not writing and no effects are occuring then not much
          * reason to continue reading.  This allows this case.  Mainly
-         * useful to print out info about input file header and quite.
+         * useful to print out info about input file header and quit.
          */
         if (!writing && neffects == 1)
             efftab[0].olen = 0;
@@ -672,18 +726,30 @@
         if (efftab[0].olen == 0)
             break;
 
-        flowstatus = flow_effect_out();
+	/* play only if we do not skip just now */
+	if (!jump) flowstatus = flow_effect_out();
+
+#if defined(INTERACTIVE)
+	if (beinteractive) jump = interactive(win, file_desc[0], file_desc[file_count-1], efftab, efftabR, &neffects, user_efftab, nuser_effects, &quit);
+#endif
 
         if (status)
             update_status();
 
         /* Negative flowstatus says no more output will ever be generated. */
         if (flowstatus == ST_EOF || 
-            (writing && file_desc[file_count-1]->st_errno))
+	    (writing && file_desc[file_count-1]->st_errno) || quit)
             break;
 
     } while (1); 
 
+#if defined(INTERACTIVE)
+    if (beinteractive) {
+	interactive(win, file_desc[0], file_desc[file_count-1], efftab, efftabR, &neffects, user_efftab, nuser_effects, &quit);
+	stop_curses(win);
+    }
+#endif
+
     /* This will drain the effects */
     drain_effect_out();
 
@@ -723,7 +789,7 @@
     }
 }
 
-static void parse_effects(int argc, char **argv)
+void parse_effects(int argc, char **argv)
 {
     int argc_effect;
 
@@ -769,7 +835,7 @@
  * Smart ruleset for multiple effects in sequence.
  *      Puts user-specified effect in right place.
  */
-static void check_effects(void)
+void check_effects(void)
 {
     int i;
     int needchan = 0, needrate = 0, haschan = 0, hasrate = 0;
@@ -951,7 +1017,7 @@
     }
 }
 
-static void start_effects(void)
+void start_effects(void)
 {
     int e;
 
@@ -962,7 +1028,7 @@
     }
 }
 
-static void reserve_effect_buf(void)
+void reserve_effect_buf(void)
 {
     int e;
 
@@ -1230,7 +1296,7 @@
     return flow_effect_out();
 }
 
-static int drain_effect(int e)
+int drain_effect(int e)
 {
     st_ssize_t i, olen, olenl, olenr;
     st_sample_t *obuf;
@@ -1277,7 +1343,7 @@
     return rc;
 }
 
-static void release_effect_buf(void)
+void release_effect_buf(void)
 {
     int e;
     
@@ -1289,7 +1355,7 @@
     }
 }
 
-static void stop_effects(void)
+void stop_effects(void)
 {
     int e;
 
@@ -1427,7 +1493,11 @@
         if (opt)
                 fprintf(stderr, "Failed: %s\n", opt);
         else {
-            fprintf(stderr,"gopts: -e -h -p -q -S -V\n\n");
+	    fprintf(stderr,"gopts: -e -h -p -q -S -V");
+#if defined(INTERACTIVE)
+	    fprintf(stderr," -I");
+#endif
+	    fprintf(stderr,"\n\n");
             fprintf(stderr,"fopts: -r rate -c channels -s/-u/-U/-A/-a/-i/-g/-f -b/-w/-l/-d -v volume -x\n\n");
             fprintf(stderr, "effect: ");
             for (i = 0; st_effects[i].name != NULL; i++) {
diff -Nru sox.20050917/src/st.h sox.20050917-inst6/src/st.h
--- sox.20050917/src/st.h	2005-09-17 18:13:04.000000000 +0200
+++ sox.20050917-inst6/src/st.h	2007-02-21 13:27:20.000000000 +0100
@@ -295,6 +295,16 @@
 #define ST_ENOTSUP 2005         /* Operation not supported */
 #define ST_EINVAL 2006          /* Invalid argument */
 
+/* here or elsewhere? - rzm */
+int drain_effect(int e);
+void parse_effects(int argc, char **argv);
+void check_effects(void);
+void start_effects(void);
+void reserve_effect_buf(void);
+void release_effect_buf(void);
+void stop_effects(void);
+
+
 #ifdef __cplusplus
 } /* end of extern "C" */
 #endif
diff -Nru sox.20050917/src/st_i.h sox.20050917-inst6/src/st_i.h
--- sox.20050917/src/st_i.h	2005-09-17 18:13:04.000000000 +0200
+++ sox.20050917-inst6/src/st_i.h	2007-02-21 13:27:20.000000000 +0100
@@ -1,7 +1,7 @@
 #ifndef ST_I_H
 #define ST_I_H
 /*
- * Sound Tools Interal - October 11, 2001
+ * Sound Tools Internal - October 11, 2001
  *
  *   This file is meant for libst internal use only
  *
@@ -140,7 +140,13 @@
  * to perform file I/O.  It can be useful to pass in similar sized
  * data to get max performance.
  */
+#if defined(INTERACTIVE)
+/* the buffer size is  compromise between ability to quickly skip to next position and performance+clicking noise */
+/* #define ST_BUFSIZ 128	*/	/* not catching up */
+#define ST_BUFSIZ (1*1024)
+#else
 #define ST_BUFSIZ 8192
+#endif
 
 /*=============================================================================
  * File Handlers
diff -Nru sox.20050917/src/tag.c sox.20050917-inst6/src/tag.c
--- sox.20050917/src/tag.c	1970-01-01 01:00:00.000000000 +0100
+++ sox.20050917-inst6/src/tag.c	2007-02-21 13:27:30.000000000 +0100
@@ -0,0 +1,204 @@
+#ifdef TAGGING
+
+#include "tag.h"
+
+struct tag	*tags = 0;
+int		ntag = 0, ntagalloc = 0;
+
+char		tagfile[FILENAME_MAX];
+
+static int
+tag_ctotype(char c) {
+	switch (tolower(c)) {
+		case 'b': return TAG_BEG;
+		case 'e': return TAG_END;
+		default: return TAG_UNK;
+	}
+}
+
+static char
+tag_typetoc(char type) {
+	switch (type) {
+		case TAG_BEG: return 'b';
+		case TAG_END: return 'e';
+		default: return '?';
+	}
+}
+
+/* return index of the first larger time or ntag if all are smaller */
+/* based on http://www.dcc.uchile.cl/~rbaeza/handbook/algs/3/321.srch.c */
+/* handles  ntag == 0  case correctly */
+int
+tag_search(float time) {
+	int	low = -1, high = ntag, m;
+
+	while ( high-low > 1 ) {
+		m = (high+low) / 2;
+		if (time <= tags[m].time) {high = m; } else { low = m; }
+	}
+	return high;
+}
+
+static void
+tag_sort() { }
+
+static void *
+tag_alloc() {
+	if (ntag >= ntagalloc) {
+		ntagalloc += 100;
+		tags = realloc(tags, ntagalloc * sizeof(struct tag));
+/* printf("%p\n", tags); */
+		return tags;
+	}
+	return tags;
+}
+
+static int
+tag_read(char *tagfile) {
+	FILE	*file;
+	float	time;
+	int	ntag = 0, res;
+	char	ctype, *chres;
+
+	if ( (file = fopen(tagfile, "r")) == NULL) return 0;
+	while ( (res = fscanf(file, "%f %c\n", &time, &ctype) ) ) {
+		chres = tag_alloc();
+		if (res == EOF) break;
+		tags[ntag].time = time;
+		tags[ntag].type = tag_ctotype(ctype);
+		ntag++;
+	}
+	fclose(file);
+	return ntag;
+}
+
+void
+tag_init(char *filename) {
+	char	*chres, *home, *slash;
+
+	chres = tag_alloc();
+
+	/* let us assume that file with the same name is the same file even in different directory */
+        home = getenv("HOME");
+        if (home) strncpy(tagfile, home, FILENAME_MAX);
+        strcat(tagfile, "/.sox");
+	mkdir(tagfile, 0755);	/* create the directory just in case */
+        strcat(tagfile, "/tags");
+	mkdir(tagfile, 0755);
+        strcat(tagfile, "/");
+
+	if ( (slash = rindex(filename, '/')) == NULL ) {
+		slash = filename;
+	} else {
+		slash++;
+	}
+	strncat(tagfile, slash, FILENAME_MAX);
+	tagfile[FILENAME_MAX-1] = '\0';		/* just in case it is a veeery long name */
+	ntag = tag_read(tagfile);
+	tag_sort();
+}
+
+/* void
+tag_insert(float time) { } */
+
+static void
+tag_save(char *tagfile) {
+	int	itag;
+	FILE	*file;
+
+	/* write to file */
+	/* (for huge number of tags use .db or write only new tags at the and
+	   and mark old ones (keep the record numbers!) with 'd') */
+	if ( (file = fopen(tagfile, "w")) == NULL) return;
+	for (itag = 0; itag < ntag; itag++) fprintf(file, "%.2f %c\n", tags[itag].time, tag_typetoc(tags[itag].type));
+	fclose(file);
+}
+
+void
+tag_add(float time, char ctype) {
+	int	itime, ins;
+
+	tag_alloc();
+	itime = tag_search(time);
+
+	for (ins = ntag; ins > itime; ins--) tags[ins] = tags[ins-1];	/* tag_insert() */
+	tags[itime].time = time;
+	tags[itime].type = tag_ctotype(ctype);
+	ntag++;
+
+	tag_save(tagfile);
+}
+
+void
+tag_delete(float time, float range) {
+	int	itime, jtime;
+
+	itime = tag_search(time) - 1;
+	if ( (itime >= 0) && (time - tags[itime].time <= range) ) {
+		for (jtime = itime; jtime < ntag - 1; jtime++) tags[jtime] = tags[jtime + 1];
+		ntag--;
+		tag_save(tagfile);
+	}
+}
+
+
+float
+tag_jump(float time, char type) {
+	int	itime;
+
+	/* search for next bigger index
+	   in case of Previous tag jump substract N s to allow passing thru any tag backward
+	   otherwise we are stuck in recent_jump_time+fraction_of_a_second and cannot get over it
+	*/
+	itime = tag_search(time - (type=='P'?2:0) );
+	switch (type) {
+		case 'P': if (itime - 1 >= 0) return tags[itime-1].time; break;
+		case 'N': if (itime < ntag)   return tags[itime].time; break;
+		default: return -1.0;
+	}
+	return -1.0;
+}
+
+char *
+tag_hms(float time) {
+	int		h, m, s;
+	static char	hms[20];
+
+	s = time + 0.5;
+	m = s / 60;
+	s = s - 60 * m;
+	h = m / 60;
+	m = m - 60 * h;
+	snprintf(hms, 20, "%2d:%02d:%02d", h, m, s);
+	return hms;
+}
+
+#define	ROW0	(Y0 + 7)
+#define DCOL	12
+void
+tag_display(WINDOW *win, float time) { 
+	int		row = ROW0-1, col = 0, itime, jtime, maxx, maxy;
+	static int	prevntag = 0;
+
+	if (!beinteractive) return;
+	getmaxyx(win, maxy, maxx);
+	itime = tag_search(time);	/* index of 1st larger time */
+
+	for (jtime = -1; jtime < max(ntag, prevntag); jtime++) {
+		if ( (jtime == itime - 1) ) standout();
+		if (jtime < ntag) {
+			if (jtime >=0) mvwprintw(win, row, col, "%8s %c", tag_hms(tags[jtime].time), tag_typetoc(tags[jtime].type) );
+		} else {	/* ntag decreased since last display */
+			standend();
+			mvwprintw(win, row, col, "%8s %c", "        ", ' ' );
+		}
+		if (jtime == itime) standend();
+		row++;
+		/* XXX if (row > ...) ... */
+		if (row >= maxy) { row = ROW0; col += DCOL; }
+	}
+	prevntag = ntag;
+	standend();
+}
+
+#endif /* TAGGING */
diff -Nru sox.20050917/src/tag.h sox.20050917-inst6/src/tag.h
--- sox.20050917/src/tag.h	1970-01-01 01:00:00.000000000 +0100
+++ sox.20050917-inst6/src/tag.h	2007-02-21 13:27:20.000000000 +0100
@@ -0,0 +1,40 @@
+/* tag.h - various structures and defines used for tagging. */
+
+#ifndef TAG_H_INCLUDED
+#define TAG_H_INCLUDED
+
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <ncurses.h>
+
+#include "interactive.h"
+
+struct tag {
+	float	time;
+	char	type;
+};
+
+#define	TAG_UNK		0
+#define	TAG_BEG		1
+#define	TAG_END		2
+#define	TAG_DEL		4	/* for future use: untagged tag */
+
+#define TAG_PREV	'P'
+#define TAG_NEXT	'N'
+
+#define	max(x,y)	((x > y) ? x : y)
+void tag_init(char *filename);
+void tag_add(float time, char type);
+void tag_display(WINDOW *win, float time);
+float tag_jump(float time, char type);
+void tag_delete(float time, float range);
+int tag_search(float time);
+
+#endif /* TAG_H_INCLUDED */
+
diff -Nru sox.20050917/src/util.c sox.20050917-inst6/src/util.c
--- sox.20050917/src/util.c	2005-09-17 18:13:04.000000000 +0200
+++ sox.20050917-inst6/src/util.c	2007-02-21 13:27:20.000000000 +0100
@@ -34,6 +34,10 @@
  * the ST library.
  */
 char *myname = 0;
+extern int bufferr;
+int namelen;
+
+char	bufrep[100];
 
 void st_report(const char *fmt, ...)
 {
@@ -42,36 +46,73 @@
         if (! verbose)
                 return;
 
-        fprintf(stderr, "%s: ", myname);
-        va_start(args, fmt);
-        vfprintf(stderr, fmt, args);
-        va_end(args);
-        fprintf(stderr, "\n");
+	if (!bufferr) {
+            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);
+	}
 }
 
+
+char	bufwarn[100];
+
 void st_warn(const char *fmt, ...)
 {
         va_list args;
 
-        fprintf(stderr, "%s: ", myname);
-        va_start(args, fmt);
-
-        vfprintf(stderr, fmt, args);
-        va_end(args);
-        fprintf(stderr, "\n");
+	if (!bufferr) {
+            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);
+	}
 }
 
+
+char	buffail[100];
+
 void st_fail(const char *fmt, ...)
 {
         va_list args;
         extern void cleanup();
 
-        fprintf(stderr, "%s: ", myname);
-
-        va_start(args, fmt);
-        vfprintf(stderr, fmt, args);
-        va_end(args);
-        fprintf(stderr, "\n");
+	if (!bufferr) {
+            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);
+	}
         cleanup();
         exit(2);
 }
diff -Nru sox.20050917/src/wav.c sox.20050917-inst6/src/wav.c
--- sox.20050917/src/wav.c	2005-09-17 18:13:04.000000000 +0200
+++ sox.20050917-inst6/src/wav.c	2007-02-21 13:27:20.000000000 +0100
@@ -1745,10 +1745,25 @@
     {
         case WAVE_FORMAT_IMA_ADPCM:
         case WAVE_FORMAT_ADPCM:
+            st_fail_errno(ft,ST_ENOTSUP,"PCM not supported");
+            break;
 #ifdef ENABLE_GSM
         case WAVE_FORMAT_GSM610:
+	    {	st_size_t	gsmoff;
+		/* rounding bytes to blockAlign */
+		gsmoff = offset * wav->blockAlign / wav->samplesPerBlock + wav->blockAlign * ft->info.channels / 2;
+		gsmoff -= gsmoff % (wav->blockAlign * ft->info.channels);
+		ft->st_errno = st_seek(ft, gsmoff + wav->dataStart, SEEK_SET);
+		if( ft->st_errno == ST_SUCCESS )
+		    new_offset = offset;
+		    alignment = offset % wav->samplesPerBlock;	/* offset is in samples */
+		    if (alignment != 0)
+			new_offset += (wav->samplesPerBlock - alignment);
+		    wav->numSamples = ft->length - (new_offset / ft->info.channels);
+		}
+#else
+            st_fail_errno(ft,ST_ENOTSUP,"GSM support not compiled in");
 #endif
-            st_fail_errno(ft,ST_ENOTSUP,"Only PCM Supported");
             break;
         default:
             new_offset = offset * ft->info.size;
@@ -1756,7 +1771,7 @@
             channel_block = ft->info.channels * ft->info.size;
             alignment = new_offset % channel_block;
             /* Most common mistaken is to compute something like
-             * "skip everthing upto and including this sample" so
+             * "skip everything upto and including this sample" so
              * advance to next sample block in this case.
              */
             if (alignment != 0)
