📄 sox.c
字号:
for (i = 0; i < efftab[0].olen; i++) efftab[0].obuf[i] = volumechange(efftab[0].obuf[i]); /* Run input data through effects and get more until olen == 0 */ while (efftab[0].olen > 0) { /* mark chain as empty */ for(e = 1; e < neffects; e++) efftab[e].odone = efftab[e].olen = 0; do { /* run entire chain BACKWARDS: pull, don't push.*/ /* this is because buffering system isn't a nice queueing system */ for(e = neffects - 1; e > 0; e--) if (flow_effect(e)) break; /* If outputing and output data was generated then write it */ if (writing&&(efftab[neffects-1].olen>efftab[neffects-1].odone)) { (* outformat.h->write)(&outformat, efftab[neffects-1].obuf, (LONG) efftab[neffects-1].olen); efftab[neffects-1].odone = efftab[neffects-1].olen; } /* if stuff still in pipeline, set up to flow effects again */ havedata = 0; for(e = 0; e < neffects - 1; e++) if (efftab[e].odone < efftab[e].olen) { havedata = 1; break; } } while (havedata); /* Read another chunk of input data. */ efftab[0].olen = (*informat.h->read)(&informat, efftab[0].obuf, (LONG) BUFSIZ); efftab[0].odone = 0; /* Change volume of these samples if needed. */ if (dovolume) for (i = 0; i < efftab[0].olen; i++) efftab[0].obuf[i] = volumechange(efftab[0].obuf[i]); } /* 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) */ if (writing&&efftab[neffects-1].olen > 0) (* outformat.h->write)(&outformat, efftab[neffects-1].obuf, (LONG) efftab[neffects-1].olen); if (efftab[f].olen != BUFSIZ) break; } } /* 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]); } (* informat.h->stopread)(&informat); fclose(informat.fp); if (writing) (* outformat.h->stopwrite)(&outformat); if (writing) fclose(outformat.fp);}int flow_effect(e)int e;{ LONG i, idone, odone, idonel, odonel, idoner, odoner; LONG *ibuf, *obuf; /* I have no input data ? */ if (efftab[e-1].odone == efftab[e-1].olen) return 0; if (! efftabR[e].name) { /* No stereo data, or effect can handle stereo data so * run effect over entire buffer. */ idone = efftab[e-1].olen - efftab[e-1].odone; odone = BUFSIZ; (* efftab[e].h->flow)(&efftab[e], &efftab[e-1].obuf[efftab[e-1].odone], efftab[e].obuf, &idone, &odone); efftab[e-1].odone += idone; efftab[e].odone = 0; efftab[e].olen = odone; } else { /* Put stereo data in two seperate buffers and run effect * on each of them. */ idone = efftab[e-1].olen - efftab[e-1].odone; odone = BUFSIZ; ibuf = &efftab[e-1].obuf[efftab[e-1].odone]; for(i = 0; i < idone; i += 2) { ibufl[i/2] = *ibuf++; ibufr[i/2] = *ibuf++; } /* left */ idonel = (idone + 1)/2; /* odd-length logic */ odonel = odone/2; (* efftab[e].h->flow)(&efftab[e], ibufl, obufl, &idonel, &odonel); /* right */ idoner = idone/2; /* odd-length logic */ odoner = odone/2; (* efftabR[e].h->flow)(&efftabR[e], ibufr, obufr, &idoner, &odoner); obuf = efftab[e].obuf; /* This loop implies left and right effect will always output * the same amount of data. */ for(i = 0; i < odoner; i++) { *obuf++ = obufl[i]; *obuf++ = obufr[i]; } efftab[e-1].odone += idonel + idoner; efftab[e].odone = 0; efftab[e].olen = odonel + odoner; } if (idone == 0) fail("Effect took no samples!"); return 1;}int drain_effect(e)int e;{ LONG i, olen, olenl, olenr; LONG *obuf; if (! efftabR[e].name) { efftab[e].olen = BUFSIZ; (* efftab[e].h->drain)(&efftab[e],efftab[e].obuf, &efftab[e].olen); } else { olen = BUFSIZ; /* left */ olenl = olen/2; (* efftab[e].h->drain)(&efftab[e], obufl, &olenl); /* right */ olenr = olen/2; (* efftab[e].h->drain)(&efftabR[e], obufr, &olenr); obuf = efftab[e].obuf; /* This loop implies left and right effect will always output * the same amount of data. */ for(i = 0; i < olenr; i++) { *obuf++ = obufl[i]; *obuf++ = obufr[i]; } efftab[e].olen = olenl + olenr; } return(efftab[e].olen);}#define setin(eff, effname) \ {eff.name = effname; \ eff.ininfo.rate = informat.info.rate; \ eff.ininfo.channels = informat.info.channels; \ eff.outinfo.rate = informat.info.rate; \ eff.outinfo.channels = informat.info.channels;}#define setout(eff, effname) \ {eff.name = effname; \ eff.ininfo.rate = outformat.info.rate; \ eff.ininfo.channels = outformat.info.channels; \ eff.outinfo.rate = outformat.info.rate; \ eff.outinfo.channels = outformat.info.channels;}/* * If no effect given, decide what it should be. * Smart ruleset for multiple effects in sequence. * Puts user-specified effect in right place. */voidcheckeffect(effp)eff_t effp;{ int i, j; int needchan = 0, needrate = 0; /* if given effect does these, we don't need to add them */ needrate = (informat.info.rate != outformat.info.rate) && ! (effp->h->flags & EFF_RATE); needchan = (informat.info.channels != outformat.info.channels) && ! (effp->h->flags & EFF_MCHAN); neffects = 1; /* effect #0 is the input stream */ /* inform all effects about all relevant changes */ for(i = 0; i < MAXEFF; i++) { efftab[i].name = efftabR[i].name = (char *) 0; /* inform effect about signal information */ efftab[i].ininfo = informat.info; efftabR[i].ininfo = informat.info; efftab[i].outinfo = outformat.info; efftabR[i].outinfo = outformat.info; for(j = 0; j < 8; j++) { memcpy(&efftab[i].loops[j], &informat.loops[j], sizeof(struct loopinfo)); memcpy(&efftabR[i].loops[j], &informat.loops[j], sizeof(struct loopinfo)); } efftab[i].instr = informat.instr; efftabR[i].instr = informat.instr; } /* If not writing output, then just add the user specified effect. * This is to avoid channel and rate averaging since you don't have * a real output format. */ if (! writing) { neffects = 2; efftab[1].name = effp->name; if ((informat.info.channels == 2) && (! (effp->h->flags & EFF_MCHAN))) efftabR[1].name = effp->name; } else if (soxpreview) { /* to go faster, i suppose rate could come first if downsampling */ if (needchan && (informat.info.channels > outformat.info.channels)) { if (needrate) { neffects = 4; efftab[1].name = "avg"; efftab[2].name = "rate"; setout(efftab[3], effp->name); } else { neffects = 3; efftab[1].name = "avg"; setout(efftab[2], effp->name); } } else if (needchan && (informat.info.channels < outformat.info.channels)) { if (needrate) { neffects = 4; efftab[1].name = effp->name; efftab[1].outinfo.rate = informat.info.rate; efftab[1].outinfo.channels = informat.info.channels; efftab[2].name = "rate"; efftab[3].name = "avg"; } else { neffects = 3; efftab[1].name = effp->name; efftab[1].outinfo.channels = informat.info.channels; efftab[2].name = "avg"; } } else { if (needrate) { neffects = 3; efftab[1].name = effp->name; efftab[1].outinfo.rate = informat.info.rate; efftab[2].name = "rate"; if (informat.info.channels == 2) efftabR[2].name = "rate"; } else { neffects = 2; efftab[1].name = effp->name; } if ((informat.info.channels == 2) && (! (effp->h->flags & EFF_MCHAN))) efftabR[1].name = effp->name; } } else { /* not preview mode */ /* [ sum to mono,] [ then rate,] then effect */ /* not the purest, but much faster */ if (needchan && (informat.info.channels > outformat.info.channels)) { if (needrate && (informat.info.rate != outformat.info.rate)) { neffects = 4; efftab[1].name = "avg"; efftab[2].name = effp->name; efftab[2].outinfo.rate = informat.info.rate; efftab[2].outinfo.channels = informat.info.channels; efftab[3].name = "rate"; } else { neffects = 3; efftab[1].name = "avg"; efftab[2].name = effp->name; efftab[2].outinfo.rate = informat.info.rate; efftab[2].outinfo.channels = informat.info.channels; } } else if (needchan && (informat.info.channels < outformat.info.channels)) { if (needrate) { neffects = 4; efftab[1].name = effp->name; if (! (effp->h->flags & EFF_MCHAN)) efftabR[1].name = effp->name; efftab[1].outinfo.rate = informat.info.rate; efftab[1].outinfo.channels = informat.info.channels; efftab[2].name = "rate"; efftab[3].name = "avg"; } else { neffects = 3; efftab[1].name = effp->name; if (! (effp->h->flags & EFF_MCHAN)) efftabR[1].name = effp->name; efftab[1].outinfo.channels = informat.info.channels; efftab[2].name = "avg"; } } else { if (needrate) { neffects = 3; efftab[1].name = effp->name; efftab[1].outinfo.rate = informat.info.rate; efftab[2].name = "rate"; if (informat.info.channels == 2) efftabR[2].name = "rate"; } else { neffects = 2; efftab[1].name = effp->name; } if ((informat.info.channels == 2) && (! (effp->h->flags & EFF_MCHAN))) efftabR[1].name = effp->name; } } for(i = 1; i < neffects; i++) { /* pointer comparison OK here */ /* shallow copy of initialized effect data */ /* XXX this assumes that effect_getopt() doesn't malloc() */ if (efftab[i].name == effp->name) { memcpy(&efftab[i], &eff, sizeof(struct effect)); if (efftabR[i].name) memcpy(&efftabR[i], &eff, sizeof(struct effect)); } else { /* set up & give default opts for added effects */ geteffect(&efftab[i]); (* efftab[i].h->getopts)(&efftab[i],0,(char *)0); if (efftabR[i].name) memcpy(&efftabR[i], &efftab[i], sizeof(struct effect)); } } /* If a user doesn't specify an effect then a null entry could * have been placed in the middle of the list above. Remove * those entries here. */ for(i = 1; i < neffects; i++) if (! strcmp(efftab[i].name, "null")) { for(; i < neffects; i++) { efftab[i] = efftab[i+1]; efftabR[i] = efftabR[i+1]; } neffects--; }}/* Guido Van Rossum fix */void statistics() { if (dovolume && clipped > 0) report("Volume change clipped %d samples", clipped);}LONG volumechange(y)LONG y;{ double y1; y1 = y * volume; if (y1 < -2147483647.0) { y1 = -2147483647.0; clipped++; } else if (y1 > 2147483647.0) { y1 = 2147483647.0; clipped++; } return y1;}#if defined(unix) || defined(AMIGA)int filetype(fd)int fd;{ struct stat st; fstat(fd, &st); return st.st_mode & S_IFMT;}#endifchar *usagestr = "[ gopts ] [ fopts ] ifile [ fopts ] ofile [ effect [ effopts ] ]";void usage(opt)char *opt;{ int i; #ifndef DOS /* single-threaded machines don't really need this */ fprintf(stderr, "%s: ", myname);#endif if (verbose || !opt) fprintf(stderr, "%s\n\n", version()); fprintf(stderr, "Usage: %s\n\n", usagestr); if (opt) fprintf(stderr, "Failed at: %s\n", opt); else { fprintf(stderr,"gopts: -e -h -p -v volume -V\n\n"); fprintf(stderr,"fopts: -r rate -c channels -s/-u/-U/-A/-a/-g -b/-w/-l/-f/-d/-D -x\n\n"); fprintf(stderr, "effect: "); for (i = 1; effects[i].name != NULL; i++) { fprintf(stderr, "%s ", effects[i].name); } fprintf(stderr, "\n\neffopts: depends on effect\n\n"); fprintf(stderr, "Supported file formats: "); for (i = 0; formats[i].names != NULL; i++) { /* only print the first name */ fprintf(stderr, "%s ", formats[i].names[0]); } fputc('\n', stderr); } exit(1);}/* called from util.c:fail */void cleanup() { /* Close the input file and outputfile before exiting*/ if (informat.fp) fclose(informat.fp); if (outformat.fp) { fclose(outformat.fp); /* remove the output file because we failed, if it's ours. */ /* unless its a unix /dev/sound type file */#ifdef unix if (filetype(fileno(outformat.fp)) == S_IFREG)#endif REMOVE(outformat.filename); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -