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