int main(int argc, char** argv) { if (argc != 1) { fprintf(stderr, "usage: %s < input_file\n", argv[0]); exit(1); } const int in_channels = 2, in_samples = 512, sample_rate = 44100; if (sox_init() != SOX_SUCCESS) { oops("sox_init()"); } sox_signalinfo_t out_si = {}; out_si.rate = sample_rate; out_si.channels = in_channels; out_si.precision = SOX_SAMPLE_PRECISION; sox_format_t* output = sox_open_write("default", &out_si, NULL, "alsa", NULL, NULL); if (!output) { oops("sox_open_read()"); } sox_sample_t samples[in_samples * in_channels]; float input[in_samples * in_channels]; size_t clips = 0; SOX_SAMPLE_LOCALS; for (;;) { ssize_t sz = read(STDIN_FILENO, input, sizeof(input)); if (sz < 0) { oops("read(stdin)"); } if (sz == 0) { break; } const size_t n_samples = sz / sizeof(float); for (size_t n = 0; n < n_samples; n++) { samples[n] = SOX_FLOAT_32BIT_TO_SAMPLE(input[n], clips); } if (sox_write(output, samples, n_samples) != n_samples) { oops("sox_write()"); } } if (sox_close(output) != SOX_SUCCESS) { oops("sox_close()"); } if (sox_quit() != SOX_SUCCESS) { oops("sox_quit()"); } return 0; }
static int flow(sox_effect_t * effp, const sox_sample_t * ibuf, sox_sample_t * obuf, size_t * isamp, size_t * osamp) { priv_t *p = (priv_t *) effp->priv; size_t i, len = *isamp = *osamp = min(*isamp, *osamp); double magn, phase, tmp, window, real, imag; double freqPerBin, expct; long k, qpd, index, inFifoLatency, stepSize, fftFrameSize2; float pitchShift = p->shift; /* set up some handy variables */ fftFrameSize2 = p->fftFrameSize / 2; stepSize = p->fftFrameSize / p->ovsamp; freqPerBin = effp->in_signal.rate / p->fftFrameSize; expct = 2. * M_PI * (double) stepSize / (double) p->fftFrameSize; inFifoLatency = p->fftFrameSize - stepSize; if (!p->gRover) p->gRover = inFifoLatency; /* main processing loop */ for (i = 0; i < len; i++) { SOX_SAMPLE_LOCALS; ++p->in_pos; /* As long as we have not yet collected enough data just read in */ p->gInFIFO[p->gRover] = SOX_SAMPLE_TO_FLOAT_32BIT(ibuf[i], effp->clips); obuf[i] = SOX_FLOAT_32BIT_TO_SAMPLE( p->gOutFIFO[p->gRover - inFifoLatency], effp->clips); p->gRover++; /* now we have enough data for processing */ if (p->gRover >= p->fftFrameSize) { if (p->bends_pos != p->nbends && p->in_pos >= p->bends[p->bends_pos].start + p->bends[p->bends_pos].duration) { pitchShift = p->shift *= pow(2., p->bends[p->bends_pos].cents / 1200); ++p->bends_pos; } if (p->bends_pos != p->nbends && p->in_pos >= p->bends[p->bends_pos].start) { double progress = (double)(p->in_pos - p->bends[p->bends_pos].start) / p->bends[p->bends_pos].duration; progress = 1 - cos(M_PI * progress); progress *= p->bends[p->bends_pos].cents * (.5 / 1200); pitchShift = p->shift * pow(2., progress); } p->gRover = inFifoLatency; /* do windowing and re,im interleave */ for (k = 0; k < p->fftFrameSize; k++) { window = -.5 * cos(2 * M_PI * k / (double) p->fftFrameSize) + .5; p->gFFTworksp[2 * k] = p->gInFIFO[k] * window; p->gFFTworksp[2 * k + 1] = 0.; } /* ***************** ANALYSIS ******************* */ lsx_safe_cdft(2 * p->fftFrameSize, 1, p->gFFTworksp); /* this is the analysis step */ for (k = 0; k <= fftFrameSize2; k++) { /* de-interlace FFT buffer */ real = p->gFFTworksp[2 * k]; imag = - p->gFFTworksp[2 * k + 1]; /* compute magnitude and phase */ magn = 2. * sqrt(real * real + imag * imag); phase = atan2(imag, real); /* compute phase difference */ tmp = phase - p->gLastPhase[k]; p->gLastPhase[k] = phase; tmp -= (double) k *expct; /* subtract expected phase difference */ /* map delta phase into +/- Pi interval */ qpd = tmp / M_PI; if (qpd >= 0) qpd += qpd & 1; else qpd -= qpd & 1; tmp -= M_PI * (double) qpd; /* get deviation from bin frequency from the +/- Pi interval */ tmp = p->ovsamp * tmp / (2. * M_PI); /* compute the k-th partials' true frequency */ tmp = (double) k *freqPerBin + tmp * freqPerBin; /* store magnitude and true frequency in analysis arrays */ p->gAnaMagn[k] = magn; p->gAnaFreq[k] = tmp; } /* this does the actual pitch shifting */ memset(p->gSynMagn, 0, p->fftFrameSize * sizeof(float)); memset(p->gSynFreq, 0, p->fftFrameSize * sizeof(float)); for (k = 0; k <= fftFrameSize2; k++) { index = k * pitchShift; if (index <= fftFrameSize2) { p->gSynMagn[index] += p->gAnaMagn[k]; p->gSynFreq[index] = p->gAnaFreq[k] * pitchShift; } } for (k = 0; k <= fftFrameSize2; k++) { /* SYNTHESIS */ /* get magnitude and true frequency from synthesis arrays */ magn = p->gSynMagn[k], tmp = p->gSynFreq[k]; tmp -= (double) k *freqPerBin; /* subtract bin mid frequency */ tmp /= freqPerBin; /* get bin deviation from freq deviation */ tmp = 2. * M_PI * tmp / p->ovsamp; /* take p->ovsamp into account */ tmp += (double) k *expct; /* add the overlap phase advance back in */ p->gSumPhase[k] += tmp; /* accumulate delta phase to get bin phase */ phase = p->gSumPhase[k]; /* get real and imag part and re-interleave */ p->gFFTworksp[2 * k] = magn * cos(phase); p->gFFTworksp[2 * k + 1] = - magn * sin(phase); } for (k = p->fftFrameSize + 2; k < 2 * p->fftFrameSize; k++) p->gFFTworksp[k] = 0.; /* zero negative frequencies */ lsx_safe_cdft(2 * p->fftFrameSize, -1, p->gFFTworksp); /* do windowing and add to output accumulator */ for (k = 0; k < p->fftFrameSize; k++) { window = -.5 * cos(2. * M_PI * (double) k / (double) p->fftFrameSize) + .5; p->gOutputAccum[k] += 2. * window * p->gFFTworksp[2 * k] / (fftFrameSize2 * p->ovsamp); } for (k = 0; k < stepSize; k++) p->gOutFIFO[k] = p->gOutputAccum[k]; memmove(p->gOutputAccum, /* shift accumulator */ p->gOutputAccum + stepSize, p->fftFrameSize * sizeof(float)); for (k = 0; k < inFifoLatency; k++) /* move input FIFO */ p->gInFIFO[k] = p->gInFIFO[k + stepSize]; } } return SOX_SUCCESS; }