| /********************************************************************** |
| |
| resample-sndfile.c |
| |
| Written by Dominic Mazzoni |
| |
| Based on resample-1.7: |
| http://www-ccrma.stanford.edu/~jos/resample/ |
| |
| License: LGPL - see the file LICENSE.txt for more information |
| |
| **********************************************************************/ |
| |
| #include "../include/libresample.h" |
| |
| #include <sndfile.h> |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <math.h> |
| |
| #include <sys/time.h> |
| |
| #define MIN(A, B) (A) < (B)? (A) : (B) |
| |
| void usage(char *progname) |
| { |
| fprintf(stderr, "Usage: %s -by <ratio> <input> <output>\n", progname); |
| fprintf(stderr, " %s -to <rate> <input> <output>\n", progname); |
| fprintf(stderr, "\n"); |
| exit(-1); |
| } |
| |
| int main(int argc, char **argv) |
| { |
| SNDFILE *srcfile, *dstfile; |
| SF_INFO srcinfo, dstinfo; |
| SF_FORMAT_INFO formatinfo; |
| char *extension; |
| void **handle; |
| int channels; |
| int srclen, dstlen; |
| float *src, *srci; |
| float *dst, *dsti; |
| double ratio = 0.0; |
| double srcrate; |
| double dstrate = 0.0; |
| struct timeval tv0, tv1; |
| double deltat; |
| int numformats; |
| int pos, bufferpos, outcount; |
| int i, c; |
| |
| if (argc != 5) |
| usage(argv[0]); |
| |
| if (!strcmp(argv[1], "-by")) { |
| ratio = atof(argv[2]); |
| if (ratio <= 0.0) { |
| fprintf(stderr, "Ratio of %f is illegal\n", ratio); |
| usage(argv[0]); |
| } |
| } |
| else if (!strcmp(argv[1], "-to")) { |
| dstrate = atof(argv[2]); |
| if (dstrate < 10.0 || dstrate > 100000.0) { |
| fprintf(stderr, "Sample rate of %f is illegal\n", dstrate); |
| usage(argv[0]); |
| } |
| } |
| else |
| usage(argv[0]); |
| |
| memset(&srcinfo, 0, sizeof(srcinfo)); |
| memset(&dstinfo, 0, sizeof(dstinfo)); |
| srcfile = sf_open(argv[3], SFM_READ, &srcinfo); |
| if (!srcfile) { |
| fprintf(stderr, "%s", sf_strerror(NULL)); |
| exit(-1); |
| } |
| |
| srcrate = srcinfo.samplerate; |
| if (dstrate == 0.0) |
| dstrate = srcrate * ratio; |
| else |
| ratio = dstrate / srcrate; |
| |
| channels = srcinfo.channels; |
| |
| /* figure out format of destination file */ |
| |
| extension = strstr(argv[4], "."); |
| if (extension) { |
| extension++; |
| sf_command(NULL, SFC_GET_FORMAT_MAJOR_COUNT, |
| &numformats, sizeof(numformats)); |
| for(i=0; i<numformats; i++) { |
| memset(&formatinfo, 0, sizeof(formatinfo)); |
| formatinfo.format = i; |
| sf_command(NULL, SFC_GET_FORMAT_MAJOR, |
| &formatinfo, sizeof(formatinfo)); |
| if (!strcmp(formatinfo.extension, extension)) { |
| printf("Using %s for output format.\n", formatinfo.name); |
| dstinfo.format = formatinfo.format | |
| (srcinfo.format & SF_FORMAT_SUBMASK); |
| break; |
| } |
| } |
| } |
| |
| if (!dstinfo.format) { |
| if (extension) |
| printf("Warning: output format (%s) not recognized, " |
| "using same as input format.\n", |
| extension); |
| dstinfo.format = srcinfo.format; |
| } |
| |
| dstinfo.samplerate = (int)(dstrate + 0.5); |
| dstinfo.channels = channels; |
| |
| dstfile = sf_open(argv[4], SFM_WRITE, &dstinfo); |
| if (!dstfile) { |
| fprintf(stderr, "%s", sf_strerror(NULL)); |
| exit(-1); |
| } |
| |
| printf("Source: %s (%d frames, %.2f Hz)\n", |
| argv[3], (int)srcinfo.frames, srcrate); |
| printf("Destination: %s (%.2f Hz, ratio=%.5f)\n", argv[4], |
| dstrate, ratio); |
| |
| srclen = 4096; |
| dstlen = (srclen * ratio + 1000); |
| srci = (float *)malloc(srclen * channels * sizeof(float)); |
| dsti = (float *)malloc(dstlen * channels * sizeof(float)); |
| src = (float *)malloc(srclen * sizeof(float)); |
| dst = (float *)malloc(dstlen * sizeof(float)); |
| |
| handle = (void **)malloc(channels * sizeof(void *)); |
| for(c=0; c<channels; c++) |
| handle[c] = resample_open(1, ratio, ratio); |
| |
| gettimeofday(&tv0, NULL); |
| |
| pos = 0; |
| bufferpos = 0; |
| outcount = 0; |
| while(pos < srcinfo.frames) { |
| int block = MIN(srclen-bufferpos, srcinfo.frames-pos); |
| int lastFlag = (pos+block == srcinfo.frames); |
| int inUsed, inUsed2=0, out=0, out2=0; |
| |
| sf_readf_float(srcfile, &srci[bufferpos*channels], block); |
| block += bufferpos; |
| |
| for(c=0; c<channels; c++) { |
| for(i=0; i<block; i++) |
| src[i] = srci[i*channels+c]; |
| |
| inUsed = 0; |
| out = resample_process(handle[c], ratio, src, block, lastFlag, |
| &inUsed, dst, dstlen); |
| if (c==0) { |
| inUsed2 = inUsed; |
| out2 = out; |
| } |
| else { |
| if (inUsed2 != inUsed || out2 != out) { |
| fprintf(stderr, "Fatal error: channels out of sync!\n"); |
| exit(-1); |
| } |
| } |
| |
| for(i=0; i<out; i++) |
| { |
| if(dst[i] <= -1) |
| dsti[i*channels+c] = -1; |
| else if(dst[i] >= 1) |
| dsti[i*channels+c] = 1; |
| else |
| dsti[i*channels+c] = dst[i]; |
| } |
| } |
| |
| sf_writef_float(dstfile, dsti, out); |
| |
| bufferpos = block - inUsed; |
| for(i=0; i<bufferpos*channels; i++) |
| srci[i] = srci[i+(inUsed*channels)]; |
| pos += inUsed; |
| outcount += out; |
| } |
| |
| sf_close(srcfile); |
| sf_close(dstfile); |
| |
| gettimeofday(&tv1, NULL); |
| deltat = |
| (tv1.tv_sec + tv1.tv_usec * 0.000001) - |
| (tv0.tv_sec + tv0.tv_usec * 0.000001); |
| |
| printf("Elapsed time: %.3f seconds\n", deltat); |
| printf("%d frames written to output file\n", outcount); |
| |
| free(src); |
| free(srci); |
| free(dst); |
| free(dsti); |
| |
| exit(0); |
| } |