diff -Nru --exclude CVS sox.20050917-inst/src/interactive.c sox.20050917-inst2/src/interactive.c
--- sox.20050917-inst/src/interactive.c	2005-09-18 00:40:57.000000000 +0200
+++ sox.20050917-inst2/src/interactive.c	2005-10-27 17:46:59.000000000 +0200
@@ -12,18 +12,17 @@
 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;
-	short		c;
 	int		pfile, err;
 	struct stat	fstat;
 
-	printf("sizeof(c): %d\n", sizeof(c));
 	home = getenv("HOME");
-	if (home); strncpy(spfile, home, sizeof(spfile)-1);
+	if (home) strncpy(spfile, home, sizeof(spfile)-1);
 	strcat(spfile, "/.soxi");
 
 	err = 0;
@@ -60,6 +59,38 @@
 #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();
@@ -75,6 +106,8 @@
 		informat0, outformat);
 #if defined(COMMUNICATION)
 	pfile = init_pipe();
+	prevstate = state_read();
+	state_write(' ');
 #endif
 }
 
@@ -243,6 +276,11 @@
 	float		tmpspeed;
 	static float	time = 0, ptime, pos = 0, oldspeed = -1;
 	static struct timespec	sl = { 0, 200000000 };
+#if defined(TAGGING)
+	int		passtag;
+	static int	prevpasstag;
+	float		ntime;
+#endif
 
 	if (oldspeed == -1) oldspeed = speed;
 
@@ -264,6 +302,10 @@
 			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:	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;
@@ -288,12 +330,31 @@
 			case '=':	oldspeed = speed; speed = 3.0; chspeed = 1; break;
 			case '\177':	oldspeed = speed; speed = 3.2; chspeed = 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); tag_display(win, time); break;
+#endif
+
+			case KEY_RESIZE:
 			case '':	/* redrawwin(win); */ init_curses(&win, informat0, outformat); break;
-			case 'q':	*pquit = 1; 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) { nanosleep(&sl, NULL); pausecount++; goto pause; }
 
 	jump = (time != ptime);
diff -Nru --exclude CVS sox.20050917-inst/src/tag.c sox.20050917-inst2/src/tag.c
--- sox.20050917-inst/src/tag.c	1970-01-01 01:00:00.000000000 +0100
+++ sox.20050917-inst2/src/tag.c	2005-10-27 17:41:17.000000000 +0200
@@ -0,0 +1,203 @@
+#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) {
+	int	itime, jtime;
+
+	itime = tag_search(time) - 1;
+	if ( (itime >= 0) && (time - tags[itime].time <= 5) ) {
+		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;
+
+	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 --exclude CVS sox.20050917-inst/src/tag.h sox.20050917-inst2/src/tag.h
--- sox.20050917-inst/src/tag.h	1970-01-01 01:00:00.000000000 +0100
+++ sox.20050917-inst2/src/tag.h	2005-09-21 00:50:25.000000000 +0200
@@ -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);
+int tag_search(float time);
+
+#endif /* TAG_H_INCLUDED */
+
diff -Nru --exclude CVS sox.20050917-inst/src/wav.c sox.20050917-inst2/src/wav.c
--- sox.20050917-inst/src/wav.c	2005-09-17 18:13:04.000000000 +0200
+++ sox.20050917-inst2/src/wav.c	2005-09-20 16:18:40.000000000 +0200
@@ -1745,10 +1745,21 @@
     {
         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;
+		/* dwDataLength is divided by wav->blockAlign in line 859
+		so let's assume blockAlign is in bytes */
+		/* rounding to blockAlign */
+		gsmoff = offset * ft->info.size + wav->blockAlign / 2;
+		gsmoff -= gsmoff % wav->blockAlign;
+		ft->st_errno = st_seek(ft, gsmoff + wav->dataStart, SEEK_SET);
+	    }
+#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;
