xref: /aosp_15_r20/external/sonic/main.c (revision b290403dc9d28f89f133eb7e190ea8185d440ecd)
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