1*b290403dSRicardo Garcia /* This file was written by Bill Cox in 2010, and is licensed under the Apache
2*b290403dSRicardo Garcia 2.0 license.
3*b290403dSRicardo Garcia
4*b290403dSRicardo Garcia This file is meant as a simple example for how to use libsonic. It is also a
5*b290403dSRicardo Garcia useful utility on its own, which can speed up or slow down wav files, change
6*b290403dSRicardo Garcia pitch, and scale volume. */
7*b290403dSRicardo Garcia
8*b290403dSRicardo Garcia #include <stdio.h>
9*b290403dSRicardo Garcia #include <stdlib.h>
10*b290403dSRicardo Garcia #include <string.h>
11*b290403dSRicardo Garcia #include "sonic.h"
12*b290403dSRicardo Garcia #include "wave.h"
13*b290403dSRicardo Garcia
14*b290403dSRicardo Garcia #define BUFFER_SIZE 2048
15*b290403dSRicardo Garcia
16*b290403dSRicardo Garcia /* Run sonic. */
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)17*b290403dSRicardo Garcia static void runSonic(char* inFileName, char* outFileName, float speed,
18*b290403dSRicardo Garcia float pitch, float rate, float volume, int outputSampleRate,
19*b290403dSRicardo Garcia int emulateChordPitch, int quality, int computeSpectrogram,
20*b290403dSRicardo Garcia int numRows, int numCols) {
21*b290403dSRicardo Garcia waveFile inFile, outFile = NULL;
22*b290403dSRicardo Garcia sonicStream stream;
23*b290403dSRicardo Garcia short inBuffer[BUFFER_SIZE], outBuffer[BUFFER_SIZE];
24*b290403dSRicardo Garcia int sampleRate, numChannels, samplesRead, samplesWritten;
25*b290403dSRicardo Garcia
26*b290403dSRicardo Garcia inFile = openInputWaveFile(inFileName, &sampleRate, &numChannels);
27*b290403dSRicardo Garcia if (outputSampleRate != 0) {
28*b290403dSRicardo Garcia sampleRate = outputSampleRate;
29*b290403dSRicardo Garcia }
30*b290403dSRicardo Garcia if (inFile == NULL) {
31*b290403dSRicardo Garcia fprintf(stderr, "Unable to read wave file %s\n", inFileName);
32*b290403dSRicardo Garcia exit(1);
33*b290403dSRicardo Garcia }
34*b290403dSRicardo Garcia if (!computeSpectrogram) {
35*b290403dSRicardo Garcia outFile = openOutputWaveFile(outFileName, sampleRate, numChannels);
36*b290403dSRicardo Garcia if (outFile == NULL) {
37*b290403dSRicardo Garcia closeWaveFile(inFile);
38*b290403dSRicardo Garcia fprintf(stderr, "Unable to open wave file %s for writing\n", outFileName);
39*b290403dSRicardo Garcia exit(1);
40*b290403dSRicardo Garcia }
41*b290403dSRicardo Garcia }
42*b290403dSRicardo Garcia stream = sonicCreateStream(sampleRate, numChannels);
43*b290403dSRicardo Garcia sonicSetSpeed(stream, speed);
44*b290403dSRicardo Garcia sonicSetPitch(stream, pitch);
45*b290403dSRicardo Garcia sonicSetRate(stream, rate);
46*b290403dSRicardo Garcia sonicSetVolume(stream, volume);
47*b290403dSRicardo Garcia sonicSetChordPitch(stream, emulateChordPitch);
48*b290403dSRicardo Garcia sonicSetQuality(stream, quality);
49*b290403dSRicardo Garcia #ifdef SONIC_SPECTROGRAM
50*b290403dSRicardo Garcia if (computeSpectrogram) {
51*b290403dSRicardo Garcia sonicComputeSpectrogram(stream);
52*b290403dSRicardo Garcia }
53*b290403dSRicardo Garcia #endif /* SONIC_SPECTROGRAM */
54*b290403dSRicardo Garcia do {
55*b290403dSRicardo Garcia samplesRead = readFromWaveFile(inFile, inBuffer, BUFFER_SIZE / numChannels);
56*b290403dSRicardo Garcia if (samplesRead == 0) {
57*b290403dSRicardo Garcia sonicFlushStream(stream);
58*b290403dSRicardo Garcia } else {
59*b290403dSRicardo Garcia sonicWriteShortToStream(stream, inBuffer, samplesRead);
60*b290403dSRicardo Garcia }
61*b290403dSRicardo Garcia if (!computeSpectrogram) {
62*b290403dSRicardo Garcia do {
63*b290403dSRicardo Garcia samplesWritten = sonicReadShortFromStream(stream, outBuffer,
64*b290403dSRicardo Garcia BUFFER_SIZE / numChannels);
65*b290403dSRicardo Garcia if (samplesWritten > 0 && !computeSpectrogram) {
66*b290403dSRicardo Garcia writeToWaveFile(outFile, outBuffer, samplesWritten);
67*b290403dSRicardo Garcia }
68*b290403dSRicardo Garcia } while (samplesWritten > 0);
69*b290403dSRicardo Garcia }
70*b290403dSRicardo Garcia } while (samplesRead > 0);
71*b290403dSRicardo Garcia #ifdef SONIC_SPECTROGRAM
72*b290403dSRicardo Garcia if (computeSpectrogram) {
73*b290403dSRicardo Garcia sonicSpectrogram spectrogram = sonicGetSpectrogram(stream);
74*b290403dSRicardo Garcia sonicBitmap bitmap =
75*b290403dSRicardo Garcia sonicConvertSpectrogramToBitmap(spectrogram, numRows, numCols);
76*b290403dSRicardo Garcia sonicWritePGM(bitmap, outFileName);
77*b290403dSRicardo Garcia sonicDestroyBitmap(bitmap);
78*b290403dSRicardo Garcia }
79*b290403dSRicardo Garcia #endif /* SONIC_SPECTROGRAM */
80*b290403dSRicardo Garcia sonicDestroyStream(stream);
81*b290403dSRicardo Garcia closeWaveFile(inFile);
82*b290403dSRicardo Garcia if (!computeSpectrogram) {
83*b290403dSRicardo Garcia closeWaveFile(outFile);
84*b290403dSRicardo Garcia }
85*b290403dSRicardo Garcia }
86*b290403dSRicardo Garcia
87*b290403dSRicardo Garcia /* Print the usage. */
usage(void)88*b290403dSRicardo Garcia static void usage(void) {
89*b290403dSRicardo Garcia fprintf(
90*b290403dSRicardo Garcia stderr,
91*b290403dSRicardo Garcia "Usage: sonic [OPTION]... infile outfile\n"
92*b290403dSRicardo Garcia " -c -- Modify pitch by emulating vocal chords vibrating\n"
93*b290403dSRicardo Garcia " faster or slower.\n"
94*b290403dSRicardo Garcia " -o -- Override the sample rate of the output. -o 44200\n"
95*b290403dSRicardo Garcia " on an input file at 22100 KHz will play twice as fast\n"
96*b290403dSRicardo Garcia " and have twice the pitch.\n"
97*b290403dSRicardo Garcia " -p pitch -- Set pitch scaling factor. 1.3 means 30%% higher.\n"
98*b290403dSRicardo Garcia " -q -- Disable speed-up heuristics. May increase quality.\n"
99*b290403dSRicardo Garcia " -r rate -- Set playback rate. 2.0 means 2X faster, and 2X "
100*b290403dSRicardo Garcia "pitch.\n"
101*b290403dSRicardo Garcia " -s speed -- Set speed up factor. 2.0 means 2X faster.\n"
102*b290403dSRicardo Garcia #ifdef SONIC_SPECTROGRAM
103*b290403dSRicardo Garcia " -S width height -- Write a spectrogram in outfile in PGM format.\n"
104*b290403dSRicardo Garcia #endif /* SONIC_SPECTROGRAM */
105*b290403dSRicardo Garcia " -v volume -- Scale volume by a constant factor.\n");
106*b290403dSRicardo Garcia exit(1);
107*b290403dSRicardo Garcia }
108*b290403dSRicardo Garcia
main(int argc,char ** argv)109*b290403dSRicardo Garcia int main(int argc, char** argv) {
110*b290403dSRicardo Garcia char* inFileName;
111*b290403dSRicardo Garcia char* outFileName;
112*b290403dSRicardo Garcia float speed = 1.0f;
113*b290403dSRicardo Garcia float pitch = 1.0f;
114*b290403dSRicardo Garcia float rate = 1.0f;
115*b290403dSRicardo Garcia float volume = 1.0f;
116*b290403dSRicardo Garcia int outputSampleRate = 0; /* Means use the input file sample rate. */
117*b290403dSRicardo Garcia int emulateChordPitch = 0;
118*b290403dSRicardo Garcia int quality = 0;
119*b290403dSRicardo Garcia int xArg = 1;
120*b290403dSRicardo Garcia int computeSpectrogram = 0;
121*b290403dSRicardo Garcia int numRows = 0, numCols = 0;
122*b290403dSRicardo Garcia
123*b290403dSRicardo Garcia while (xArg < argc && *(argv[xArg]) == '-') {
124*b290403dSRicardo Garcia if (!strcmp(argv[xArg], "-c")) {
125*b290403dSRicardo Garcia emulateChordPitch = 1;
126*b290403dSRicardo Garcia printf("Scaling pitch linearly.\n");
127*b290403dSRicardo Garcia } else if (!strcmp(argv[xArg], "-o")) {
128*b290403dSRicardo Garcia xArg++;
129*b290403dSRicardo Garcia if (xArg < argc) {
130*b290403dSRicardo Garcia outputSampleRate = atoi(argv[xArg]);
131*b290403dSRicardo Garcia printf("Setting output sample rate to %d\n", outputSampleRate);
132*b290403dSRicardo Garcia }
133*b290403dSRicardo Garcia } else if (!strcmp(argv[xArg], "-p")) {
134*b290403dSRicardo Garcia xArg++;
135*b290403dSRicardo Garcia if (xArg < argc) {
136*b290403dSRicardo Garcia pitch = atof(argv[xArg]);
137*b290403dSRicardo Garcia printf("Setting pitch to %0.2fX\n", pitch);
138*b290403dSRicardo Garcia }
139*b290403dSRicardo Garcia } else if (!strcmp(argv[xArg], "-q")) {
140*b290403dSRicardo Garcia quality = 1;
141*b290403dSRicardo Garcia printf("Disabling speed-up heuristics\n");
142*b290403dSRicardo Garcia } else if (!strcmp(argv[xArg], "-r")) {
143*b290403dSRicardo Garcia xArg++;
144*b290403dSRicardo Garcia if (xArg < argc) {
145*b290403dSRicardo Garcia rate = atof(argv[xArg]);
146*b290403dSRicardo Garcia if (rate == 0.0f) {
147*b290403dSRicardo Garcia usage();
148*b290403dSRicardo Garcia }
149*b290403dSRicardo Garcia printf("Setting rate to %0.2fX\n", rate);
150*b290403dSRicardo Garcia }
151*b290403dSRicardo Garcia } else if (!strcmp(argv[xArg], "-s")) {
152*b290403dSRicardo Garcia xArg++;
153*b290403dSRicardo Garcia if (xArg < argc) {
154*b290403dSRicardo Garcia speed = atof(argv[xArg]);
155*b290403dSRicardo Garcia printf("Setting speed to %0.2fX\n", speed);
156*b290403dSRicardo Garcia }
157*b290403dSRicardo Garcia #ifdef SONIC_SPECTROGRAM
158*b290403dSRicardo Garcia } else if (!strcmp(argv[xArg], "-S")) {
159*b290403dSRicardo Garcia xArg++;
160*b290403dSRicardo Garcia if (xArg < argc) {
161*b290403dSRicardo Garcia numCols = atof(argv[xArg]);
162*b290403dSRicardo Garcia }
163*b290403dSRicardo Garcia xArg++;
164*b290403dSRicardo Garcia if (xArg < argc) {
165*b290403dSRicardo Garcia numRows = atof(argv[xArg]);
166*b290403dSRicardo Garcia computeSpectrogram = 1;
167*b290403dSRicardo Garcia printf("Computing spectrogram %d wide and %d tall\n", numCols, numRows);
168*b290403dSRicardo Garcia }
169*b290403dSRicardo Garcia #endif /* SONIC_SPECTROGRAM */
170*b290403dSRicardo Garcia } else if (!strcmp(argv[xArg], "-v")) {
171*b290403dSRicardo Garcia xArg++;
172*b290403dSRicardo Garcia if (xArg < argc) {
173*b290403dSRicardo Garcia volume = atof(argv[xArg]);
174*b290403dSRicardo Garcia printf("Setting volume to %0.2f\n", volume);
175*b290403dSRicardo Garcia }
176*b290403dSRicardo Garcia }
177*b290403dSRicardo Garcia xArg++;
178*b290403dSRicardo Garcia }
179*b290403dSRicardo Garcia if (argc - xArg != 2) {
180*b290403dSRicardo Garcia usage();
181*b290403dSRicardo Garcia }
182*b290403dSRicardo Garcia inFileName = argv[xArg];
183*b290403dSRicardo Garcia outFileName = argv[xArg + 1];
184*b290403dSRicardo Garcia runSonic(inFileName, outFileName, speed, pitch, rate, volume,
185*b290403dSRicardo Garcia outputSampleRate, emulateChordPitch, quality,
186*b290403dSRicardo Garcia computeSpectrogram, numRows, numCols);
187*b290403dSRicardo Garcia return 0;
188*b290403dSRicardo Garcia }
189