1 /*
2 Audio File Library
3 Copyright (C) 2000-2001, Silicon Graphics, Inc.
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301 USA
19 */
20
21 #include "config.h"
22
23 #include <stdlib.h>
24 #include <assert.h>
25 #include <string.h>
26
27 #ifdef HAVE_UNISTD_H
28 #include <unistd.h>
29 #endif
30
31 #include <audiofile.h>
32
33 #include "File.h"
34 #include "FileHandle.h"
35 #include "Instrument.h"
36 #include "Marker.h"
37 #include "Setup.h"
38 #include "Track.h"
39 #include "afinternal.h"
40 #include "modules/Module.h"
41 #include "modules/ModuleState.h"
42 #include "units.h"
43 #include "util.h"
44
45 static status _afOpenFile (int access, File *f, const char *filename,
46 AFfilehandle *file, AFfilesetup filesetup);
47
_af_identify(File * f,int * implemented)48 int _af_identify (File *f, int *implemented)
49 {
50 if (!f->canSeek())
51 {
52 _af_error(AF_BAD_LSEEK, "Cannot seek in file");
53 return AF_FILE_UNKNOWN;
54 }
55
56 AFfileoffset curpos = f->tell();
57
58 for (int i=0; i<_AF_NUM_UNITS; i++)
59 {
60 if (_af_units[i].recognize &&
61 _af_units[i].recognize(f))
62 {
63 if (implemented != NULL)
64 *implemented = _af_units[i].implemented;
65 f->seek(curpos, File::SeekFromBeginning);
66 return _af_units[i].fileFormat;
67 }
68 }
69
70 f->seek(curpos, File::SeekFromBeginning);
71
72 if (implemented != NULL)
73 *implemented = false;
74
75 return AF_FILE_UNKNOWN;
76 }
77
afIdentifyFD(int fd)78 int afIdentifyFD (int fd)
79 {
80 /*
81 Duplicate the file descriptor since otherwise the
82 original file descriptor would get closed when we close
83 the virtual file below.
84 */
85 fd = dup(fd);
86 File *f = File::create(fd, File::ReadAccess);
87
88 int result = _af_identify(f, NULL);
89
90 delete f;
91
92 return result;
93 }
94
afIdentifyNamedFD(int fd,const char * filename,int * implemented)95 int afIdentifyNamedFD (int fd, const char *filename, int *implemented)
96 {
97 /*
98 Duplicate the file descriptor since otherwise the
99 original file descriptor would get closed when we close
100 the virtual file below.
101 */
102 fd = dup(fd);
103
104 File *f = File::create(fd, File::ReadAccess);
105 if (!f)
106 {
107 _af_error(AF_BAD_OPEN, "could not open file '%s'", filename);
108 return AF_FILE_UNKNOWN;
109 }
110
111 int result = _af_identify(f, implemented);
112
113 delete f;
114
115 return result;
116 }
117
afOpenFD(int fd,const char * mode,AFfilesetup setup)118 AFfilehandle afOpenFD (int fd, const char *mode, AFfilesetup setup)
119 {
120 if (!mode)
121 {
122 _af_error(AF_BAD_ACCMODE, "null access mode");
123 return AF_NULL_FILEHANDLE;
124 }
125
126 int access;
127 if (mode[0] == 'r')
128 {
129 access = _AF_READ_ACCESS;
130 }
131 else if (mode[0] == 'w')
132 {
133 access = _AF_WRITE_ACCESS;
134 }
135 else
136 {
137 _af_error(AF_BAD_ACCMODE, "unrecognized access mode '%s'", mode);
138 return AF_NULL_FILEHANDLE;
139 }
140
141 File *f = File::create(fd, access == _AF_READ_ACCESS ?
142 File::ReadAccess : File::WriteAccess);
143
144 AFfilehandle filehandle = NULL;
145 if (_afOpenFile(access, f, NULL, &filehandle, setup) != AF_SUCCEED)
146 {
147 delete f;
148 }
149
150 return filehandle;
151 }
152
afOpenNamedFD(int fd,const char * mode,AFfilesetup setup,const char * filename)153 AFfilehandle afOpenNamedFD (int fd, const char *mode, AFfilesetup setup,
154 const char *filename)
155 {
156 if (!mode)
157 {
158 _af_error(AF_BAD_ACCMODE, "null access mode");
159 return AF_NULL_FILEHANDLE;
160 }
161
162 int access;
163 if (mode[0] == 'r')
164 access = _AF_READ_ACCESS;
165 else if (mode[0] == 'w')
166 access = _AF_WRITE_ACCESS;
167 else
168 {
169 _af_error(AF_BAD_ACCMODE, "unrecognized access mode '%s'", mode);
170 return AF_NULL_FILEHANDLE;
171 }
172
173 File *f = File::create(fd, access == _AF_READ_ACCESS ?
174 File::ReadAccess : File::WriteAccess);
175
176 AFfilehandle filehandle;
177 if (_afOpenFile(access, f, filename, &filehandle, setup) != AF_SUCCEED)
178 {
179 delete f;
180 }
181
182 return filehandle;
183 }
184
afOpenFile(const char * filename,const char * mode,AFfilesetup setup)185 AFfilehandle afOpenFile (const char *filename, const char *mode, AFfilesetup setup)
186 {
187 if (!mode)
188 {
189 _af_error(AF_BAD_ACCMODE, "null access mode");
190 return AF_NULL_FILEHANDLE;
191 }
192
193 int access;
194 if (mode[0] == 'r')
195 {
196 access = _AF_READ_ACCESS;
197 }
198 else if (mode[0] == 'w')
199 {
200 access = _AF_WRITE_ACCESS;
201 }
202 else
203 {
204 _af_error(AF_BAD_ACCMODE, "unrecognized access mode '%s'", mode);
205 return AF_NULL_FILEHANDLE;
206 }
207
208 File *f = File::open(filename,
209 access == _AF_READ_ACCESS ? File::ReadAccess : File::WriteAccess);
210 if (!f)
211 {
212 _af_error(AF_BAD_OPEN, "could not open file '%s'", filename);
213 return AF_NULL_FILEHANDLE;
214 }
215
216 AFfilehandle filehandle;
217 if (_afOpenFile(access, f, filename, &filehandle, setup) != AF_SUCCEED)
218 {
219 delete f;
220 }
221
222 return filehandle;
223 }
224
afOpenVirtualFile(AFvirtualfile * vf,const char * mode,AFfilesetup setup)225 AFfilehandle afOpenVirtualFile (AFvirtualfile *vf, const char *mode,
226 AFfilesetup setup)
227 {
228 if (!vf)
229 {
230 _af_error(AF_BAD_OPEN, "null virtual file");
231 return AF_NULL_FILEHANDLE;
232 }
233
234 if (!mode)
235 {
236 _af_error(AF_BAD_ACCMODE, "null access mode");
237 return AF_NULL_FILEHANDLE;
238 }
239
240 int access;
241 if (mode[0] == 'r')
242 {
243 access = _AF_READ_ACCESS;
244 }
245 else if (mode[0] == 'w')
246 {
247 access = _AF_WRITE_ACCESS;
248 }
249 else
250 {
251 _af_error(AF_BAD_ACCMODE, "unrecognized access mode '%s'", mode);
252 return AF_NULL_FILEHANDLE;
253 }
254
255 File *f = File::create(vf,
256 access == _AF_READ_ACCESS ? File::ReadAccess : File::WriteAccess);
257 if (!f)
258 {
259 _af_error(AF_BAD_OPEN, "could not open virtual file");
260 return AF_NULL_FILEHANDLE;
261 }
262
263 AFfilehandle filehandle;
264 if (_afOpenFile(access, f, NULL, &filehandle, setup) != AF_SUCCEED)
265 {
266 delete f;
267 }
268
269 return filehandle;
270 }
271
_afOpenFile(int access,File * f,const char * filename,AFfilehandle * file,AFfilesetup filesetup)272 static status _afOpenFile (int access, File *f, const char *filename,
273 AFfilehandle *file, AFfilesetup filesetup)
274 {
275 int fileFormat = AF_FILE_UNKNOWN;
276 int implemented = true;
277
278 int userSampleFormat = 0;
279 double userSampleRate = 0.0;
280 PCMInfo userPCM = {0};
281 bool userFormatSet = false;
282
283 AFfilehandle filehandle = AF_NULL_FILEHANDLE;
284 AFfilesetup completesetup = AF_NULL_FILESETUP;
285
286 *file = AF_NULL_FILEHANDLE;
287
288 if (access == _AF_WRITE_ACCESS || filesetup != AF_NULL_FILESETUP)
289 {
290 if (!_af_filesetup_ok(filesetup))
291 return AF_FAIL;
292
293 fileFormat = filesetup->fileFormat;
294 if (access == _AF_READ_ACCESS && fileFormat != AF_FILE_RAWDATA)
295 {
296 _af_error(AF_BAD_FILESETUP,
297 "warning: opening file for read access: "
298 "ignoring file setup with non-raw file format");
299 filesetup = AF_NULL_FILESETUP;
300 fileFormat = _af_identify(f, &implemented);
301 }
302 }
303 else if (filesetup == AF_NULL_FILESETUP)
304 fileFormat = _af_identify(f, &implemented);
305
306 if (fileFormat == AF_FILE_UNKNOWN)
307 {
308 if (filename != NULL)
309 _af_error(AF_BAD_NOT_IMPLEMENTED,
310 "'%s': unrecognized audio file format",
311 filename);
312 else
313 _af_error(AF_BAD_NOT_IMPLEMENTED,
314 "unrecognized audio file format");
315 return AF_FAIL;
316 }
317
318 const char *formatName = _af_units[fileFormat].name;
319
320 if (!implemented)
321 {
322 _af_error(AF_BAD_NOT_IMPLEMENTED,
323 "%s format not currently supported", formatName);
324 }
325
326 completesetup = NULL;
327 if (filesetup != AF_NULL_FILESETUP)
328 {
329 userSampleFormat = filesetup->tracks[0].f.sampleFormat;
330 userPCM = filesetup->tracks[0].f.pcm;
331 userSampleRate = filesetup->tracks[0].f.sampleRate;
332 userFormatSet = true;
333 if ((completesetup = _af_units[fileFormat].completesetup(filesetup)) == NULL)
334 return AF_FAIL;
335 }
336
337 filehandle = _AFfilehandle::create(fileFormat);
338 if (!filehandle)
339 {
340 if (completesetup)
341 afFreeFileSetup(completesetup);
342 return AF_FAIL;
343 }
344
345 filehandle->m_fh = f;
346 filehandle->m_access = access;
347 filehandle->m_seekok = f->canSeek();
348 if (filename != NULL)
349 filehandle->m_fileName = strdup(filename);
350 else
351 filehandle->m_fileName = NULL;
352 filehandle->m_fileFormat = fileFormat;
353
354 status result = access == _AF_READ_ACCESS ?
355 filehandle->readInit(completesetup) :
356 filehandle->writeInit(completesetup);
357
358 if (result != AF_SUCCEED)
359 {
360 delete filehandle;
361 filehandle = AF_NULL_FILEHANDLE;
362 if (completesetup)
363 afFreeFileSetup(completesetup);
364 return AF_FAIL;
365 }
366
367 if (completesetup)
368 afFreeFileSetup(completesetup);
369
370 /*
371 Initialize virtual format.
372 */
373 for (int t=0; t<filehandle->m_trackCount; t++)
374 {
375 Track *track = &filehandle->m_tracks[t];
376
377 track->v = track->f;
378
379 if (userFormatSet)
380 {
381 track->v.sampleFormat = userSampleFormat;
382 track->v.pcm = userPCM;
383 track->v.sampleRate = userSampleRate;
384 }
385
386 track->v.compressionType = AF_COMPRESSION_NONE;
387 track->v.compressionParams = NULL;
388
389 #if WORDS_BIGENDIAN
390 track->v.byteOrder = AF_BYTEORDER_BIGENDIAN;
391 #else
392 track->v.byteOrder = AF_BYTEORDER_LITTLEENDIAN;
393 #endif
394
395 track->ms = new ModuleState();
396 if (track->ms->init(filehandle, track) == AF_FAIL)
397 {
398 delete filehandle;
399 return AF_FAIL;
400 }
401 }
402
403 *file = filehandle;
404
405 return AF_SUCCEED;
406 }
407
afSyncFile(AFfilehandle handle)408 int afSyncFile (AFfilehandle handle)
409 {
410 if (!_af_filehandle_ok(handle))
411 return -1;
412
413 if (handle->m_access == _AF_WRITE_ACCESS)
414 {
415 /* Finish writes on all tracks. */
416 for (int trackno = 0; trackno < handle->m_trackCount; trackno++)
417 {
418 Track *track = &handle->m_tracks[trackno];
419
420 if (track->ms->isDirty() && track->ms->setup(handle, track) == AF_FAIL)
421 return -1;
422
423 if (track->ms->sync(handle, track) != AF_SUCCEED)
424 return -1;
425 }
426
427 /* Update file headers. */
428 if (handle->update() != AF_SUCCEED)
429 return AF_FAIL;
430 }
431 else if (handle->m_access == _AF_READ_ACCESS)
432 {
433 /* Do nothing. */
434 }
435 else
436 {
437 _af_error(AF_BAD_ACCMODE, "unrecognized access mode %d",
438 handle->m_access);
439 return AF_FAIL;
440 }
441
442 return AF_SUCCEED;
443 }
444
afCloseFile(AFfilehandle file)445 int afCloseFile (AFfilehandle file)
446 {
447 int err;
448
449 if (!_af_filehandle_ok(file))
450 return -1;
451
452 afSyncFile(file);
453
454 err = file->m_fh->close();
455 if (err < 0)
456 _af_error(AF_BAD_CLOSE, "close returned %d", err);
457
458 delete file->m_fh;
459 delete file;
460
461 return 0;
462 }
463