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