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