--- 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)