/* * Do anything required when you stop reading samples. * Don't close input file! */ int st_vol_stop(eff_t effp) { vol_t vol = (vol_t) effp->priv; if (vol->limited) { st_warn("VOL limited %d values (%d percent).", vol->limited, (int) (vol->limited * 100.0 / vol->totalprocessed)); } if (vol->clipped) { st_warn("VOL clipped %d values, amplitude gain=%f too high...", vol->clipped, vol->gain); } return ST_SUCCESS; }
/* * Process tail of input samples. */ int st_resample_drain(eff_t effp, st_sample_t *obuf, st_size_t *osamp) { resample_t r = (resample_t) effp->priv; long isamp_res, osamp_res; st_sample_t *Obuf; int rc; /* fprintf(stderr,"Xoff %d, Xt %d <--- DRAIN\n",r->Xoff, r->Xt); */ /* stuff end with Xoff zeros */ isamp_res = r->Xoff; osamp_res = *osamp; Obuf = obuf; while (isamp_res>0 && osamp_res>0) { st_sample_t Isamp, Osamp; Isamp = isamp_res; Osamp = osamp_res; rc = st_resample_flow(effp, NULL, Obuf, (st_size_t *)&Isamp, (st_size_t *)&Osamp); if (rc) return rc; /* fprintf(stderr,"DRAIN isamp,osamp (%d,%d) -> (%d,%d)\n", isamp_res,osamp_res,Isamp,Osamp); */ Obuf += Osamp; osamp_res -= Osamp; isamp_res -= Isamp; } *osamp -= osamp_res; /* fprintf(stderr,"DRAIN osamp %d\n", *osamp); */ if (isamp_res) st_warn("drain overran obuf by %d\n", isamp_res); fflush(stderr); return (ST_SUCCESS); }
/* * Drain out remaining samples if the effect generates any. */ int st_fade_drain(eff_t effp, st_sample_t *obuf, st_size_t *osamp) { fade_t fade = (fade_t) effp->priv; int len, t_chan = 0; len = *osamp; *osamp = 0; if (fade->do_out && fade->samplesdone < fade->out_stop && !(fade->endpadwarned)) { /* Warning about padding silence into end of sample */ st_warn("Fade: warning: End time passed end-of-file. Padding with silence"); fade->endpadwarned = 1; } /* endif endpadwarned */ for (;len && (fade->do_out && fade->samplesdone < fade->out_stop); len--) { *obuf = 0; obuf++; *osamp += 1; t_chan++; if (t_chan >= effp->ininfo.channels) { fade->samplesdone += 1; t_chan = 0; } /* endif channels */ } /* endfor */ if (fade->do_out && fade->samplesdone >= fade->out_stop) return ST_EOF; else return ST_SUCCESS; }
/* * Do anything required when you stop reading samples. * Don't close input file! */ int st_pitch_stop(eff_t effp) { pitch_t pitch = (pitch_t) effp->priv; free(pitch->fade); free(pitch->tmp); free(pitch->acc); free(pitch->buf); if (pitch->clipped) st_warn("PITCH clipped %d values... adjust volume with -v option maybe?", pitch->clipped); return ST_SUCCESS; }
int st_wvestopwrite(ft_t ft) { /* Call before seeking to flush buffer */ return st_rawstopwrite(ft); if (!ft->seekable) { st_warn("Header will be have invalid file length since file is not seekable"); return ST_SUCCESS; } if (st_seeki(ft, 0L, 0) != 0) { st_fail_errno(ft,errno,"Can't rewind output file to rewrite Psion header."); return(ST_EOF); } wvewriteheader(ft); }
/* Do window management once we have a complete window, including mangling * the current window. */ static int process_window(reddata_t data, int chan_num, int num_chans, st_sample_t *obuf, int len) { int j; float* nextwindow; int use = min(len, WINDOWSIZE)-(WINDOWSIZE/2); chandata_t *chan = &(data->chandata[chan_num]); int first = (chan->lastwindow == NULL); nextwindow = (float*)calloc(WINDOWSIZE, sizeof(float)); memcpy(nextwindow, chan->window+WINDOWSIZE/2, sizeof(float)*(WINDOWSIZE/2)); reduce_noise(chan, chan->window, data->threshold); if (!first) { for (j = 0; j < use; j ++) { float s = chan->window[j] + chan->lastwindow[WINDOWSIZE/2 + j]; if (s < -1 || s > 1) { float news; if (s > 1) news = 1; else news = -1; st_warn("noisered: Output clipped from %f to %f.\n", s, news); } obuf[chan_num + num_chans * j] = ST_FLOAT_DWORD_TO_SAMPLE(s); } free(chan->lastwindow); } else { for (j = 0; j < use; j ++) { assert(chan->window[j] >= -1 && chan->window[j] <= 1); obuf[chan_num + num_chans * j] = ST_FLOAT_DWORD_TO_SAMPLE(chan->window[j]); } } chan->lastwindow = chan->window; chan->window = nextwindow; return use; }
/* * Start processing */ int st_vol_start(eff_t effp) { vol_t vol = (vol_t) effp->priv; if (effp->outinfo.channels != effp->ininfo.channels) { st_warn("VOL cannot handle different channels (in=%d, out=%d)" " use avg or pan", effp->ininfo.channels, effp->outinfo.channels); } if (effp->outinfo.rate != effp->ininfo.rate) { st_fail("VOL cannot handle different rates (in=%ld, out=%ld)" " use resample or rate", effp->ininfo.rate, effp->outinfo.rate); return ST_EOF; } vol->clipped = 0; vol->limited = 0; vol->totalprocessed = 0; return ST_SUCCESS; }
/* * Prepare for processing. */ int st_chorus_start(eff_t effp) { chorus_t chorus = (chorus_t) effp->priv; int i; float sum_in_volume; chorus->maxsamples = 0; if ( chorus->in_gain < 0.0 ) { st_fail("chorus: gain-in must be positive!\n"); return (ST_EOF); } if ( chorus->in_gain > 1.0 ) { st_fail("chorus: gain-in must be less than 1.0!\n"); return (ST_EOF); } if ( chorus->out_gain < 0.0 ) { st_fail("chorus: gain-out must be positive!\n"); return (ST_EOF); } for ( i = 0; i < chorus->num_chorus; i++ ) { chorus->samples[i] = (int) ( ( chorus->delay[i] + chorus->depth[i] ) * effp->ininfo.rate / 1000.0); chorus->depth_samples[i] = (int) (chorus->depth[i] * effp->ininfo.rate / 1000.0); if ( chorus->delay[i] < 20.0 ) { st_fail("chorus: delay must be more than 20.0 msec!\n"); return (ST_EOF); } if ( chorus->delay[i] > 100.0 ) { st_fail("chorus: delay must be less than 100.0 msec!\n"); return (ST_EOF); } if ( chorus->speed[i] < 0.1 ) { st_fail("chorus: speed must be more than 0.1 Hz!\n"); return (ST_EOF); } if ( chorus->speed[i] > 5.0 ) { st_fail("chorus: speed must be less than 5.0 Hz!\n"); return (ST_EOF); } if ( chorus->depth[i] < 0.0 ) { st_fail("chorus: delay must be more positive!\n"); return (ST_EOF); } if ( chorus->depth[i] > 10.0 ) { st_fail("chorus: delay must be less than 10.0 msec!\n"); return (ST_EOF); } if ( chorus->decay[i] < 0.0 ) { st_fail("chorus: decay must be positive!\n" ); return (ST_EOF); } if ( chorus->decay[i] > 1.0 ) { st_fail("chorus: decay must be less that 1.0!\n" ); return (ST_EOF); } chorus->length[i] = effp->ininfo.rate / chorus->speed[i]; if (! (chorus->lookup_tab[i] = (int *) malloc(sizeof (int) * chorus->length[i]))) { st_fail("chorus: Cannot malloc %d bytes!\n", sizeof(int) * chorus->length[i]); return (ST_EOF); } if ( chorus->modulation[i] == MOD_SINE ) st_sine(chorus->lookup_tab[i], chorus->length[i], chorus->depth_samples[i] - 1, chorus->depth_samples[i]); else st_triangle(chorus->lookup_tab[i], chorus->length[i], chorus->samples[i] - 1, chorus->depth_samples[i]); chorus->phase[i] = 0; if ( chorus->samples[i] > chorus->maxsamples ) chorus->maxsamples = chorus->samples[i]; } /* Be nice and check the hint with warning, if... */ sum_in_volume = 1.0; for ( i = 0; i < chorus->num_chorus; i++ ) sum_in_volume += chorus->decay[i]; if ( chorus->in_gain * ( sum_in_volume ) > 1.0 / chorus->out_gain ) st_warn("chorus: warning >>> gain-out can cause saturation or clipping of output <<<"); if (! (chorus->chorusbuf = (float *) malloc(sizeof (float) * chorus->maxsamples))) { st_fail("chorus: Cannot malloc %d bytes!\n", sizeof(float) * chorus->maxsamples); return (ST_EOF); } for ( i = 0; i < chorus->maxsamples; i++ ) chorus->chorusbuf[i] = 0.0; chorus->counter = 0; chorus->fade_out = chorus->maxsamples; return (ST_SUCCESS); }
ft_t st_open_read(const char *path, const st_signalinfo_t *info, const char *filetype) { ft_t ft; ft = (ft_t)calloc(sizeof(struct st_soundstream), 1); if (!ft ) return NULL; ft->filename = strdup(path); /* Let auto effect do the work if user is not overriding. */ if (!filetype) ft->filetype = strdup("auto"); else ft->filetype = strdup(filetype); if (!ft->filename || !ft->filetype) goto input_error; if (st_gettype(ft) != ST_SUCCESS) { st_warn("Unknown input file format for '%s': %s", ft->filename, ft->st_errstr); goto input_error; } ft->info.size = -1; ft->info.encoding = -1; ft->info.channels = -1; if (info) ft->info = *info; /* FIXME: Remove ft->swap from code */ ft->swap = ft->info.swap; ft->mode = 'r'; if (!(ft->h->flags & ST_FILE_NOSTDIO)) { /* Open file handler based on input name. Used stdin file handler * if the filename is "-" */ if (!strcmp(ft->filename, "-")) ft->fp = stdin; else if ((ft->fp = fopen(ft->filename, "rb")) == NULL) { st_warn("Can't open input file '%s': %s", ft->filename, strerror(errno)); goto input_error; } /* See if this file is seekable or not */ ft->seekable = is_seekable(ft); } /* Read and write starters can change their formats. */ if ((*ft->h->startread)(ft) != ST_SUCCESS) { st_warn("Failed reading %s: %s", ft->filename, ft->st_errstr); goto input_error; } /* Go a head and assume 1 channel audio if nothing is detected. * This is because libst usually doesn't set this for mono file * formats (for historical reasons). */ if (ft->info.channels == -1) ft->info.channels = 1; if (st_checkformat(ft) ) { st_fail("bad input format for file %s: %s", ft->filename, ft->st_errstr); goto input_error; } return ft; input_error: if (ft->filename) free(ft->filename); if (ft->filetype) free(ft->filetype); free(ft); return NULL; }
ft_t st_open_write_instr(const char *path, const st_signalinfo_t *info, const char *filetype, const char *comment, const st_instrinfo_t *instr, const st_loopinfo_t *loops) { ft_t ft; int i; ft = (ft_t)calloc(sizeof(struct st_soundstream), 1); if (!ft ) return NULL; ft->filename = strdup(path); /* Let auto effect do the work if user is not overriding. */ if (!filetype) { char *chop; int len; len = strlen(ft->filename); /* Use filename extension to determine audio type. */ chop = ft->filename + len; while (chop > ft->filename && *chop != LASTCHAR) chop--; while (chop < ft->filename+len && *chop != '.') chop++; if (*chop == '.') { chop++; ft->filetype = strdup(chop); } } else ft->filetype = strdup(filetype); if (!ft->filename || !ft->filetype) goto output_error; if (st_gettype(ft) != ST_SUCCESS) { st_warn("Unknown output file format for '%s': %s", ft->filename, ft->st_errstr); goto output_error; } ft->info.size = -1; ft->info.encoding = -1; ft->info.channels = -1; if (info) ft->info = *info; ft->mode = 'w'; if (!(ft->h->flags & ST_FILE_NOSTDIO)) { /* Open file handler based on input name. Used stdin file handler * if the filename is "-" */ if (!strcmp(ft->filename, "-")) { ft->fp = stdout; } else if ((ft->fp = fopen(ft->filename, "wb")) == NULL) { st_warn("Can't open output file '%s': %s", ft->filename, strerror(errno)); goto output_error; } /* stdout tends to be line-buffered. Override this */ /* to be Full Buffering. */ /* FIXME: Use buffer size from ft structure */ if (setvbuf (ft->fp, NULL, _IOFBF, sizeof(char)*ST_BUFSIZ)) { st_warn("Can't set write buffer"); goto output_error; } /* See if this file is seekable or not */ ft->seekable = is_seekable(ft); } if (ft->comment == NULL && comment != NULL) ft->comment = strdup(comment); else ft->comment = strdup("Processed by SoX"); if (loops) { for (i = 0; i < ST_MAX_NLOOPS; i++) { ft->loops[i] = loops[i]; } } /* leave SMPTE # alone since it's absolute */ if (instr) ft->instr = *instr; /* FIXME: Remove ft->swap from code */ ft->swap = ft->info.swap; /* Read and write starters can change their formats. */ if ((*ft->h->startwrite)(ft) != ST_SUCCESS) { st_warn("Failed writing %s: %s", ft->filename, ft->st_errstr); goto output_error; } if (st_checkformat(ft) ) { st_fail("bad output format for file %s: %s", ft->filename, ft->st_errstr); goto output_error; } return ft; output_error: if (ft->filename) free(ft->filename); if (ft->filetype) free(ft->filetype); free(ft); return NULL; }