160eeb064f62a106069d2ce148fabd724f9df9780Bill Cox/* This file was written by Bill Cox in 2010, and is licensed under the Apache
260eeb064f62a106069d2ce148fabd724f9df9780Bill Cox   2.0 license.
3ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox
49d1402171689d5b13869fe3f9d8ef753996a6fb5Bill Cox   This file is meant as a simple example for how to use libsonic.  It is also a
59d1402171689d5b13869fe3f9d8ef753996a6fb5Bill Cox   useful utility on it's own, which can speed up or slow down wav files, change
69d1402171689d5b13869fe3f9d8ef753996a6fb5Bill Cox   pitch, and scale volume. */
7ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox
8ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox#include <stdio.h>
9ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox#include <stdlib.h>
100e4ec5e65f696f6648feeeace9adc77dd69e2532Bill Cox#include <string.h>
11ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox#include "sonic.h"
12ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox#include "wave.h"
13ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox
141a299bb54901f02ef8cd0d9f3774e2a67b85e938Bill Cox#define BUFFER_SIZE 2048
15ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox
16ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox/* Run sonic. */
17ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Coxstatic void runSonic(
180c4cade6939162c0700dd5d701bf91095bcc9eddBill Cox    waveFile inFile,
190c4cade6939162c0700dd5d701bf91095bcc9eddBill Cox    waveFile outFile,
20d544fdb83eee1360eedfdcbd1e24a983403bb314Bill Cox    float speed,
21d544fdb83eee1360eedfdcbd1e24a983403bb314Bill Cox    float pitch,
223276bb0eab2af227631cd376d649ff6766b9291fBill Cox    float rate,
23d544fdb83eee1360eedfdcbd1e24a983403bb314Bill Cox    float volume,
243276bb0eab2af227631cd376d649ff6766b9291fBill Cox    int emulateChordPitch,
25c978c39e1abbdf7bd650a4a74d5936fd0d2b0f0dBill Cox    int quality,
261a299bb54901f02ef8cd0d9f3774e2a67b85e938Bill Cox    int sampleRate,
271a299bb54901f02ef8cd0d9f3774e2a67b85e938Bill Cox    int numChannels)
28ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox{
29d544fdb83eee1360eedfdcbd1e24a983403bb314Bill Cox    sonicStream stream = sonicCreateStream(sampleRate, numChannels);
300c4c06089176345f408613c8da6a5585a9af9615Bill Cox    short inBuffer[BUFFER_SIZE], outBuffer[BUFFER_SIZE];
310c4cade6939162c0700dd5d701bf91095bcc9eddBill Cox    int samplesRead, samplesWritten;
32ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox
33d544fdb83eee1360eedfdcbd1e24a983403bb314Bill Cox    sonicSetSpeed(stream, speed);
34d544fdb83eee1360eedfdcbd1e24a983403bb314Bill Cox    sonicSetPitch(stream, pitch);
353276bb0eab2af227631cd376d649ff6766b9291fBill Cox    sonicSetRate(stream, rate);
36d544fdb83eee1360eedfdcbd1e24a983403bb314Bill Cox    sonicSetVolume(stream, volume);
373276bb0eab2af227631cd376d649ff6766b9291fBill Cox    sonicSetChordPitch(stream, emulateChordPitch);
38c978c39e1abbdf7bd650a4a74d5936fd0d2b0f0dBill Cox    sonicSetQuality(stream, quality);
390c4cade6939162c0700dd5d701bf91095bcc9eddBill Cox    do {
401a299bb54901f02ef8cd0d9f3774e2a67b85e938Bill Cox        samplesRead = readFromWaveFile(inFile, inBuffer, BUFFER_SIZE/numChannels);
410c4cade6939162c0700dd5d701bf91095bcc9eddBill Cox	if(samplesRead == 0) {
42ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox	    sonicFlushStream(stream);
430c4cade6939162c0700dd5d701bf91095bcc9eddBill Cox	} else {
440c4cade6939162c0700dd5d701bf91095bcc9eddBill Cox	    sonicWriteShortToStream(stream, inBuffer, samplesRead);
45ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox	}
46882fb1db2700b48a33c11783635e936780199840Bill Cox	do {
471a299bb54901f02ef8cd0d9f3774e2a67b85e938Bill Cox	    samplesWritten = sonicReadShortFromStream(stream, outBuffer,
481a299bb54901f02ef8cd0d9f3774e2a67b85e938Bill Cox	        BUFFER_SIZE/numChannels);
490c4cade6939162c0700dd5d701bf91095bcc9eddBill Cox	    if(samplesWritten > 0) {
500c4cade6939162c0700dd5d701bf91095bcc9eddBill Cox		writeToWaveFile(outFile, outBuffer, samplesWritten);
51882fb1db2700b48a33c11783635e936780199840Bill Cox	    }
520c4cade6939162c0700dd5d701bf91095bcc9eddBill Cox	} while(samplesWritten > 0);
530c4cade6939162c0700dd5d701bf91095bcc9eddBill Cox    } while(samplesRead > 0);
540c4cade6939162c0700dd5d701bf91095bcc9eddBill Cox    sonicDestroyStream(stream);
55ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox}
56ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox
57ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox/* Print the usage. */
58ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Coxstatic void usage(void)
59ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox{
60c978c39e1abbdf7bd650a4a74d5936fd0d2b0f0dBill Cox    fprintf(stderr, "Usage: sonic [OPTION]... infile outfile\n"
613276bb0eab2af227631cd376d649ff6766b9291fBill Cox        "    -c         -- Modify pitch by emulating vocal chords vibrating\n"
623276bb0eab2af227631cd376d649ff6766b9291fBill Cox	"                  faster or slower.\n"
63c978c39e1abbdf7bd650a4a74d5936fd0d2b0f0dBill Cox        "    -p pitch   -- Set pitch scaling factor.  1.3 means 30%% higher.\n"
64c978c39e1abbdf7bd650a4a74d5936fd0d2b0f0dBill Cox        "    -q         -- Disable speed-up heuristics.  May increase quality.\n"
653276bb0eab2af227631cd376d649ff6766b9291fBill Cox        "    -r rate    -- Set playback rate.  2.0 means 2X faster, and 2X pitch.\n"
66c978c39e1abbdf7bd650a4a74d5936fd0d2b0f0dBill Cox        "    -s speed   -- Set speed up factor.  2.0 means 2X faster.\n"
67c978c39e1abbdf7bd650a4a74d5936fd0d2b0f0dBill Cox	"    -v volume  -- Scale volume by a constant factor.\n");
683a7abf9306e470963a422881af62811633fede47Bill Cox    exit(1);
69ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox}
70ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox
71ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Coxint main(
72ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox    int argc,
73ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox    char **argv)
74ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox{
750c4cade6939162c0700dd5d701bf91095bcc9eddBill Cox    waveFile inFile, outFile;
76ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox    char *inFileName, *outFileName;
773276bb0eab2af227631cd376d649ff6766b9291fBill Cox    float speed = 1.0f;
783276bb0eab2af227631cd376d649ff6766b9291fBill Cox    float pitch = 1.0f;
793276bb0eab2af227631cd376d649ff6766b9291fBill Cox    float rate = 1.0f;
803276bb0eab2af227631cd376d649ff6766b9291fBill Cox    float volume = 1.0f;
813276bb0eab2af227631cd376d649ff6766b9291fBill Cox    int emulateChordPitch = 0;
82c978c39e1abbdf7bd650a4a74d5936fd0d2b0f0dBill Cox    int quality = 0;
831a299bb54901f02ef8cd0d9f3774e2a67b85e938Bill Cox    int sampleRate, numChannels;
840e4ec5e65f696f6648feeeace9adc77dd69e2532Bill Cox    int xArg = 1;
85ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox
860e4ec5e65f696f6648feeeace9adc77dd69e2532Bill Cox    while(xArg < argc && *(argv[xArg]) == '-') {
873276bb0eab2af227631cd376d649ff6766b9291fBill Cox	if(!strcmp(argv[xArg], "-c")) {
883276bb0eab2af227631cd376d649ff6766b9291fBill Cox	    emulateChordPitch = 1;
893276bb0eab2af227631cd376d649ff6766b9291fBill Cox	    printf("Scaling pitch linearly.\n");
903276bb0eab2af227631cd376d649ff6766b9291fBill Cox	} else if(!strcmp(argv[xArg], "-p")) {
91d544fdb83eee1360eedfdcbd1e24a983403bb314Bill Cox	    xArg++;
92d544fdb83eee1360eedfdcbd1e24a983403bb314Bill Cox	    if(xArg < argc) {
93d544fdb83eee1360eedfdcbd1e24a983403bb314Bill Cox	        pitch = atof(argv[xArg]);
943276bb0eab2af227631cd376d649ff6766b9291fBill Cox                printf("Setting pitch to %0.2fX\n", pitch);
95d544fdb83eee1360eedfdcbd1e24a983403bb314Bill Cox	    }
96c978c39e1abbdf7bd650a4a74d5936fd0d2b0f0dBill Cox	} else if(!strcmp(argv[xArg], "-q")) {
97c978c39e1abbdf7bd650a4a74d5936fd0d2b0f0dBill Cox	    quality = 1;
98c978c39e1abbdf7bd650a4a74d5936fd0d2b0f0dBill Cox	    printf("Disabling speed-up heuristics\n");
993276bb0eab2af227631cd376d649ff6766b9291fBill Cox	} else if(!strcmp(argv[xArg], "-r")) {
1003276bb0eab2af227631cd376d649ff6766b9291fBill Cox	    xArg++;
1013276bb0eab2af227631cd376d649ff6766b9291fBill Cox	    if(xArg < argc) {
1023276bb0eab2af227631cd376d649ff6766b9291fBill Cox	        rate = atof(argv[xArg]);
1033276bb0eab2af227631cd376d649ff6766b9291fBill Cox                printf("Setting rate to %0.2fX\n", rate);
1043276bb0eab2af227631cd376d649ff6766b9291fBill Cox	    }
105d544fdb83eee1360eedfdcbd1e24a983403bb314Bill Cox	} else if(!strcmp(argv[xArg], "-s")) {
1060e4ec5e65f696f6648feeeace9adc77dd69e2532Bill Cox	    xArg++;
1070e4ec5e65f696f6648feeeace9adc77dd69e2532Bill Cox	    if(xArg < argc) {
1080e4ec5e65f696f6648feeeace9adc77dd69e2532Bill Cox	        speed = atof(argv[xArg]);
1093276bb0eab2af227631cd376d649ff6766b9291fBill Cox                printf("Setting speed to %0.2fX\n", speed);
1100e4ec5e65f696f6648feeeace9adc77dd69e2532Bill Cox	    }
1110e4ec5e65f696f6648feeeace9adc77dd69e2532Bill Cox	} else if(!strcmp(argv[xArg], "-v")) {
1120e4ec5e65f696f6648feeeace9adc77dd69e2532Bill Cox	    xArg++;
1130e4ec5e65f696f6648feeeace9adc77dd69e2532Bill Cox	    if(xArg < argc) {
1140e4ec5e65f696f6648feeeace9adc77dd69e2532Bill Cox	        volume = atof(argv[xArg]);
115c978c39e1abbdf7bd650a4a74d5936fd0d2b0f0dBill Cox                printf("Setting volume to %0.2f\n", volume);
1160e4ec5e65f696f6648feeeace9adc77dd69e2532Bill Cox	    }
1170e4ec5e65f696f6648feeeace9adc77dd69e2532Bill Cox	}
1180e4ec5e65f696f6648feeeace9adc77dd69e2532Bill Cox	xArg++;
1190e4ec5e65f696f6648feeeace9adc77dd69e2532Bill Cox    }
120d544fdb83eee1360eedfdcbd1e24a983403bb314Bill Cox    if(argc - xArg != 2) {
121ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox	usage();
122ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox    }
1230e4ec5e65f696f6648feeeace9adc77dd69e2532Bill Cox    inFileName = argv[xArg];
1240e4ec5e65f696f6648feeeace9adc77dd69e2532Bill Cox    outFileName = argv[xArg + 1];
1251a299bb54901f02ef8cd0d9f3774e2a67b85e938Bill Cox    inFile = openInputWaveFile(inFileName, &sampleRate, &numChannels);
1260c4cade6939162c0700dd5d701bf91095bcc9eddBill Cox    if(inFile == NULL) {
1270c4cade6939162c0700dd5d701bf91095bcc9eddBill Cox	return 1;
1280c4cade6939162c0700dd5d701bf91095bcc9eddBill Cox    }
1291a299bb54901f02ef8cd0d9f3774e2a67b85e938Bill Cox    outFile = openOutputWaveFile(outFileName, sampleRate, numChannels);
1300c4cade6939162c0700dd5d701bf91095bcc9eddBill Cox    if(outFile == NULL) {
1310c4cade6939162c0700dd5d701bf91095bcc9eddBill Cox	closeWaveFile(inFile);
1320c4cade6939162c0700dd5d701bf91095bcc9eddBill Cox	return 1;
1330c4cade6939162c0700dd5d701bf91095bcc9eddBill Cox    }
1343276bb0eab2af227631cd376d649ff6766b9291fBill Cox    runSonic(inFile, outFile, speed, pitch, rate, volume, emulateChordPitch, quality,
1353276bb0eab2af227631cd376d649ff6766b9291fBill Cox        sampleRate, numChannels);
1360c4cade6939162c0700dd5d701bf91095bcc9eddBill Cox    closeWaveFile(inFile);
1370c4cade6939162c0700dd5d701bf91095bcc9eddBill Cox    closeWaveFile(outFile);
138ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox    return 0;
139ca02d872cc6cb963d438ceae6d011bd04c658b3Bill Cox}
140