1 /*
2 Audio File Library
3
4 Copyright (C) 1998, 2011-2012, Michael Pruett <michael@68k.org>
5 Copyright (C) 2001, Silicon Graphics, Inc.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License along
18 with this program; if not, write to the Free Software Foundation, Inc.,
19 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 */
21
22 /*
23 sfconvert is a program which can convert various parameters of
24 sound files.
25 */
26
27 #include "config.h"
28
29 #ifdef __USE_SGI_HEADERS__
30 #include <dmedia/audiofile.h>
31 #else
32 #include <audiofile.h>
33 #endif
34
35 #include <stdbool.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <unistd.h>
40
41 #include "printinfo.h"
42
43 void printversion (void);
44 void printusage (void);
45 void usageerror (void);
46 bool copyaudiodata (AFfilehandle infile, AFfilehandle outfile, int trackid);
47
main(int argc,char ** argv)48 int main (int argc, char **argv)
49 {
50 if (argc == 2)
51 {
52 if (!strcmp(argv[1], "--version") || !strcmp(argv[1], "-v"))
53 {
54 printversion();
55 exit(EXIT_SUCCESS);
56 }
57
58 if (!strcmp(argv[1], "--help") || !strcmp(argv[1], "-h"))
59 {
60 printusage();
61 exit(EXIT_SUCCESS);
62 }
63 }
64
65 if (argc < 3)
66 usageerror();
67
68 const char *inFileName = argv[1];
69 const char *outFileName = argv[2];
70
71 int outFileFormat = AF_FILE_UNKNOWN;
72 int outSampleFormat = -1, outSampleWidth = -1, outChannelCount = -1;
73 int outCompression = AF_COMPRESSION_NONE;
74 double outMaxAmp = 1.0;
75
76 int i = 3;
77
78 while (i < argc)
79 {
80 if (!strcmp(argv[i], "format"))
81 {
82 if (i + 1 >= argc)
83 usageerror();
84
85 if (!strcmp(argv[i+1], "aiff"))
86 outFileFormat = AF_FILE_AIFF;
87 else if (!strcmp(argv[i+1], "aifc"))
88 outFileFormat = AF_FILE_AIFFC;
89 else if (!strcmp(argv[i+1], "wave"))
90 outFileFormat = AF_FILE_WAVE;
91 else if (!strcmp(argv[i+1], "next"))
92 outFileFormat = AF_FILE_NEXTSND;
93 else if (!strcmp(argv[i+1], "bics"))
94 outFileFormat = AF_FILE_BICSF;
95 else if (!strcmp(argv[i+1], "smp"))
96 outFileFormat = AF_FILE_SAMPLEVISION;
97 else if (!strcmp(argv[i+1], "voc"))
98 outFileFormat = AF_FILE_VOC;
99 else if (!strcmp(argv[i+1], "nist"))
100 outFileFormat = AF_FILE_NIST_SPHERE;
101 else if (!strcmp(argv[i+1], "caf"))
102 outFileFormat = AF_FILE_CAF;
103 else if (!strcmp(argv[i+1], "flac"))
104 outFileFormat = AF_FILE_FLAC;
105 else
106 {
107 fprintf(stderr, "sfconvert: Unknown format %s.\n", argv[i+1]);
108 exit(EXIT_FAILURE);
109 }
110
111 // Increment for argument.
112 i++;
113 }
114 else if (!strcmp(argv[i], "channels"))
115 {
116 if (i + 1 >= argc)
117 usageerror();
118
119 outChannelCount = atoi(argv[i+1]);
120 if (outChannelCount < 1)
121 usageerror();
122
123 // Increment for argument.
124 i++;
125 }
126 else if (!strcmp(argv[i], "float"))
127 {
128 if (i + 1 >= argc)
129 usageerror();
130
131 outSampleFormat = AF_SAMPFMT_FLOAT;
132 outSampleWidth = 32;
133 outMaxAmp = atof(argv[i+1]);
134
135 // outMaxAmp is currently unused.
136 (void) outMaxAmp;
137
138 // Increment for argument.
139 i++;
140 }
141 else if (!strcmp(argv[i], "integer"))
142 {
143 if (i + 2 >= argc)
144 usageerror();
145
146 outSampleWidth = atoi(argv[i+1]);
147 if (outSampleWidth < 1 || outSampleWidth > 32)
148 usageerror();
149
150 if (!strcmp(argv[i+2], "2scomp"))
151 outSampleFormat = AF_SAMPFMT_TWOSCOMP;
152 else if (!strcmp(argv[i+2], "unsigned"))
153 outSampleFormat = AF_SAMPFMT_UNSIGNED;
154 else
155 usageerror();
156
157 // Increment for arguments.
158 i += 2;
159 }
160 else if (!strcmp(argv[i], "compression"))
161 {
162 if (i + 1 >= argc)
163 usageerror();
164
165 if (!strcmp(argv[i+1], "none"))
166 outCompression = AF_COMPRESSION_NONE;
167 else if (!strcmp(argv[i+1], "ulaw"))
168 outCompression = AF_COMPRESSION_G711_ULAW;
169 else if (!strcmp(argv[i+1], "alaw"))
170 outCompression = AF_COMPRESSION_G711_ALAW;
171 else if (!strcmp(argv[i+1], "ima"))
172 outCompression = AF_COMPRESSION_IMA;
173 else if (!strcmp(argv[i+1], "msadpcm"))
174 outCompression = AF_COMPRESSION_MS_ADPCM;
175 else if (!strcmp(argv[i+1], "flac"))
176 outCompression = AF_COMPRESSION_FLAC;
177 else if (!strcmp(argv[i+1], "alac"))
178 outCompression = AF_COMPRESSION_ALAC;
179 else
180 {
181 fprintf(stderr, "sfconvert: Unknown compression format %s.\n", argv[i+1]);
182 exit(EXIT_FAILURE);
183 }
184
185 i++;
186 }
187 else
188 {
189 printf("Unrecognized command %s\n", argv[i]);
190 }
191
192 i++;
193 }
194
195 AFfilehandle inFile = afOpenFile(inFileName, "r", AF_NULL_FILESETUP);
196 if (!inFile)
197 {
198 printf("Could not open file '%s' for reading.\n", inFileName);
199 return EXIT_FAILURE;
200 }
201
202 // Get audio format parameters from input file.
203 int fileFormat = afGetFileFormat(inFile, NULL);
204 int channelCount = afGetChannels(inFile, AF_DEFAULT_TRACK);
205 double sampleRate = afGetRate(inFile, AF_DEFAULT_TRACK);
206 int sampleFormat, sampleWidth;
207 afGetSampleFormat(inFile, AF_DEFAULT_TRACK, &sampleFormat, &sampleWidth);
208
209 // Initialize output audio format parameters.
210 AFfilesetup outFileSetup = afNewFileSetup();
211
212 if (outFileFormat == -1)
213 outFileFormat = fileFormat;
214
215 if (outSampleFormat == -1 || outSampleWidth == -1)
216 {
217 outSampleFormat = sampleFormat;
218 outSampleWidth = sampleWidth;
219 }
220
221 if (outChannelCount == -1)
222 outChannelCount = channelCount;
223
224 afInitFileFormat(outFileSetup, outFileFormat);
225 afInitCompression(outFileSetup, AF_DEFAULT_TRACK, outCompression);
226 afInitSampleFormat(outFileSetup, AF_DEFAULT_TRACK, outSampleFormat,
227 outSampleWidth);
228 afInitChannels(outFileSetup, AF_DEFAULT_TRACK, outChannelCount);
229 afInitRate(outFileSetup, AF_DEFAULT_TRACK, sampleRate);
230
231 AFfilehandle outFile = afOpenFile(outFileName, "w", outFileSetup);
232 if (!outFile)
233 {
234 printf("Could not open file '%s' for writing.\n", outFileName);
235 return EXIT_FAILURE;
236 }
237
238 afFreeFileSetup(outFileSetup);
239
240 /*
241 Set the output file's virtual audio format parameters
242 to match the audio format parameters of the input file.
243 */
244 afSetVirtualChannels(outFile, AF_DEFAULT_TRACK, channelCount);
245 afSetVirtualSampleFormat(outFile, AF_DEFAULT_TRACK, sampleFormat,
246 sampleWidth);
247
248 bool success = copyaudiodata(inFile, outFile, AF_DEFAULT_TRACK);
249
250 afCloseFile(inFile);
251 afCloseFile(outFile);
252
253 if (!success)
254 {
255 unlink(outFileName);
256 return EXIT_FAILURE;
257 }
258
259 printfileinfo(inFileName);
260 putchar('\n');
261 printfileinfo(outFileName);
262
263 return EXIT_SUCCESS;
264 }
265
printusage(void)266 void printusage (void)
267 {
268 printf("usage: sfconvert infile outfile [ options ... ] [ output keywords ... ]\n");
269 printf("\n");
270
271 printf("Where keywords specify format of input or output soundfile:\n");
272 printf(" format f file format f (see below)\n");
273 printf(" compression c compression format c (see below)\n");
274 printf(" byteorder e endian (e is big or little)\n");
275 printf(" channels n n-channel file (1 or 2)\n");
276 printf(" integer n s n-bit integer file, where s is one of\n");
277 printf(" 2scomp: 2's complement signed data\n");
278 printf(" unsigned: unsigned data\n");
279 printf(" float m floating point file, maxamp m (usually 1.0)\n");
280 printf("\n");
281
282 printf("Currently supported file formats are:\n");
283 printf("\n");
284 printf(" aiff Audio Interchange File Format\n");
285 printf(" aifc AIFF-C File Format\n");
286 printf(" next NeXT/Sun Format\n");
287 printf(" wave MS RIFF WAVE Format\n");
288 printf(" bics Berkeley/IRCAM/CARL Sound File Format\n");
289 printf(" smp Sample Vision Format\n");
290 printf(" voc Creative Voice File\n");
291 printf(" nist NIST SPHERE Format\n");
292 printf(" caf Core Audio Format\n");
293 printf("\n");
294
295 printf("Currently supported compression formats are:\n");
296 printf("\n");
297 printf(" ulaw G.711 u-law\n");
298 printf(" alaw G.711 A-law\n");
299 printf(" ima IMA ADPCM\n");
300 printf(" msadpcm MS ADPCM\n");
301 printf(" flac FLAC\n");
302 printf(" alac Apple Lossless Audio Codec\n");
303 printf("\n");
304 }
305
usageerror(void)306 void usageerror (void)
307 {
308 printusage();
309 exit(EXIT_FAILURE);
310 }
311
printversion(void)312 void printversion (void)
313 {
314 printf("sfconvert: Audio File Library version %s\n", VERSION);
315 }
316
317 /*
318 Copy audio data from one file to another. This function
319 assumes that the virtual sample formats of the two files
320 match.
321 */
copyaudiodata(AFfilehandle infile,AFfilehandle outfile,int trackid)322 bool copyaudiodata (AFfilehandle infile, AFfilehandle outfile, int trackid)
323 {
324 int frameSize = afGetVirtualFrameSize(infile, trackid, 1);
325
326 const int kBufferFrameCount = 65536;
327 void *buffer = malloc(kBufferFrameCount * frameSize);
328
329 AFframecount totalFrames = afGetFrameCount(infile, AF_DEFAULT_TRACK);
330 AFframecount totalFramesWritten = 0;
331
332 bool success = true;
333
334 while (totalFramesWritten < totalFrames)
335 {
336 AFframecount framesToRead = totalFrames - totalFramesWritten;
337 if (framesToRead > kBufferFrameCount)
338 framesToRead = kBufferFrameCount;
339
340 AFframecount framesRead = afReadFrames(infile, trackid, buffer,
341 framesToRead);
342
343 if (framesRead < framesToRead)
344 {
345 fprintf(stderr, "Bad read of audio track data.\n");
346 success = false;
347 break;
348 }
349
350 AFframecount framesWritten = afWriteFrames(outfile, trackid, buffer,
351 framesRead);
352
353 if (framesWritten < framesRead)
354 {
355 fprintf(stderr, "Bad write of audio track data.\n");
356 success = false;
357 break;
358 }
359
360 totalFramesWritten += framesWritten;
361 }
362
363 free(buffer);
364
365 return success;
366 }
367