/*
Audio File Library
Copyright (C) 2000-2001, Silicon Graphics, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307 USA.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <audiofile.h>
#include "afinternal.h"
#include "units.h"
#include "util.h"
#include "modules.h"
#ifndef _MSC_VER
#define SETBINARYMODE(x)
#endif
extern _Unit _af_units[];
static void freeFileHandle (AFfilehandle filehandle);
static void freeInstParams (AFPVu *values, int fileFormat);
static status _afOpenFile (int access, AFvirtualfile *vf, const char *filename,
AFfilehandle *file, AFfilesetup filesetup);
int _af_identify (AFvirtualfile *vf, int *implemented)
{
AFfileoffset curpos;
int i;
curpos = af_ftell(vf);
for (i=0; i<_AF_NUM_UNITS; i++)
{
if (_af_units[i].read.recognize &&
_af_units[i].read.recognize(vf))
{
if (implemented != NULL)
*implemented = _af_units[i].implemented;
af_fseek(vf, curpos, SEEK_SET);
return _af_units[i].fileFormat;
}
}
af_fseek(vf, curpos, SEEK_SET);
if (implemented != NULL)
*implemented = AF_FALSE;
return AF_FILE_UNKNOWN;
}
int afIdentifyFD (int fd)
{
FILE *fp;
AFvirtualfile *vf;
int result;
/*
Duplicate the file descriptor since otherwise the
original file descriptor would get closed when we close
the virtual file below.
*/
fd = dup(fd);
fp = fdopen(fd, "r");
if (fp == NULL)
{
_af_error(AF_BAD_OPEN, "could not open file");
return AF_FILE_UNKNOWN;
}
SETBINARYMODE(fp);
vf = af_virtual_file_new_for_file(fp);
if (vf == NULL)
{
_af_error(AF_BAD_OPEN, "could not open file");
return AF_FILE_UNKNOWN;
}
result = _af_identify(vf, NULL);
af_fclose(vf);
return result;
}
int afIdentifyNamedFD (int fd, const char *filename, int *implemented)
{
FILE *fp;
AFvirtualfile *vf;
int result;
/*
Duplicate the file descriptor since otherwise the
original file descriptor would get closed when we close
the virtual file below.
*/
fd = dup(fd);
fp = fdopen(fd, "r");
if (fp == NULL)
{
_af_error(AF_BAD_OPEN, "could not open file '%s'", filename);
return AF_FILE_UNKNOWN;
}
SETBINARYMODE(fp);
vf = af_virtual_file_new_for_file(fp);
if (vf == NULL)
{
_af_error(AF_BAD_OPEN, "could not open file '%s'", filename);
return AF_FILE_UNKNOWN;
}
result = _af_identify(vf, implemented);
af_fclose(vf);
return result;
}
AFfilehandle afOpenFD (int fd, const char *mode, AFfilesetup setup)
{
FILE *fp;
AFvirtualfile *vf;
AFfilehandle filehandle;
int access;
if (mode == NULL)
{
_af_error(AF_BAD_ACCMODE, "null access mode");
return AF_NULL_FILEHANDLE;
}
if (mode[0] == 'r')
access = _AF_READ_ACCESS;
else if (mode[0] == 'w')
access = _AF_WRITE_ACCESS;
else
{
_af_error(AF_BAD_ACCMODE, "unrecognized access mode '%s'", mode);
return AF_NULL_FILEHANDLE;
}
if ((fp = fdopen(fd, mode)) == NULL)
{
_af_error(AF_BAD_OPEN, "could not open file");
return AF_NULL_FILEHANDLE;
}
SETBINARYMODE(fp);
vf = af_virtual_file_new_for_file(fp);
if (_afOpenFile(access, vf, NULL, &filehandle, setup) != AF_SUCCEED)
af_fclose(vf);
return filehandle;
}
AFfilehandle afOpenNamedFD (int fd, const char *mode, AFfilesetup setup,
const char *filename)
{
FILE *fp;
AFvirtualfile *vf;
AFfilehandle filehandle;
int access;
if (mode == NULL)
{
_af_error(AF_BAD_ACCMODE, "null access mode");
return AF_NULL_FILEHANDLE;
}
if (mode[0] == 'r')
access = _AF_READ_ACCESS;
else if (mode[0] == 'w')
access = _AF_WRITE_ACCESS;
else
{
_af_error(AF_BAD_ACCMODE, "unrecognized access mode '%s'", mode);
return AF_NULL_FILEHANDLE;
}
if ((fp = fdopen(fd, mode)) == NULL)
{
_af_error(AF_BAD_OPEN, "could not open file '%s'", filename);
return AF_NULL_FILEHANDLE;
}
SETBINARYMODE(fp);
vf = af_virtual_file_new_for_file(fp);
if (_afOpenFile(access, vf, filename, &filehandle, setup) != AF_SUCCEED)
af_fclose(vf);
return filehandle;
}
AFfilehandle afOpenFile (const char *filename, const char *mode, AFfilesetup setup)
{
FILE *fp;
AFvirtualfile *vf;
AFfilehandle filehandle;
int access;
if (mode == NULL)
{
_af_error(AF_BAD_ACCMODE, "null access mode");
return AF_NULL_FILEHANDLE;
}
if (mode[0] == 'r')
access = _AF_READ_ACCESS;
else if (mode[0] == 'w')
access = _AF_WRITE_ACCESS;
else
{
_af_error(AF_BAD_ACCMODE, "unrecognized access mode '%s'", mode);
return AF_NULL_FILEHANDLE;
}
if ((fp = fopen(filename, mode)) == NULL)
{
_af_error(AF_BAD_OPEN, "could not open file '%s'", filename);
return AF_NULL_FILEHANDLE;
}
SETBINARYMODE(fp);
vf = af_virtual_file_new_for_file(fp);
if (_afOpenFile(access, vf, filename, &filehandle, setup) != AF_SUCCEED)
af_fclose(vf);
return filehandle;
}
AFfilehandle afOpenVirtualFile (AFvirtualfile *vfile, const char *mode,
AFfilesetup setup)
{
AFfilehandle filehandle;
int access;
if (vfile == NULL)
{
_af_error(AF_BAD_FILEHANDLE, "null virtual filehandle");
return AF_NULL_FILEHANDLE;
}
if (mode == NULL)
{
_af_error(AF_BAD_ACCMODE, "null access mode");
return AF_NULL_FILEHANDLE;
}
if (mode[0] == 'r')
access = _AF_READ_ACCESS;
else if (mode[0] == 'w')
access = _AF_WRITE_ACCESS;
else
{
_af_error(AF_BAD_ACCMODE, "unrecognized access mode '%s'", mode);
return AF_NULL_FILEHANDLE;
}
if (_afOpenFile(access, vfile, NULL, &filehandle, setup) != AF_SUCCEED)
af_fclose(vfile);
return filehandle;
}
static status _afOpenFile (int access, AFvirtualfile *vf, const char *filename,
AFfilehandle *file, AFfilesetup filesetup)
{
int fileFormat = AF_FILE_UNKNOWN;
bool implemented = AF_TRUE;
char *formatName;
status (*initfunc) (AFfilesetup, AFfilehandle);
int userSampleFormat = 0;
double userSampleRate = 0.0;
_PCMInfo userPCM;
bool userFormatSet = AF_FALSE;
int t;
AFfilehandle filehandle = AF_NULL_FILEHANDLE;
AFfilesetup completesetup = AF_NULL_FILESETUP;
*file = AF_NULL_FILEHANDLE;
if (access == _AF_WRITE_ACCESS || filesetup != AF_NULL_FILESETUP)
{
if (!_af_filesetup_ok(filesetup))
return AF_FAIL;
fileFormat = filesetup->fileFormat;
if (access == _AF_READ_ACCESS && fileFormat != AF_FILE_RAWDATA)
{
_af_error(AF_BAD_FILESETUP,
"warning: opening file for read access: "
"ignoring file setup with non-raw file format");
filesetup = AF_NULL_FILESETUP;
fileFormat = _af_identify(vf, (int *) &implemented);
}
}
else if (filesetup == AF_NULL_FILESETUP)
fileFormat = _af_identify(vf, (int *) &implemented);
if (fileFormat == AF_FILE_UNKNOWN)
{
if (filename != NULL)
_af_error(AF_BAD_NOT_IMPLEMENTED,
"'%s': unrecognized audio file format",
filename);
else
_af_error(AF_BAD_NOT_IMPLEMENTED,
"unrecognized audio file format");
return AF_FAIL;
}
formatName = _af_units[fileFormat].name;
if (implemented == AF_FALSE)
{
_af_error(AF_BAD_NOT_IMPLEMENTED,
"%s format not currently supported", formatName);
}
assert(_af_units[fileFormat].completesetup != NULL);
assert(_af_units[fileFormat].read.init != NULL);
if (access == _AF_WRITE_ACCESS &&
_af_units[fileFormat].write.init == NULL)
{
_af_error(AF_BAD_NOT_IMPLEMENTED,
"%s format is currently supported for reading only",
formatName);
return AF_FAIL;
}
completesetup = NULL;
if (filesetup != AF_NULL_FILESETUP)
{
userSampleFormat = filesetup->tracks[0].f.sampleFormat;
userPCM = filesetup->tracks[0].f.pcm;
userSampleRate = filesetup->tracks[0].f.sampleRate;
userFormatSet = AF_TRUE;
if ((completesetup = _af_units[fileFormat].completesetup(filesetup)) == NULL)
return AF_FAIL;
}
filehandle = (_AFfilehandle *) _af_malloc(sizeof (_AFfilehandle));
if (filehandle == NULL)
{
if (completesetup)
afFreeFileSetup(completesetup);
return AF_FAIL;
}
memset(filehandle, 0, sizeof (_AFfilehandle));
filehandle->valid = _AF_VALID_FILEHANDLE;
filehandle->fh = vf;
filehandle->access = access;
filehandle->fileFormat = fileFormat;
filehandle->formatSpecific = NULL;
initfunc = (access == _AF_READ_ACCESS) ?
_af_units[fileFormat].read.init : _af_units[fileFormat].write.init;
if (initfunc(completesetup, filehandle) != AF_SUCCEED)
{
freeFileHandle(filehandle);
filehandle = AF_NULL_FILEHANDLE;
if (completesetup)
afFreeFileSetup(completesetup);
return AF_FAIL;
}
if (completesetup)
{
afFreeFileSetup(completesetup);
completesetup = NULL;
}
/*
Initialize virtual format.
*/
for (t=0; t<filehandle->trackCount; t++)
{
_Track *track = &filehandle->tracks[t];
track->v = track->f;
if (userFormatSet)
{
track->v.sampleFormat = userSampleFormat;
track->v.pcm = userPCM;
track->v.sampleRate = userSampleRate;
}
track->v.compressionType = AF_COMPRESSION_NONE;
track->v.compressionParams = NULL;
#if WORDS_BIGENDIAN
track->v.byteOrder = AF_BYTEORDER_BIGENDIAN;
#else
track->v.byteOrder = AF_BYTEORDER_LITTLEENDIAN;
#endif
if (_AFinitmodules(filehandle, track) == AF_FAIL)
{
freeFileHandle(filehandle);
return AF_FAIL;
}
}
*file = filehandle;
return AF_SUCCEED;
}
int afSyncFile (AFfilehandle handle)
{
if (!_af_filehandle_ok(handle))
return -1;
if (handle->access == _AF_WRITE_ACCESS)
{
int filefmt = handle->fileFormat;
int trackno;
/* Finish writes on all tracks. */
for (trackno = 0; trackno < handle->trackCount; trackno++)
{
_Track *track = &handle->tracks[trackno];
if (track->ms.modulesdirty)
{
if (_AFsetupmodules(handle, track) == AF_FAIL)
return -1;
}
if (_AFsyncmodules(handle, track) != AF_SUCCEED)
return -1;
}
/* Update file headers. */
if (_af_units[filefmt].write.update != NULL &&
_af_units[filefmt].write.update(handle) != AF_SUCCEED)
return AF_FAIL;
}
else if (handle->access == _AF_READ_ACCESS)
{
/* Do nothing. */
}
else
{
_af_error(AF_BAD_ACCMODE, "unrecognized access mode %d",
handle->access);
return AF_FAIL;
}
return AF_SUCCEED;
}
int afCloseFile (AFfilehandle file)
{
int err;
if (!_af_filehandle_ok(file))
return -1;
afSyncFile(file);
err = af_fclose(file->fh);
if (err < 0)
_af_error(AF_BAD_CLOSE, "close returned %d", err);
freeFileHandle(file);
return 0;
}
static void freeFileHandle (AFfilehandle filehandle)
{
int fileFormat;
if (filehandle == NULL || filehandle->valid != _AF_VALID_FILEHANDLE)
{
_af_error(AF_BAD_FILEHANDLE, "bad filehandle");
return;
}
filehandle->valid = 0;
fileFormat = filehandle->fileFormat;
if (filehandle->formatSpecific != NULL)
{
free(filehandle->formatSpecific);
filehandle->formatSpecific = NULL;
}
if (filehandle->tracks)
{
int i;
for (i=0; i<filehandle->trackCount; i++)
{
/* Free the compression parameters. */
if (filehandle->tracks[i].f.compressionParams)
{
AUpvfree((_AUpvlist *) (filehandle->tracks[i].f.compressionParams));
filehandle->tracks[i].f.compressionParams = AU_NULL_PVLIST;
}
if (filehandle->tracks[i].v.compressionParams)
{
AUpvfree((_AUpvlist *) (filehandle->tracks[i].v.compressionParams));
filehandle->tracks[i].v.compressionParams = AU_NULL_PVLIST;
}
/* Free the track's modules. */
_AFfreemodules(&filehandle->tracks[i]);
if (filehandle->tracks[i].channelMatrix)
{
free(filehandle->tracks[i].channelMatrix);
filehandle->tracks[i].channelMatrix = NULL;
}
if (filehandle->tracks[i].markers)
{
int j;
for (j=0; j<filehandle->tracks[i].markerCount; j++)
{
if (filehandle->tracks[i].markers[j].name)
{
free(filehandle->tracks[i].markers[j].name);
filehandle->tracks[i].markers[j].name = NULL;
}
if (filehandle->tracks[i].markers[j].comment)
{
free(filehandle->tracks[i].markers[j].comment);
filehandle->tracks[i].markers[j].comment = NULL;
}
}
free(filehandle->tracks[i].markers);
filehandle->tracks[i].markers = NULL;
}
}
free(filehandle->tracks);
filehandle->tracks = NULL;
}
filehandle->trackCount = 0;
if (filehandle->instruments)
{
int i;
for (i=0; i<filehandle->instrumentCount; i++)
{
if (filehandle->instruments[i].loops)
{
free(filehandle->instruments[i].loops);
filehandle->instruments[i].loops = NULL;
}
filehandle->instruments[i].loopCount = 0;
if (filehandle->instruments[i].values)
{
freeInstParams(filehandle->instruments[i].values, fileFormat);
filehandle->instruments[i].values = NULL;
}
}
free(filehandle->instruments);
filehandle->instruments = NULL;
}
filehandle->instrumentCount = 0;
if (filehandle->miscellaneous)
{
free(filehandle->miscellaneous);
filehandle->miscellaneous = NULL;
}
filehandle->miscellaneousCount = 0;
memset(filehandle, 0, sizeof (_AFfilehandle));
free(filehandle);
}
static void freeInstParams (AFPVu *values, int fileFormat)
{
int i;
int parameterCount = _af_units[fileFormat].instrumentParameterCount;
for (i=0; i<parameterCount; i++)
{
if (_af_units[fileFormat].instrumentParameters[i].type == AU_PVTYPE_PTR)
if (values[i].v != NULL)
free(values[i].v);
}
free(values);
}
syntax highlighted by Code2HTML, v. 0.9.1