--- sox.20050917/README.interactive     1970-01-01 01:00:00.000000000 +0100
+++ sox.20050917-inst7/README.interactive       2014-05-08 12:52:21.699375072 +0200
@@ -0,0 +1,183 @@
+                               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
+- 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.
+
+2014-05-07 print time difference between beginning and ending tags, the b-e tags pairs can be nested
diff -Nru sox.20050917/scripts/myplay sox.20050917-inst7/scripts/myplay
--- sox.20050917/scripts/myplay 1970-01-01 01:00:00.000000000 +0100
+++ sox.20050917-inst7/scripts/myplay   2009-05-05 14:38:30.019417000 +0200
@@ -0,0 +1,21 @@
+#!/bin/sh
+
+eatbuf="-r 44100 -c 4 -w"
+eatbuf=""
+
+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 0.333333 vol 0 dB
+#~/bin/sox -I "$1" $eatbuf -t alsa pulse stretch 0.333333 vol 0 dB
+#TODO: read total pauses value seconds?
+
+end=`date '+%s'`
+tdiff=$(( $end - $start ))
+echo "stop  $1 "`date` $tdiff >> $log
diff -Nru sox.20050917/scripts/rmplay sox.20050917-inst7/scripts/rmplay
--- sox.20050917/scripts/rmplay 1970-01-01 01:00:00.000000000 +0100
+++ sox.20050917-inst7/scripts/rmplay   2014-01-01 16:52:10.000000000 +0100
@@ -0,0 +1,60 @@
+#!/bin/bash
+# player script for sox - Rafał Maszkowski <[email protected]>
+# ...      created by [email protected]
+# 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
+# 20070525 ls ..*.. overflow, using find
+# 20080827 rm20... AND rm-20...
+# 20090115 AND tvt-...
+# 2010-02-12 regex
+# 2010-04-27 .rpmlay.$$ -> ~/...
+# 2011-11-29 find -regex was matching only 2 chars before '-' (TODO: turn rmplay into seqplay - playing consecutive files with any prefix - DONE?); UTF-8
+# 2014-01-01 sh->bash (makes a difference on Debian)
+# $1 - start, optional
+
+active=~/.rmplay.$$
+touch $active
+
+# accept calling without arguments
+if [ "$1" != "" ]; then
+       file=$1
+else
+       file=`ls [a-zA-Z_][a-zA-Z_0-9]*{,-}[12]*[0-9].wav | head -1`
+       if [ "$file" == "" ]; then
+               echo No files to play. Exiting...
+               exit
+       fi
+fi
+
+while true; do
+       echo $file > $active
+ls -l $file
+       myplay $file
+#bash -xv /home/staff/rzm/bin/myplay $file
+# echo myplay $file; sleep 1
+       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=`find . -maxdepth 1 -regex './[a-zA-Z_][a-zA-Z_0-9]*-?*[12][0-9]*[0-9].wav' | sed 's/^\.\///' | sort | 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-inst7/scripts/sox
--- sox.20050917/scripts/sox    1970-01-01 01:00:00.000000000 +0100
+++ sox.20050917-inst7/scripts/sox      2014-05-07 22:32:34.080136000 +0200
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+#/home/staff/rzm/ukwial/src/sox.20050917-inst2/src/sox $*
+#/home/staff/rzm/ukwial/src/sox.20050917-inst6/src/sox $*
+#padsp /home/rzm/ukwial/src/sox.20050917-inst6/src/sox $*
+#/home/rzm/ukwial/src/sox.20050917-inst6/src/sox $*
+#padsp /home/rzm/src/sox.20050917-inst6/src/sox $*
+# 2014-03-20 cisza z padsp - rzm
+##/home/rzm/src/sox.20050917-inst6/src/sox $*
+# 2014-03-20? powrót do padsp
+##padsp /home/rzm/src/sox.20050917-inst6/src/sox $*
+# 2014-05-07 nowa wersja, z długością obsz. tagowanego
+padsp /home/rzm/src/sox.20050917-inst7/src/sox $*
diff -Nru sox.20050917/src/interactive.c sox.20050917-inst7/src/interactive.c
--- sox.20050917/src/interactive.c      1970-01-01 01:00:00.000000000 +0100
+++ sox.20050917-inst7/src/interactive.c        2007-04-12 15:10:51.000000000 +0200
@@ -0,0 +1,430 @@
+#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];
+       time_t          playt, curt, difft, difftd;
+       struct tm       playtm, *tm;
+       struct timeval  tv;
+       struct timezone tz;
+
+       bzero(&playtm, sizeof(playtm));
+       playtm.tm_year = y - 1900; playtm.tm_mon = m - 1; playtm.tm_mday = d + dd;
+       playtm.tm_sec = ptime; playtm.tm_isdst = -1; /* not known */
+       playt = mktime(&playtm);
+
+       gettimeofday(&tv, &tz);
+       curt = tv.tv_sec + ((tv.tv_usec >= 500000) ? 1 : 0); /* no 60*tz.tz_minuteswest substraction cos tv is local */
+
+       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-inst7/src/interactive.h
--- sox.20050917/src/interactive.h      1970-01-01 01:00:00.000000000 +0100
+++ sox.20050917-inst7/src/interactive.h        2007-02-22 14:07:53.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-inst7/src/Makefile.in
--- sox.20050917/src/Makefile.in        2005-09-17 18:13:03.000000000 +0200
+++ sox.20050917-inst7/src/Makefile.in  2005-09-19 21:33:14.000000000 +0200
@@ -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)

Binarne pliki sox.20050917/src/sox i sox.20050917-inst7/src/sox różnią się
diff -Nru sox.20050917/src/sox.c sox.20050917-inst7/src/sox.c
--- sox.20050917/src/sox.c      2005-09-17 18:13:04.000000000 +0200
+++ sox.20050917-inst7/src/sox.c        2007-02-02 15:52:02.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,21 @@
    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)
+    if (beinteractive) {
+       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 +720,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 +728,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 +791,7 @@
    }
}

-static void parse_effects(int argc, char **argv)
+void parse_effects(int argc, char **argv)
{
    int argc_effect;

@@ -769,7 +837,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 +1019,7 @@
    }
}

-static void start_effects(void)
+void start_effects(void)
{
    int e;

@@ -962,7 +1030,7 @@
    }
}

-static void reserve_effect_buf(void)
+void reserve_effect_buf(void)
{
    int e;

@@ -1230,7 +1298,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 +1345,7 @@
    return rc;
}

-static void release_effect_buf(void)
+void release_effect_buf(void)
{
    int e;

@@ -1289,7 +1357,7 @@
    }
}

-static void stop_effects(void)
+void stop_effects(void)
{
    int e;

@@ -1427,7 +1495,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++) {
Binarne pliki sox.20050917/src/soxmix i sox.20050917-inst7/src/soxmix różnią się
diff -Nru sox.20050917/src/st.h sox.20050917-inst7/src/st.h
--- sox.20050917/src/st.h       2005-09-17 18:13:04.000000000 +0200
+++ sox.20050917-inst7/src/st.h 2005-09-18 00:54:10.000000000 +0200
@@ -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-inst7/src/st_i.h
--- sox.20050917/src/st_i.h     2005-09-17 18:13:04.000000000 +0200
+++ sox.20050917-inst7/src/st_i.h       2005-09-17 18:34:24.000000000 +0200
@@ -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-inst7/src/tag.c
--- sox.20050917/src/tag.c      1970-01-01 01:00:00.000000000 +0100
+++ sox.20050917-inst7/src/tag.c        2014-05-07 23:32:27.870503067 +0200
@@ -0,0 +1,228 @@
+#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;
+}
+
+/* Search for beginning tag and return time difference in s. Use nesting: any 'e' tag adds one to the counter of 'b's looked for, 'b' tag substacts
+   one */
+int
+tag_len(int iend) {
+       int     ind, btofind = 1;
+
+       for (ind = iend - 1; ind >= 0; ind--) {
+               if (tags[ind].type == TAG_BEG) btofind--;
+               if (tags[ind].type == TAG_END) btofind++;
+               if (btofind == 0) return tags[iend].time - tags[ind].time;
+       }
+       return -1;
+}
+
+#define        ROW0    (Y0 + 7)
+#define DCOL   12
+void
+tag_display(WINDOW *win, float time) {
+       char            stdiff[10], *idiff;
+       int             row = ROW0-1, col = 0, itime, jtime, maxx, maxy, tdiff;
+       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) {
+                       stdiff[0] = '\0'; tdiff = -1;
+                       if (tags[jtime].type == TAG_END) {
+                               tdiff = tag_len(jtime);
+                               if (tdiff != -1) {
+                                       strncpy(stdiff, tag_hms(tdiff), sizeof(stdiff));
+                                       idiff = stdiff;
+                                       while ( (*idiff == '0' || *idiff == ':' || *idiff == ' ') && idiff < stdiff + strlen(stdiff) - 2 ) {
+                                               *idiff = ' ';   idiff++;
+                                       }
+                               }
+                       }
+                       if (jtime >=0) mvwprintw(win, row, col, "%8s %c %s", tag_hms(tags[jtime].time), tag_typetoc(tags[jtime].type), stdiff);
+               } else {        /* ntag decreased since last display */
+                       standend();
+                       mvwprintw(win, row, col, "%8s %c %s", "        ", ' ', "        ");
+               }
+               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-inst7/src/tag.h
--- sox.20050917/src/tag.h      1970-01-01 01:00:00.000000000 +0100
+++ sox.20050917-inst7/src/tag.h        2006-05-28 21:23:03.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, float range);
+int tag_search(float time);
+
+#endif /* TAG_H_INCLUDED */
+
diff -Nru sox.20050917/src/util.c sox.20050917-inst7/src/util.c
--- sox.20050917/src/util.c     2005-09-17 18:13:04.000000000 +0200
+++ sox.20050917-inst7/src/util.c       2005-09-17 18:34:24.000000000 +0200
@@ -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-inst7/src/wav.c
--- sox.20050917/src/wav.c      2005-09-17 18:13:04.000000000 +0200
+++ sox.20050917-inst7/src/wav.c        2007-03-01 16:32:26.000000000 +0100
@@ -1745,10 +1745,27 @@
    {
        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 down to blockAlign */
+               gsmoff = offset / wav->samplesPerBlock * wav->blockAlign;
+               /* is the fraction bigger than half of the block? */
+               if ( (offset % wav->samplesPerBlock) * wav->blockAlign / wav->samplesPerBlock >
+                        wav->blockAlign * ft->info.channels / 2 ) 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 +1773,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)