/* This file was written by Bill Cox in 2010, and is licensed under the Apache 2.0 license. This file is meant as a simple example for how to use libsonic. It is also a useful utility on its own, which can speed up or slow down wav files, change pitch, and scale volume. */ #include #include #include #include "sonic.h" #include "wave.h" #define BUFFER_SIZE 2048 /* Run sonic. */ static void runSonic(char* inFileName, char* outFileName, float speed, float pitch, float rate, float volume, int outputSampleRate, int emulateChordPitch, int quality, int computeSpectrogram, int numRows, int numCols) { waveFile inFile, outFile = NULL; sonicStream stream; short inBuffer[BUFFER_SIZE], outBuffer[BUFFER_SIZE]; int sampleRate, numChannels, samplesRead, samplesWritten; inFile = openInputWaveFile(inFileName, &sampleRate, &numChannels); if (outputSampleRate != 0) { sampleRate = outputSampleRate; } if (inFile == NULL) { fprintf(stderr, "Unable to read wave file %s\n", inFileName); exit(1); } if (!computeSpectrogram) { outFile = openOutputWaveFile(outFileName, sampleRate, numChannels); if (outFile == NULL) { closeWaveFile(inFile); fprintf(stderr, "Unable to open wave file %s for writing\n", outFileName); exit(1); } } stream = sonicCreateStream(sampleRate, numChannels); sonicSetSpeed(stream, speed); sonicSetPitch(stream, pitch); sonicSetRate(stream, rate); sonicSetVolume(stream, volume); sonicSetChordPitch(stream, emulateChordPitch); sonicSetQuality(stream, quality); #ifdef SONIC_SPECTROGRAM if (computeSpectrogram) { sonicComputeSpectrogram(stream); } #endif /* SONIC_SPECTROGRAM */ do { samplesRead = readFromWaveFile(inFile, inBuffer, BUFFER_SIZE / numChannels); if (samplesRead == 0) { sonicFlushStream(stream); } else { sonicWriteShortToStream(stream, inBuffer, samplesRead); } if (!computeSpectrogram) { do { samplesWritten = sonicReadShortFromStream(stream, outBuffer, BUFFER_SIZE / numChannels); if (samplesWritten > 0 && !computeSpectrogram) { writeToWaveFile(outFile, outBuffer, samplesWritten); } } while (samplesWritten > 0); } } while (samplesRead > 0); #ifdef SONIC_SPECTROGRAM if (computeSpectrogram) { sonicSpectrogram spectrogram = sonicGetSpectrogram(stream); sonicBitmap bitmap = sonicConvertSpectrogramToBitmap(spectrogram, numRows, numCols); sonicWritePGM(bitmap, outFileName); sonicDestroyBitmap(bitmap); } #endif /* SONIC_SPECTROGRAM */ sonicDestroyStream(stream); closeWaveFile(inFile); if (!computeSpectrogram) { closeWaveFile(outFile); } } /* Print the usage. */ static void usage(void) { fprintf( stderr, "Usage: sonic [OPTION]... infile outfile\n" " -c -- Modify pitch by emulating vocal chords vibrating\n" " faster or slower.\n" " -o -- Override the sample rate of the output. -o 44200\n" " on an input file at 22100 KHz will play twice as fast\n" " and have twice the pitch.\n" " -p pitch -- Set pitch scaling factor. 1.3 means 30%% higher.\n" " -q -- Disable speed-up heuristics. May increase quality.\n" " -r rate -- Set playback rate. 2.0 means 2X faster, and 2X " "pitch.\n" " -s speed -- Set speed up factor. 2.0 means 2X faster.\n" #ifdef SONIC_SPECTROGRAM " -S width height -- Write a spectrogram in outfile in PGM format.\n" #endif /* SONIC_SPECTROGRAM */ " -v volume -- Scale volume by a constant factor.\n"); exit(1); } int main(int argc, char** argv) { char* inFileName; char* outFileName; float speed = 1.0f; float pitch = 1.0f; float rate = 1.0f; float volume = 1.0f; int outputSampleRate = 0; /* Means use the input file sample rate. */ int emulateChordPitch = 0; int quality = 0; int xArg = 1; int computeSpectrogram = 0; int numRows = 0, numCols = 0; while (xArg < argc && *(argv[xArg]) == '-') { if (!strcmp(argv[xArg], "-c")) { emulateChordPitch = 1; printf("Scaling pitch linearly.\n"); } else if (!strcmp(argv[xArg], "-o")) { xArg++; if (xArg < argc) { outputSampleRate = atoi(argv[xArg]); printf("Setting output sample rate to %d\n", outputSampleRate); } } else if (!strcmp(argv[xArg], "-p")) { xArg++; if (xArg < argc) { pitch = atof(argv[xArg]); printf("Setting pitch to %0.2fX\n", pitch); } } else if (!strcmp(argv[xArg], "-q")) { quality = 1; printf("Disabling speed-up heuristics\n"); } else if (!strcmp(argv[xArg], "-r")) { xArg++; if (xArg < argc) { rate = atof(argv[xArg]); if (rate == 0.0f) { usage(); } printf("Setting rate to %0.2fX\n", rate); } } else if (!strcmp(argv[xArg], "-s")) { xArg++; if (xArg < argc) { speed = atof(argv[xArg]); printf("Setting speed to %0.2fX\n", speed); } #ifdef SONIC_SPECTROGRAM } else if (!strcmp(argv[xArg], "-S")) { xArg++; if (xArg < argc) { numCols = atof(argv[xArg]); } xArg++; if (xArg < argc) { numRows = atof(argv[xArg]); computeSpectrogram = 1; printf("Computing spectrogram %d wide and %d tall\n", numCols, numRows); } #endif /* SONIC_SPECTROGRAM */ } else if (!strcmp(argv[xArg], "-v")) { xArg++; if (xArg < argc) { volume = atof(argv[xArg]); printf("Setting volume to %0.2f\n", volume); } } xArg++; } if (argc - xArg != 2) { usage(); } inFileName = argv[xArg]; outFileName = argv[xArg + 1]; runSonic(inFileName, outFileName, speed, pitch, rate, volume, outputSampleRate, emulateChordPitch, quality, computeSpectrogram, numRows, numCols); return 0; }