#define HAVE_UNISTD_H 1
#if defined __BIG_ENDIAN__
# define WORDS_BIGENDIAN 1
#endif
#include <stdlib.h>
#ifndef Features_h
#define Features_h
#define ENABLE(FEATURE) (defined ENABLE_##FEATURE && ENABLE_##FEATURE)
#endif
#ifndef COMPILER_H
#define COMPILER_H
#if defined(__GNUC__) && !defined(__clang__)
#define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
#define GCC_VERSION_AT_LEAST(major, minor, patch) \
(GCC_VERSION >= (major * 10000 + minor * 100 + patch))
#if GCC_VERSION_AT_LEAST(4, 7, 0) && defined(__cplusplus) && __cplusplus >= 201103L
#define OVERRIDE override
#endif
#endif
#if defined(__clang__)
#if __has_extension(cxx_override_control)
#define OVERRRIDE override
#endif
#endif
#ifndef OVERRIDE
#define OVERRIDE
#endif
#endif
#ifndef ERROR_H
#define ERROR_H
#ifdef __cplusplus
extern "C" {
#endif
#if !defined(__GNUC__) && !defined(__clang__) && !defined(__attribute__)
#define __attribute__(x)
#endif
void _af_error (int errorCode, const char *fmt, ...)
__attribute__((format(printf, 2, 3)));
#ifdef __cplusplus
}
#endif
#endif
#ifndef EXTENDED_H
#define EXTENDED_H
#ifdef __cplusplus
extern "C" {
#endif
void _af_convert_to_ieee_extended (double num, unsigned char *bytes);
double _af_convert_from_ieee_extended (const unsigned char *bytes);
#ifdef __cplusplus
}
#endif
#endif
#ifndef COMPRESSION_H
#define COMPRESSION_H
struct CompressionUnit;
const CompressionUnit *_af_compression_unit_from_id (int compressionid);
#endif
#ifndef AUPVINTERNAL_H
#define AUPVINTERNAL_H
struct _AUpvitem
{
int valid;
int type;
int parameter;
union
{
long l;
double d;
void *v;
}
value;
};
struct _AUpvlist
{
int valid;
size_t count;
struct _AUpvitem *items;
};
enum
{
_AU_VALID_PVLIST = 30932,
_AU_VALID_PVITEM = 30933
};
enum
{
AU_BAD_PVLIST = -5,
AU_BAD_PVITEM = -6,
AU_BAD_PVTYPE = -7,
AU_BAD_ALLOC = -8
};
enum
{
_AU_FAIL = -1,
_AU_SUCCESS = 0
};
#define _AU_NULL_PVITEM ((struct _AUpvitem *) NULL)
#endif
#ifndef AUPVLIST_H
#define AUPVLIST_H
#ifdef __cplusplus
extern "C" {
#endif
#if (defined(__GNUC__) && __GNUC__ >= 4) || defined(__clang__)
#define AFAPI __attribute__((visibility("default")))
#else
#define AFAPI
#endif
enum
{
AU_PVTYPE_LONG = 1,
AU_PVTYPE_DOUBLE = 2,
AU_PVTYPE_PTR = 3
};
typedef struct _AUpvlist *AUpvlist;
#define AU_NULL_PVLIST ((struct _AUpvlist *) 0)
AFAPI AUpvlist AUpvnew (int maxItems);
AFAPI int AUpvgetmaxitems (AUpvlist);
AFAPI int AUpvfree (AUpvlist);
AFAPI int AUpvsetparam (AUpvlist, int item, int param);
AFAPI int AUpvsetvaltype (AUpvlist, int item, int type);
AFAPI int AUpvsetval (AUpvlist, int item, void *val);
AFAPI int AUpvgetparam (AUpvlist, int item, int *param);
AFAPI int AUpvgetvaltype (AUpvlist, int item, int *type);
AFAPI int AUpvgetval (AUpvlist, int item, void *val);
#undef AFAPI
#ifdef __cplusplus
}
#endif
#endif
#ifndef AUDIOFILE_H
#define AUDIOFILE_H
#include <aupvlist.h>
#include <stdint.h>
#include <sys/types.h>
#define LIBAUDIOFILE_MAJOR_VERSION 0
#define LIBAUDIOFILE_MINOR_VERSION 3
#define LIBAUDIOFILE_MICRO_VERSION 6
#ifdef __cplusplus
extern "C" {
#endif
#if (defined(__GNUC__) && __GNUC__ >= 4) || defined(__clang__)
#define AFAPI __attribute__((visibility("default")))
#else
#define AFAPI
#endif
typedef struct _AFvirtualfile AFvirtualfile;
typedef struct _AFfilesetup *AFfilesetup;
typedef struct _AFfilehandle *AFfilehandle;
typedef void (*AFerrfunc)(long, const char *);
#if defined(__FreeBSD__) || \
defined(__DragonFly__) || \
defined(__NetBSD__) || \
defined(__OpenBSD__) || \
defined(__APPLE__) || \
defined(__sgi) || \
(defined(__linux__) && defined(__LP64__))
typedef off_t AFframecount;
typedef off_t AFfileoffset;
#else
typedef int64_t AFframecount;
typedef int64_t AFfileoffset;
#endif
#define AF_NULL_FILESETUP ((struct _AFfilesetup *) 0)
#define AF_NULL_FILEHANDLE ((struct _AFfilehandle *) 0)
#define AF_ERR_BASE 3000
enum
{
AF_DEFAULT_TRACK = 1001
};
enum
{
AF_DEFAULT_INST = 2001
};
enum
{
AF_NUM_UNLIMITED = 99999
};
enum
{
AF_BYTEORDER_BIGENDIAN = 501,
AF_BYTEORDER_LITTLEENDIAN = 502
};
enum
{
AF_FILE_UNKNOWN = -1,
AF_FILE_RAWDATA = 0,
AF_FILE_AIFFC = 1,
AF_FILE_AIFF = 2,
AF_FILE_NEXTSND = 3,
AF_FILE_WAVE = 4,
AF_FILE_BICSF = 5,
AF_FILE_IRCAM = AF_FILE_BICSF,
AF_FILE_MPEG1BITSTREAM = 6,
AF_FILE_SOUNDDESIGNER1 = 7,
AF_FILE_SOUNDDESIGNER2 = 8,
AF_FILE_AVR = 9,
AF_FILE_IFF_8SVX = 10,
AF_FILE_SAMPLEVISION = 11,
AF_FILE_VOC = 12,
AF_FILE_NIST_SPHERE = 13,
AF_FILE_SOUNDFONT2 = 14,
AF_FILE_CAF = 15,
AF_FILE_FLAC = 16
};
enum
{
AF_LOOP_MODE_NOLOOP = 0,
AF_LOOP_MODE_FORW = 1,
AF_LOOP_MODE_FORWBAKW = 2
};
enum
{
AF_SAMPFMT_TWOSCOMP = 401,
AF_SAMPFMT_UNSIGNED = 402,
AF_SAMPFMT_FLOAT = 403,
AF_SAMPFMT_DOUBLE = 404
};
enum
{
AF_INST_LOOP_OFF = 0,
AF_INST_LOOP_CONTINUOUS = 1,
AF_INST_LOOP_SUSTAIN = 3
};
enum
{
AF_INST_MIDI_BASENOTE = 301,
AF_INST_NUMCENTS_DETUNE = 302,
AF_INST_MIDI_LONOTE = 303,
AF_INST_MIDI_HINOTE = 304,
AF_INST_MIDI_LOVELOCITY = 305,
AF_INST_MIDI_HIVELOCITY = 306,
AF_INST_NUMDBS_GAIN = 307,
AF_INST_SUSLOOPID = 308,
AF_INST_RELLOOPID = 309,
AF_INST_SAMP_STARTFRAME = 310,
AF_INST_SAMP_ENDFRAME = 311,
AF_INST_SAMP_MODE = 312,
AF_INST_TRACKID = 313,
AF_INST_NAME = 314,
AF_INST_SAMP_RATE = 315,
AF_INST_PRESETID = 316,
AF_INST_PRESET_NAME = 317
};
enum
{
AF_MISC_UNRECOGNIZED = 0,
AF_MISC_COPY = 201,
AF_MISC_AUTH = 202,
AF_MISC_NAME = 203,
AF_MISC_ANNO = 204,
AF_MISC_APPL = 205,
AF_MISC_MIDI = 206,
AF_MISC_PCMMAP = 207,
AF_MISC_NeXT = 208,
AF_MISC_IRCAM_PEAKAMP = 209,
AF_MISC_IRCAM_COMMENT = 210,
AF_MISC_COMMENT = 210,
AF_MISC_ICMT = AF_MISC_COMMENT,
AF_MISC_ICRD = 211,
AF_MISC_ISFT = 212
};
enum
{
AF_COMPRESSION_UNKNOWN = -1,
AF_COMPRESSION_NONE = 0,
AF_COMPRESSION_G722 = 501,
AF_COMPRESSION_G711_ULAW = 502,
AF_COMPRESSION_G711_ALAW = 503,
AF_COMPRESSION_APPLE_ACE2 = 504,
AF_COMPRESSION_APPLE_ACE8 = 505,
AF_COMPRESSION_APPLE_MAC3 = 506,
AF_COMPRESSION_APPLE_MAC6 = 507,
AF_COMPRESSION_G726 = 517,
AF_COMPRESSION_G728 = 518,
AF_COMPRESSION_DVI_AUDIO = 519,
AF_COMPRESSION_IMA = AF_COMPRESSION_DVI_AUDIO,
AF_COMPRESSION_GSM = 520,
AF_COMPRESSION_FS1016 = 521,
AF_COMPRESSION_DV = 522,
AF_COMPRESSION_MS_ADPCM = 523,
AF_COMPRESSION_FLAC = 530,
AF_COMPRESSION_ALAC = 540
};
enum
{
AF_QUERYTYPE_INSTPARAM = 500,
AF_QUERYTYPE_FILEFMT = 501,
AF_QUERYTYPE_COMPRESSION = 502,
AF_QUERYTYPE_COMPRESSIONPARAM = 503,
AF_QUERYTYPE_MISC = 504,
AF_QUERYTYPE_INST = 505,
AF_QUERYTYPE_MARK = 506,
AF_QUERYTYPE_LOOP = 507
};
enum
{
AF_QUERY_NAME = 600,
AF_QUERY_DESC = 601,
AF_QUERY_LABEL = 602,
AF_QUERY_TYPE = 603,
AF_QUERY_DEFAULT = 604,
AF_QUERY_ID_COUNT = 605,
AF_QUERY_IDS = 606,
AF_QUERY_IMPLEMENTED = 613,
AF_QUERY_TYPE_COUNT = 607,
AF_QUERY_TYPES = 608,
AF_QUERY_NATIVE_SAMPFMT = 609,
AF_QUERY_NATIVE_SAMPWIDTH = 610,
AF_QUERY_SQUISHFAC = 611,
AF_QUERY_MAX_NUMBER = 612,
AF_QUERY_SUPPORTED = 613
};
enum
{
AF_QUERY_TRACKS = 620,
AF_QUERY_CHANNELS = 621,
AF_QUERY_SAMPLE_SIZES = 622,
AF_QUERY_SAMPLE_FORMATS = 623,
AF_QUERY_COMPRESSION_TYPES = 624
};
enum
{
AF_QUERY_VALUE_COUNT = 650,
AF_QUERY_VALUES = 651
};
enum
{
AF_BAD_NOT_IMPLEMENTED = 0,
AF_BAD_FILEHANDLE = 1,
AF_BAD_OPEN = 3,
AF_BAD_CLOSE = 4,
AF_BAD_READ = 5,
AF_BAD_WRITE = 6,
AF_BAD_LSEEK = 7,
AF_BAD_NO_FILEHANDLE = 8,
AF_BAD_ACCMODE = 10,
AF_BAD_NOWRITEACC = 11,
AF_BAD_NOREADACC = 12,
AF_BAD_FILEFMT = 13,
AF_BAD_RATE = 14,
AF_BAD_CHANNELS = 15,
AF_BAD_SAMPCNT = 16,
AF_BAD_WIDTH = 17,
AF_BAD_SEEKMODE = 18,
AF_BAD_NO_LOOPDATA = 19,
AF_BAD_MALLOC = 20,
AF_BAD_LOOPID = 21,
AF_BAD_SAMPFMT = 22,
AF_BAD_FILESETUP = 23,
AF_BAD_TRACKID = 24,
AF_BAD_NUMTRACKS = 25,
AF_BAD_NO_FILESETUP = 26,
AF_BAD_LOOPMODE = 27,
AF_BAD_INSTID = 28,
AF_BAD_NUMLOOPS = 29,
AF_BAD_NUMMARKS = 30,
AF_BAD_MARKID = 31,
AF_BAD_MARKPOS = 32,
AF_BAD_NUMINSTS = 33,
AF_BAD_NOAESDATA = 34,
AF_BAD_MISCID = 35,
AF_BAD_NUMMISC = 36,
AF_BAD_MISCSIZE = 37,
AF_BAD_MISCTYPE = 38,
AF_BAD_MISCSEEK = 39,
AF_BAD_STRLEN = 40,
AF_BAD_RATECONV = 45,
AF_BAD_SYNCFILE = 46,
AF_BAD_CODEC_CONFIG = 47,
AF_BAD_CODEC_STATE = 48,
AF_BAD_CODEC_LICENSE = 49,
AF_BAD_CODEC_TYPE = 50,
AF_BAD_COMPRESSION = AF_BAD_CODEC_CONFIG,
AF_BAD_COMPTYPE = AF_BAD_CODEC_TYPE,
AF_BAD_INSTPTYPE = 51,
AF_BAD_INSTPID = 52,
AF_BAD_BYTEORDER = 53,
AF_BAD_FILEFMT_PARAM = 54,
AF_BAD_COMP_PARAM = 55,
AF_BAD_DATAOFFSET = 56,
AF_BAD_FRAMECNT = 57,
AF_BAD_QUERYTYPE = 58,
AF_BAD_QUERY = 59,
AF_WARNING_CODEC_RATE = 60,
AF_WARNING_RATECVT = 61,
AF_BAD_HEADER = 62,
AF_BAD_FRAME = 63,
AF_BAD_LOOPCOUNT = 64,
AF_BAD_DMEDIA_CALL = 65,
AF_BAD_AIFF_HEADER = 108,
AF_BAD_AIFF_FORM = 109,
AF_BAD_AIFF_SSND = 110,
AF_BAD_AIFF_CHUNKID = 111,
AF_BAD_AIFF_COMM = 112,
AF_BAD_AIFF_INST = 113,
AF_BAD_AIFF_MARK = 114,
AF_BAD_AIFF_SKIP = 115,
AF_BAD_AIFF_LOOPMODE = 116
};
enum
{
AF_ERR_NOT_IMPLEMENTED = 0+AF_ERR_BASE,
AF_ERR_BAD_FILEHANDLE = 1+AF_ERR_BASE,
AF_ERR_BAD_READ = 5+AF_ERR_BASE,
AF_ERR_BAD_WRITE = 6+AF_ERR_BASE,
AF_ERR_BAD_LSEEK = 7+AF_ERR_BASE,
AF_ERR_BAD_ACCMODE = 10+AF_ERR_BASE,
AF_ERR_NO_WRITEACC = 11+AF_ERR_BASE,
AF_ERR_NO_READACC = 12+AF_ERR_BASE,
AF_ERR_BAD_FILEFMT = 13+AF_ERR_BASE,
AF_ERR_BAD_RATE = 14+AF_ERR_BASE,
AF_ERR_BAD_CHANNELS = 15+AF_ERR_BASE,
AF_ERR_BAD_SAMPCNT = 16+AF_ERR_BASE,
AF_ERR_BAD_WIDTH = 17+AF_ERR_BASE,
AF_ERR_BAD_SEEKMODE = 18+AF_ERR_BASE,
AF_ERR_BAD_LOOPID = 21+AF_ERR_BASE,
AF_ERR_BAD_SAMPFMT = 22+AF_ERR_BASE,
AF_ERR_BAD_FILESETUP = 23+AF_ERR_BASE,
AF_ERR_BAD_TRACKID = 24+AF_ERR_BASE,
AF_ERR_BAD_NUMTRACKS = 25+AF_ERR_BASE,
AF_ERR_BAD_LOOPMODE = 27+AF_ERR_BASE,
AF_ERR_BAD_INSTID = 28+AF_ERR_BASE,
AF_ERR_BAD_NUMLOOPS = 29+AF_ERR_BASE,
AF_ERR_BAD_NUMMARKS = 30+AF_ERR_BASE,
AF_ERR_BAD_MARKID = 31+AF_ERR_BASE,
AF_ERR_BAD_MARKPOS = 32+AF_ERR_BASE,
AF_ERR_BAD_NUMINSTS = 33+AF_ERR_BASE,
AF_ERR_BAD_NOAESDATA = 34+AF_ERR_BASE,
AF_ERR_BAD_MISCID = 35+AF_ERR_BASE,
AF_ERR_BAD_NUMMISC = 36+AF_ERR_BASE,
AF_ERR_BAD_MISCSIZE = 37+AF_ERR_BASE,
AF_ERR_BAD_MISCTYPE = 38+AF_ERR_BASE,
AF_ERR_BAD_MISCSEEK = 39+AF_ERR_BASE,
AF_ERR_BAD_STRLEN = 40+AF_ERR_BASE,
AF_ERR_BAD_RATECONV = 45+AF_ERR_BASE,
AF_ERR_BAD_SYNCFILE = 46+AF_ERR_BASE,
AF_ERR_BAD_CODEC_CONFIG = 47+AF_ERR_BASE,
AF_ERR_BAD_CODEC_TYPE = 50+AF_ERR_BASE,
AF_ERR_BAD_INSTPTYPE = 51+AF_ERR_BASE,
AF_ERR_BAD_INSTPID = 52+AF_ERR_BASE,
AF_ERR_BAD_BYTEORDER = 53+AF_ERR_BASE,
AF_ERR_BAD_FILEFMT_PARAM = 54+AF_ERR_BASE,
AF_ERR_BAD_COMP_PARAM = 55+AF_ERR_BASE,
AF_ERR_BAD_DATAOFFSET = 56+AF_ERR_BASE,
AF_ERR_BAD_FRAMECNT = 57+AF_ERR_BASE,
AF_ERR_BAD_QUERYTYPE = 58+AF_ERR_BASE,
AF_ERR_BAD_QUERY = 59+AF_ERR_BASE,
AF_ERR_BAD_HEADER = 62+AF_ERR_BASE,
AF_ERR_BAD_FRAME = 63+AF_ERR_BASE,
AF_ERR_BAD_LOOPCOUNT = 64+AF_ERR_BASE,
AF_ERR_BAD_AIFF_HEADER = 66+AF_ERR_BASE,
AF_ERR_BAD_AIFF_FORM = 67+AF_ERR_BASE,
AF_ERR_BAD_AIFF_SSND = 68+AF_ERR_BASE,
AF_ERR_BAD_AIFF_CHUNKID = 69+AF_ERR_BASE,
AF_ERR_BAD_AIFF_COMM = 70+AF_ERR_BASE,
AF_ERR_BAD_AIFF_INST = 71+AF_ERR_BASE,
AF_ERR_BAD_AIFF_MARK = 72+AF_ERR_BASE,
AF_ERR_BAD_AIFF_SKIP = 73+AF_ERR_BASE,
AF_ERR_BAD_AIFF_LOOPMODE = 74+AF_ERR_BASE
};
AFAPI AFerrfunc afSetErrorHandler (AFerrfunc efunc);
AFAPI AUpvlist afQuery (int querytype, int arg1, int arg2, int arg3, int arg4);
AFAPI long afQueryLong (int querytype, int arg1, int arg2, int arg3, int arg4);
AFAPI double afQueryDouble (int querytype, int arg1, int arg2, int arg3, int arg4);
AFAPI void *afQueryPointer (int querytype, int arg1, int arg2, int arg3, int arg4);
AFAPI AFfilesetup afNewFileSetup (void);
AFAPI void afFreeFileSetup (AFfilesetup);
AFAPI int afIdentifyFD (int);
AFAPI int afIdentifyNamedFD (int, const char *filename, int *implemented);
AFAPI AFfilehandle afOpenFile (const char *filename, const char *mode,
AFfilesetup setup);
AFAPI AFfilehandle afOpenVirtualFile (AFvirtualfile *vfile, const char *mode,
AFfilesetup setup);
AFAPI AFfilehandle afOpenFD (int fd, const char *mode, AFfilesetup setup);
AFAPI AFfilehandle afOpenNamedFD (int fd, const char *mode, AFfilesetup setup,
const char *filename);
AFAPI void afSaveFilePosition (AFfilehandle file);
AFAPI void afRestoreFilePosition (AFfilehandle file);
AFAPI int afSyncFile (AFfilehandle file);
AFAPI int afCloseFile (AFfilehandle file);
AFAPI void afInitFileFormat (AFfilesetup, int format);
AFAPI int afGetFileFormat (AFfilehandle, int *version);
AFAPI void afInitTrackIDs (AFfilesetup, const int *trackids, int trackCount);
AFAPI int afGetTrackIDs (AFfilehandle, int *trackids);
AFAPI int afReadFrames (AFfilehandle, int track, void *buffer, int frameCount);
AFAPI int afWriteFrames (AFfilehandle, int track, const void *buffer, int frameCount);
AFAPI AFframecount afSeekFrame (AFfilehandle, int track, AFframecount frameoffset);
AFAPI AFframecount afTellFrame (AFfilehandle, int track);
AFAPI AFfileoffset afGetTrackBytes (AFfilehandle, int track);
AFAPI float afGetFrameSize (AFfilehandle, int track, int expand3to4);
AFAPI float afGetVirtualFrameSize (AFfilehandle, int track, int expand3to4);
AFAPI void afInitAESChannelData (AFfilesetup, int track);
AFAPI void afInitAESChannelDataTo (AFfilesetup, int track, int willBeData);
AFAPI int afGetAESChannelData (AFfilehandle, int track, unsigned char buf[24]);
AFAPI void afSetAESChannelData (AFfilehandle, int track, unsigned char buf[24]);
AFAPI void afInitByteOrder (AFfilesetup, int track, int byteOrder);
AFAPI int afGetByteOrder (AFfilehandle, int track);
AFAPI int afSetVirtualByteOrder (AFfilehandle, int track, int byteOrder);
AFAPI int afGetVirtualByteOrder (AFfilehandle, int track);
AFAPI void afInitChannels (AFfilesetup, int track, int nchannels);
AFAPI int afGetChannels (AFfilehandle, int track);
AFAPI int afSetVirtualChannels (AFfilehandle, int track, int channelCount);
AFAPI int afGetVirtualChannels (AFfilehandle, int track);
AFAPI void afSetChannelMatrix (AFfilehandle, int track, double *matrix);
AFAPI void afInitSampleFormat (AFfilesetup, int track, int sampleFormat,
int sampleWidth);
AFAPI void afGetSampleFormat (AFfilehandle file, int track, int *sampleFormat,
int *sampleWidth);
AFAPI int afSetVirtualSampleFormat (AFfilehandle, int track,
int sampleFormat, int sampleWidth);
AFAPI void afGetVirtualSampleFormat (AFfilehandle, int track,
int *sampleFormat, int *sampleWidth);
AFAPI void afInitRate (AFfilesetup, int track, double rate);
AFAPI double afGetRate (AFfilehandle, int track);
#if 0
int afSetVirtualRate (AFfilehandle, int track, double rate);
double afGetVirtualRate (AFfilehandle, int track);
#endif
AFAPI void afInitCompression (AFfilesetup, int track, int compression);
#if 0
void afInitCompressionParams (AFfilesetup, int track, int compression
AUpvlist params, int parameterCount);
#endif
AFAPI int afGetCompression (AFfilehandle, int track);
#if 0
void afGetCompressionParams (AFfilehandle, int track, int *compression,
AUpvlist params, int parameterCount);
int afSetVirtualCompression (AFfilesetup, int track, int compression);
void afSetVirtualCompressionParams (AFfilehandle, int track, int compression,
AUpvlist params, int parameterCount);
int afGetVirtualCompression (AFfilesetup, int track, int compression);
void afGetVirtualCompressionParams (AFfilehandle, int track, int *compression,
AUpvlist params, int parameterCount);
#endif
AFAPI void afInitPCMMapping (AFfilesetup filesetup, int track,
double slope, double intercept, double minClip, double maxClip);
AFAPI void afGetPCMMapping (AFfilehandle file, int track,
double *slope, double *intercept, double *minClip, double *maxClip);
AFAPI int afSetTrackPCMMapping (AFfilehandle file, int track,
double slope, double intercept, double minClip, double maxClip);
AFAPI int afSetVirtualPCMMapping (AFfilehandle file, int track,
double slope, double intercept, double minClip, double maxClip);
AFAPI void afGetVirtualPCMMapping (AFfilehandle file, int track,
double *slope, double *intercept, double *minClip, double *maxClip);
AFAPI void afInitDataOffset(AFfilesetup, int track, AFfileoffset offset);
AFAPI AFfileoffset afGetDataOffset (AFfilehandle, int track);
AFAPI void afInitFrameCount (AFfilesetup, int track, AFframecount frameCount);
AFAPI AFframecount afGetFrameCount (AFfilehandle file, int track);
AFAPI void afInitLoopIDs (AFfilesetup, int instid, const int *ids, int nids);
AFAPI int afGetLoopIDs (AFfilehandle, int instid, int loopids[]);
AFAPI void afSetLoopMode (AFfilehandle, int instid, int loop, int mode);
AFAPI int afGetLoopMode (AFfilehandle, int instid, int loopid);
AFAPI int afSetLoopCount (AFfilehandle, int instid, int loop, int count);
AFAPI int afGetLoopCount (AFfilehandle, int instid, int loopid);
AFAPI void afSetLoopStart (AFfilehandle, int instid, int loopid, int markerid);
AFAPI int afGetLoopStart (AFfilehandle, int instid, int loopid);
AFAPI void afSetLoopEnd (AFfilehandle, int instid, int loopid, int markerid);
AFAPI int afGetLoopEnd (AFfilehandle, int instid, int loopid);
AFAPI int afSetLoopStartFrame (AFfilehandle, int instid, int loop,
AFframecount startFrame);
AFAPI AFframecount afGetLoopStartFrame (AFfilehandle, int instid, int loop);
AFAPI int afSetLoopEndFrame (AFfilehandle, int instid, int loop,
AFframecount startFrame);
AFAPI AFframecount afGetLoopEndFrame (AFfilehandle, int instid, int loop);
AFAPI void afSetLoopTrack (AFfilehandle, int instid, int loopid, int trackid);
AFAPI int afGetLoopTrack (AFfilehandle, int instid, int loopid);
AFAPI void afInitMarkIDs (AFfilesetup, int trackid, const int *ids, int nids);
AFAPI int afGetMarkIDs (AFfilehandle file, int trackid, int markids[]);
AFAPI void afSetMarkPosition (AFfilehandle file, int trackid, int markid,
AFframecount markpos);
AFAPI AFframecount afGetMarkPosition (AFfilehandle file, int trackid, int markid);
AFAPI void afInitMarkName (AFfilesetup, int trackid, int marker, const char *name);
AFAPI void afInitMarkComment (AFfilesetup, int trackid, int marker,
const char *comment);
AFAPI char *afGetMarkName (AFfilehandle file, int trackid, int markid);
AFAPI char *afGetMarkComment (AFfilehandle file, int trackid, int markid);
AFAPI void afInitInstIDs (AFfilesetup, const int *ids, int nids);
AFAPI int afGetInstIDs (AFfilehandle file, int *instids);
AFAPI void afGetInstParams (AFfilehandle file, int instid, AUpvlist pvlist,
int nparams);
AFAPI void afSetInstParams (AFfilehandle file, int instid, AUpvlist pvlist,
int nparams);
AFAPI long afGetInstParamLong (AFfilehandle file, int instid, int param);
AFAPI void afSetInstParamLong (AFfilehandle file, int instid, int param, long value);
AFAPI void afInitMiscIDs (AFfilesetup, const int *ids, int nids);
AFAPI int afGetMiscIDs (AFfilehandle, int *ids);
AFAPI void afInitMiscType (AFfilesetup, int miscellaneousid, int type);
AFAPI int afGetMiscType (AFfilehandle, int miscellaneousid);
AFAPI void afInitMiscSize (AFfilesetup, int miscellaneousid, int size);
AFAPI int afGetMiscSize (AFfilehandle, int miscellaneousid);
AFAPI int afWriteMisc (AFfilehandle, int miscellaneousid, const void *buf, int bytes);
AFAPI int afReadMisc (AFfilehandle, int miscellaneousid, void *buf, int bytes);
AFAPI int afSeekMisc (AFfilehandle, int miscellaneousid, int offset);
#undef AFAPI
#ifdef __cplusplus
}
#endif
#endif
#ifndef AFINTERNAL_H
#define AFINTERNAL_H
#include <sys/types.h>
enum status
{
AF_SUCCEED = 0,
AF_FAIL = -1
};
union AFPVu
{
long l;
double d;
void *v;
};
struct InstParamInfo
{
int id;
int type;
const char *name;
AFPVu defaultValue;
};
struct Loop
{
int id;
int mode;
int count;
int beginMarker, endMarker;
int trackid;
};
struct LoopSetup
{
int id;
};
struct Miscellaneous
{
int id;
int type;
int size;
void *buffer;
int position;
};
struct MiscellaneousSetup
{
int id;
int type;
int size;
};
struct TrackSetup;
class File;
struct Track;
enum
{
_AF_VALID_FILEHANDLE = 38212,
_AF_VALID_FILESETUP = 38213
};
enum
{
_AF_READ_ACCESS = 1,
_AF_WRITE_ACCESS = 2
};
enum
{
_AF_MS_ADPCM_NUM_COEFFICIENTS = 800,
_AF_MS_ADPCM_COEFFICIENTS = 801,
_AF_IMA_ADPCM_TYPE = 810,
_AF_IMA_ADPCM_TYPE_WAVE = 1,
_AF_IMA_ADPCM_TYPE_QT = 2,
_AF_CODEC_DATA = 900,
_AF_CODEC_DATA_SIZE = 901
};
#define _AF_SRATE_CODEC (8012.8210513)
#endif
#ifndef BYTEORDER_H
#define BYTEORDER_H
#include <stdint.h>
#if WORDS_BIGENDIAN
#define _AF_BYTEORDER_NATIVE (AF_BYTEORDER_BIGENDIAN)
#else
#define _AF_BYTEORDER_NATIVE (AF_BYTEORDER_LITTLEENDIAN)
#endif
inline uint16_t _af_byteswap_int16 (uint16_t x)
{
return (x >> 8) | (x << 8);
}
inline uint32_t _af_byteswap_int32 (uint32_t x)
{
return ((x & 0x000000ffU) << 24) |
((x & 0x0000ff00U) << 8) |
((x & 0x00ff0000U) >> 8) |
((x & 0xff000000U) >> 24);
}
inline uint64_t _af_byteswap_int64 (uint64_t x)
{
return ((x & 0x00000000000000ffULL) << 56) |
((x & 0x000000000000ff00ULL) << 40) |
((x & 0x0000000000ff0000ULL) << 24) |
((x & 0x00000000ff000000ULL) << 8) |
((x & 0x000000ff00000000ULL) >> 8) |
((x & 0x0000ff0000000000ULL) >> 24) |
((x & 0x00ff000000000000ULL) >> 40) |
((x & 0xff00000000000000ULL) >> 56);
}
inline float _af_byteswap_float32 (float x)
{
union
{
uint32_t i;
float f;
} u;
u.f = x;
u.i = _af_byteswap_int32(u.i);
return u.f;
}
inline double _af_byteswap_float64 (double x)
{
union
{
uint64_t i;
double f;
} u;
u.f = x;
u.i = _af_byteswap_int64(u.i);
return u.f;
}
inline uint64_t byteswap(uint64_t value) { return _af_byteswap_int64(value); }
inline int64_t byteswap(int64_t value) { return _af_byteswap_int64(value); }
inline uint32_t byteswap(uint32_t value) { return _af_byteswap_int32(value); }
inline int32_t byteswap(int32_t value) { return _af_byteswap_int32(value); }
inline uint16_t byteswap(uint16_t value) { return _af_byteswap_int16(value); }
inline int16_t byteswap(int16_t value) { return _af_byteswap_int16(value); }
inline double byteswap(double value) { return _af_byteswap_float64(value); }
inline float byteswap(float value) { return _af_byteswap_float32(value); }
template <typename T>
T bigToHost(T value)
{
return _AF_BYTEORDER_NATIVE == AF_BYTEORDER_BIGENDIAN ? value : byteswap(value);
}
template <typename T>
T littleToHost(T value)
{
return _AF_BYTEORDER_NATIVE == AF_BYTEORDER_LITTLEENDIAN ? value : byteswap(value);
}
template <typename T>
T hostToBig(T value)
{
return _AF_BYTEORDER_NATIVE == AF_BYTEORDER_BIGENDIAN ? value : byteswap(value);
}
template <typename T>
T hostToLittle(T value)
{
return _AF_BYTEORDER_NATIVE == AF_BYTEORDER_LITTLEENDIAN ? value : byteswap(value);
}
#endif
#ifndef AUDIOFORMAT_H
#define AUDIOFORMAT_H
#include <sys/types.h>
#include <string>
struct PCMInfo
{
double slope, intercept, minClip, maxClip;
};
struct AudioFormat
{
double sampleRate;
int sampleFormat;
int sampleWidth;
int byteOrder;
PCMInfo pcm;
int channelCount;
int compressionType;
AUpvlist compressionParams;
bool packed : 1;
size_t framesPerPacket;
size_t bytesPerPacket;
size_t bytesPerSample(bool stretch3to4) const;
size_t bytesPerFrame(bool stretch3to4) const;
size_t bytesPerSample() const;
size_t bytesPerFrame() const;
bool isInteger() const;
bool isSigned() const;
bool isUnsigned() const;
bool isFloat() const;
bool isCompressed() const;
bool isUncompressed() const;
bool isPacked() const { return packed; }
bool isByteOrderSignificant() const { return sampleWidth > 8; }
void computeBytesPerPacketPCM();
std::string description() const;
};
#endif
#ifndef DEBUG_H
#define DEBUG_H
#include <stdint.h>
void _af_print_filehandle (AFfilehandle filehandle);
void _af_print_tracks (AFfilehandle filehandle);
void _af_print_channel_matrix (double *matrix, int fchans, int vchans);
void _af_print_pvlist (AUpvlist list);
void _af_print_audioformat (AudioFormat *format);
void _af_print_frame (AFframecount frameno, double *frame, int nchannels,
char *formatstring, int numberwidth,
double slope, double intercept, double minclip, double maxclip);
#endif
#ifndef UTIL_H
#define UTIL_H
#include <stdint.h>
#include <stdlib.h>
struct AudioFormat;
bool _af_filesetup_ok (AFfilesetup setup);
bool _af_filehandle_ok (AFfilehandle file);
void *_af_malloc (size_t size);
void *_af_realloc (void *ptr, size_t size);
void *_af_calloc (size_t nmemb, size_t size);
char *_af_strdup (const char *s);
AUpvlist _af_pv_long (long val);
AUpvlist _af_pv_double (double val);
AUpvlist _af_pv_pointer (void *val);
bool _af_pv_getlong (AUpvlist pvlist, int param, long *l);
bool _af_pv_getdouble (AUpvlist pvlist, int param, double *d);
bool _af_pv_getptr (AUpvlist pvlist, int param, void **v);
bool _af_unique_ids (const int *ids, int nids, const char *idname, int iderr);
float _af_format_frame_size (const AudioFormat *format, bool stretch3to4);
int _af_format_frame_size_uncompressed (const AudioFormat *format, bool stretch3to4);
float _af_format_sample_size (const AudioFormat *format, bool stretch3to4);
int _af_format_sample_size_uncompressed (const AudioFormat *format, bool stretch3to4);
status _af_set_sample_format (AudioFormat *f, int sampleFormat, int sampleWidth);
#endif
#ifndef UNIT_H
#define UNIT_H
struct AudioFormat;
class FileModule;
struct Unit
{
int fileFormat;
const char *name;
const char *description;
const char *label;
bool implemented;
AFfilesetup (*completesetup) (AFfilesetup setup);
bool (*recognize) (File *fh);
int defaultSampleFormat;
int defaultSampleWidth;
int compressionTypeCount;
const int *compressionTypes;
int markerCount;
int instrumentCount;
int loopPerInstrumentCount;
int instrumentParameterCount;
const InstParamInfo *instrumentParameters;
};
struct CompressionUnit
{
int compressionID;
bool implemented;
const char *label;
const char *shortname;
const char *name;
double squishFactor;
int nativeSampleFormat;
int nativeSampleWidth;
bool needsRebuffer;
bool multiple_of;
bool (*fmtok) (AudioFormat *format);
FileModule *(*initcompress) (Track *track, File *fh,
bool seekok, bool headerless, AFframecount *chunkframes);
FileModule *(*initdecompress) (Track *track, File *fh,
bool seekok, bool headerless, AFframecount *chunkframes);
};
#define _AF_NUM_UNITS 17
#define _AF_NUM_COMPRESSION 7
extern const Unit _af_units[_AF_NUM_UNITS];
extern const CompressionUnit _af_compression[_AF_NUM_COMPRESSION];
#endif
#ifndef UUID_H
#define UUID_H
#include <stdint.h>
#include <string>
struct UUID
{
uint8_t data[16];
bool operator==(const UUID &) const;
bool operator!=(const UUID &) const;
std::string name() const;
};
#endif
#ifndef SHARED_H
#define SHARED_H
template <typename T>
class Shared
{
public:
Shared() : m_refCount(0)
{
}
void retain() { m_refCount++; }
void release() { if (--m_refCount == 0) delete static_cast<T *>(this); }
protected:
~Shared()
{
}
private:
int m_refCount;
Shared(const Shared &);
Shared &operator =(const Shared &);
};
template <typename T>
class SharedPtr
{
public:
SharedPtr() : m_ptr(0)
{
}
SharedPtr(T *ptr) : m_ptr(ptr)
{
if (m_ptr) m_ptr->retain();
}
SharedPtr(const SharedPtr &p) : m_ptr(p.m_ptr)
{
if (m_ptr) m_ptr->retain();
}
~SharedPtr()
{
if (T *p = m_ptr) p->release();
}
SharedPtr &operator =(T *ptr)
{
if (m_ptr != ptr)
{
if (ptr) ptr->retain();
if (m_ptr) m_ptr->release();
m_ptr = ptr;
}
return *this;
}
SharedPtr &operator =(const SharedPtr &p)
{
if (m_ptr != p.m_ptr)
{
if (p.m_ptr) p.m_ptr->retain();
if (m_ptr) m_ptr->release();
m_ptr = p.m_ptr;
}
return *this;
}
T *get() const { return m_ptr; }
T &operator *() const { return *m_ptr; }
T *operator ->() const { return m_ptr; }
typedef T *SharedPtr::*UnspecifiedBoolType;
operator UnspecifiedBoolType() const { return m_ptr ? &SharedPtr::m_ptr : 0; }
bool operator !() const { return !m_ptr; }
private:
T *m_ptr;
};
#endif
#ifndef Buffer_h
#define Buffer_h
#include <sys/types.h>
class Buffer : public Shared<Buffer>
{
public:
Buffer();
Buffer(size_t size);
Buffer(const void *data, size_t size);
~Buffer();
void *data() { return m_data; }
const void *data() const { return m_data; }
size_t size() const { return m_size; }
private:
void *m_data;
size_t m_size;
};
#endif
#ifndef FILE_H
#define FILE_H
#include <sys/types.h>
typedef struct _AFvirtualfile AFvirtualfile;
class File : public Shared<File>
{
public:
enum AccessMode
{
ReadAccess,
WriteAccess
};
enum SeekOrigin
{
SeekFromBeginning,
SeekFromCurrent,
SeekFromEnd
};
static File *open(const char *path, AccessMode mode);
static File *create(int fd, AccessMode mode);
static File *create(AFvirtualfile *vf, AccessMode mode);
virtual ~File();
virtual int close() = 0;
virtual ssize_t read(void *data, size_t nbytes) = 0;
virtual ssize_t write(const void *data, size_t nbytes) = 0;
virtual off_t length() = 0;
virtual off_t seek(off_t offset, SeekOrigin origin) = 0;
virtual off_t tell() = 0;
bool canSeek();
AccessMode accessMode() const { return m_accessMode; }
private:
AccessMode m_accessMode;
protected:
File(AccessMode mode) : m_accessMode(mode) { }
};
#endif
#ifndef FILEHANDLE_H
#define FILEHANDLE_H
#include <stdint.h>
class File;
class Tag;
struct Instrument;
struct Miscellaneous;
struct Track;
struct _AFfilehandle
{
static _AFfilehandle *create(int fileFormat);
int m_valid;
int m_access;
bool m_seekok;
File *m_fh;
char *m_fileName;
int m_fileFormat;
int m_trackCount;
Track *m_tracks;
int m_instrumentCount;
Instrument *m_instruments;
int m_miscellaneousCount;
Miscellaneous *m_miscellaneous;
private:
int m_formatByteOrder;
status copyTracksFromSetup(AFfilesetup setup);
status copyInstrumentsFromSetup(AFfilesetup setup);
status copyMiscellaneousFromSetup(AFfilesetup setup);
public:
virtual ~_AFfilehandle();
virtual int getVersion() { return 0; }
virtual status readInit(AFfilesetup) = 0;
virtual status writeInit(AFfilesetup) = 0;
virtual status update() = 0;
virtual bool isInstrumentParameterValid(AUpvlist, int) { return false; }
bool checkCanRead();
bool checkCanWrite();
Track *allocateTrack();
Track *getTrack(int trackID = AF_DEFAULT_TRACK);
Instrument *getInstrument(int instrumentID);
Miscellaneous *getMiscellaneous(int miscellaneousID);
protected:
_AFfilehandle();
status initFromSetup(AFfilesetup setup);
void setFormatByteOrder(int byteOrder) { m_formatByteOrder = byteOrder; }
bool readU8(uint8_t *);
bool readS8(int8_t *);
bool readU16(uint16_t *);
bool readS16(int16_t *);
bool readU32(uint32_t *);
bool readS32(int32_t *);
bool readU64(uint64_t *);
bool readS64(int64_t *);
bool readFloat(float *);
bool readDouble(double *);
bool writeU8(const uint8_t *);
bool writeS8(const int8_t *);
bool writeU16(const uint16_t *);
bool writeS16(const int16_t *);
bool writeU32(const uint32_t *);
bool writeS32(const int32_t *);
bool writeU64(const uint64_t *);
bool writeS64(const int64_t *);
bool writeFloat(const float *);
bool writeDouble(const double *);
bool readTag(Tag *t);
bool writeTag(const Tag *t);
};
#endif
#ifndef INSTRUMENT_H
#define INSTRUMENT_H
struct LoopSetup;
struct Loop;
struct InstrumentSetup
{
int id;
int loopCount;
LoopSetup *loops;
bool loopSet;
bool allocateLoops(int count);
void freeLoops();
};
struct Instrument
{
int id;
int loopCount;
Loop *loops;
AFPVu *values;
Loop *getLoop(int loopID);
};
void _af_instparam_get (AFfilehandle file, int instid, AUpvlist pvlist,
int npv, bool forceLong);
void _af_instparam_set (AFfilehandle file, int instid, AUpvlist pvlist,
int npv);
int _af_instparam_index_from_id (int fileFormat, int id);
#endif
#ifndef TRACK_H
#define TRACK_H
class ModuleState;
class PacketTable;
struct Marker;
struct MarkerSetup;
struct TrackSetup
{
int id;
AudioFormat f;
bool rateSet, sampleFormatSet, sampleWidthSet, byteOrderSet,
channelCountSet, compressionSet, aesDataSet, markersSet,
dataOffsetSet, frameCountSet;
int markerCount;
MarkerSetup *markers;
AFfileoffset dataOffset;
AFframecount frameCount;
};
struct Track
{
Track();
~Track();
int id;
AudioFormat f, v;
SharedPtr<PacketTable> m_packetTable;
double *channelMatrix;
int markerCount;
Marker *markers;
bool hasAESData;
unsigned char aesData[24];
AFframecount totalfframes;
AFframecount nextfframe;
AFframecount frames2ignore;
AFfileoffset fpos_first_frame;
AFfileoffset fpos_next_frame;
AFfileoffset fpos_after_data;
AFframecount totalvframes;
AFframecount nextvframe;
AFfileoffset data_size;
SharedPtr<ModuleState> ms;
double taper, dynamic_range;
bool ratecvt_filter_params_set;
bool filemodhappy;
void print();
Marker *getMarker(int markerID);
status copyMarkers(TrackSetup *setup);
void computeTotalFileFrames();
};
#endif
#ifndef MARKER_H
#define MARKER_H
struct MarkerSetup
{
int id;
char *name, *comment;
};
struct Marker
{
short id;
unsigned long position;
char *name;
char *comment;
};
struct Track;
Marker *_af_marker_new (int count);
Marker *_af_marker_find_by_id (Track *track, int id);
#endif
#ifndef SETUP_H
#define SETUP_H
struct InstrumentSetup;
struct MiscellaneousSetup;
struct TrackSetup;
struct _AFfilesetup
{
int valid;
int fileFormat;
bool trackSet, instrumentSet, miscellaneousSet;
int trackCount;
TrackSetup *tracks;
int instrumentCount;
InstrumentSetup *instruments;
int miscellaneousCount;
MiscellaneousSetup *miscellaneous;
TrackSetup *getTrack(int trackID = AF_DEFAULT_TRACK);
InstrumentSetup *getInstrument(int instrumentID);
MiscellaneousSetup *getMiscellaneous(int miscellaneousID);
};
void _af_setup_free_markers (AFfilesetup setup, int trackno);
void _af_setup_free_tracks (AFfilesetup setup);
void _af_setup_free_instruments (AFfilesetup setup);
AFfilesetup _af_filesetup_copy (const _AFfilesetup *setup,
const _AFfilesetup *defaultSetup, bool copyMarks);
InstrumentSetup *_af_instsetup_new (int count);
#endif
#ifndef TAG_H
#define TAG_H
#include <assert.h>
#include <stdint.h>
#include <string.h>
#include <string>
class Tag
{
public:
Tag() : m_value(0) { }
Tag(uint32_t value) : m_value(value) { }
Tag(const char *s)
{
assert(strlen(s) == 4);
memcpy(&m_value, s, 4);
}
uint32_t value() const { return m_value; }
bool operator==(const Tag &t) const { return m_value == t.m_value; }
bool operator!=(const Tag &t) const { return m_value != t.m_value; }
std::string name() const
{
char s[5];
memcpy(s, &m_value, 4);
s[4] = '\0';
return std::string(s);
}
private:
uint32_t m_value;
};
#endif
#ifndef PacketTable_h
#define PacketTable_h
#include <audiofile.h>
#include <stdint.h>
#include <sys/types.h>
#include <vector>
class PacketTable : public Shared<PacketTable>
{
public:
PacketTable();
PacketTable(int64_t numValidFrames,
int32_t primingFrames,
int32_t remainderFrames);
~PacketTable();
size_t numPackets() const { return m_bytesPerPacket.size(); }
int64_t numValidFrames() const { return m_numValidFrames; }
void setNumValidFrames(int64_t numValidFrames);
int32_t primingFrames() const { return m_primingFrames; }
void setPrimingFrames(int32_t primingFrames);
int32_t remainderFrames() const { return m_remainderFrames; }
void setRemainderFrames(int32_t remainderFrames);
void append(size_t bytesPerPacket);
size_t bytesPerPacket(size_t packet) const { return m_bytesPerPacket[packet]; }
AFfileoffset startOfPacket(size_t packet) const;
private:
int64_t m_numValidFrames;
int32_t m_primingFrames;
int32_t m_remainderFrames;
std::vector<size_t> m_bytesPerPacket;
};
#endif
#ifndef PCM_H
#define PCM_H
#define SLOPE_INT8 (128.0)
#define SLOPE_INT16 (32768.0)
#define SLOPE_INT24 (8388608.0)
#define SLOPE_INT32 (2147483648.0)
#define INTERCEPT_U_INT8 (128.0)
#define INTERCEPT_U_INT16 (32768.0)
#define INTERCEPT_U_INT24 (8388608.0)
#define INTERCEPT_U_INT32 (2147483648.0)
#define MIN_INT8 (-128.0)
#define MIN_INT16 (-32768.0)
#define MIN_INT24 (-8388608.0)
#define MIN_INT32 (-2147483648.0)
#define MAX_INT8 127.0
#define MAX_INT16 32767.0
#define MAX_INT24 8388607.0
#define MAX_INT32 2147483647.0
#define MAX_U_INT8 255.0
#define MAX_U_INT16 65535.0
#define MAX_U_INT24 16777215.0
#define MAX_U_INT32 4294967295.0
extern const PCMInfo _af_default_signed_integer_pcm_mappings[];
extern const PCMInfo _af_default_unsigned_integer_pcm_mappings[];
extern const PCMInfo _af_default_float_pcm_mapping;
extern const PCMInfo _af_default_double_pcm_mapping;
#endif
#ifndef G711_H
#define G711_H
#ifdef __cplusplus
extern "C" {
#endif
unsigned char _af_linear2alaw (int pcm_val);
int _af_alaw2linear (unsigned char a_val);
unsigned char _af_linear2ulaw (int pcm_val);
int _af_ulaw2linear (unsigned char u_val);
#ifdef __cplusplus
}
#endif
#endif
#ifndef AUDIOFILE_VFS_H
#define AUDIOFILE_VFS_H
#include <audiofile.h>
#include <sys/types.h>
#ifdef __cplusplus
extern "C" {
#endif
#if (defined(__GNUC__) && __GNUC__ >= 4) || defined(__clang__)
#define AFAPI __attribute__((visibility("default")))
#else
#define AFAPI
#endif
struct _AFvirtualfile
{
ssize_t (*read) (AFvirtualfile *vfile, void *data, size_t nbytes);
AFfileoffset (*length) (AFvirtualfile *vfile);
ssize_t (*write) (AFvirtualfile *vfile, const void *data, size_t nbytes);
void (*destroy) (AFvirtualfile *vfile);
AFfileoffset (*seek) (AFvirtualfile *vfile, AFfileoffset offset, int is_relative);
AFfileoffset (*tell) (AFvirtualfile *vfile);
void *closure;
};
AFAPI AFvirtualfile *af_virtual_file_new (void);
AFAPI void af_virtual_file_destroy (AFvirtualfile *vfile);
#undef AFAPI
#ifdef __cplusplus
}
#endif
#endif
#ifndef RAW_H
#define RAW_H
#define _AF_RAW_NUM_COMPTYPES 2
extern const int _af_raw_compression_types[_AF_RAW_NUM_COMPTYPES];
class RawFile : public _AFfilehandle
{
public:
static bool recognize(File *fh);
static AFfilesetup completeSetup(AFfilesetup);
status readInit(AFfilesetup setup) OVERRIDE;
status writeInit(AFfilesetup setup) OVERRIDE;
status update() OVERRIDE;
};
#endif
#ifndef WAVE_H
#define WAVE_H
#include <stdint.h>
#define _AF_WAVE_NUM_INSTPARAMS 7
extern const InstParamInfo _af_wave_inst_params[_AF_WAVE_NUM_INSTPARAMS];
#define _AF_WAVE_NUM_COMPTYPES 4
extern const int _af_wave_compression_types[_AF_WAVE_NUM_COMPTYPES];
struct UUID;
class WAVEFile : public _AFfilehandle
{
public:
static bool recognize(File *fh);
static AFfilesetup completeSetup(AFfilesetup);
WAVEFile();
status readInit(AFfilesetup) OVERRIDE;
status writeInit(AFfilesetup) OVERRIDE;
status update() OVERRIDE;
bool isInstrumentParameterValid(AUpvlist, int) OVERRIDE;
private:
AFfileoffset m_factOffset;
AFfileoffset m_miscellaneousOffset;
AFfileoffset m_markOffset;
AFfileoffset m_dataSizeOffset;
int m_msadpcmNumCoefficients;
int16_t m_msadpcmCoefficients[256][2];
status parseFrameCount(const Tag &type, uint32_t size);
status parseFormat(const Tag &type, uint32_t size);
status parseData(const Tag &type, uint32_t size);
status parsePlayList(const Tag &type, uint32_t size);
status parseCues(const Tag &type, uint32_t size);
status parseADTLSubChunk(const Tag &type, uint32_t size);
status parseINFOSubChunk(const Tag &type, uint32_t size);
status parseList(const Tag &type, uint32_t size);
status parseInstrument(const Tag &type, uint32_t size);
status writeFormat();
status writeFrameCount();
status writeMiscellaneous();
status writeCues();
status writeData();
bool readUUID(UUID *g);
bool writeUUID(const UUID *g);
bool writeZString(const char *);
size_t zStringLength(const char *);
void initCompressionParams();
void initIMACompressionParams();
void initMSADPCMCompressionParams();
};
#endif
#ifndef SAMPLE_VISION_H
#define SAMPLE_VISION_H
class SampleVisionFile : public _AFfilehandle
{
public:
SampleVisionFile();
virtual ~SampleVisionFile();
static bool recognize(File *fh);
static AFfilesetup completeSetup(AFfilesetup);
status readInit(AFfilesetup) OVERRIDE;
status writeInit(AFfilesetup) OVERRIDE;
status update() OVERRIDE;
private:
AFfileoffset m_frameCountOffset;
status parseLoops();
status parseMarkers();
status writeTrailer();
status writeLoops();
status writeMarkers();
void addMiscellaneous(int type, const char *data);
};
#endif
#ifndef MODULE_H
#define MODULE_H
#include <vector>
enum FormatCode
{
kUndefined = -1,
kInt8,
kInt16,
kInt24,
kInt32,
kFloat,
kDouble,
};
class Chunk : public Shared<Chunk>
{
public:
void *buffer;
size_t frameCount;
AudioFormat f;
bool ownsMemory;
Chunk() : buffer(NULL), frameCount(0), ownsMemory(false) { }
~Chunk()
{
deallocate();
}
void allocate(size_t capacity)
{
deallocate();
ownsMemory = true;
buffer = ::operator new(capacity);
}
void deallocate()
{
if (ownsMemory)
::operator delete(buffer);
ownsMemory = false;
buffer = NULL;
}
};
class Module : public Shared<Module>
{
public:
Module();
virtual ~Module();
void setSink(Module *);
void setSource(Module *);
Chunk *inChunk() const { return m_inChunk.get(); }
void setInChunk(Chunk *chunk) { m_inChunk = chunk; }
Chunk *outChunk() const { return m_outChunk.get(); }
void setOutChunk(Chunk *chunk) { m_outChunk = chunk; }
virtual const char *name() const;
virtual void describe();
virtual void maxPull();
virtual void maxPush();
virtual void runPull();
virtual void reset1() { }
virtual void reset2() { }
virtual void runPush();
virtual void sync1() { }
virtual void sync2() { }
protected:
SharedPtr<Chunk> m_inChunk, m_outChunk;
union
{
Module *m_sink;
Module *m_source;
};
void pull(size_t frames);
void push(size_t frames);
};
#define _AF_ATOMIC_NVFRAMES 1024
#endif
#ifndef MODULESTATE_H
#define MODULESTATE_H
#include <vector>
class FileModule;
class Module;
class ModuleState : public Shared<ModuleState>
{
public:
ModuleState();
virtual ~ModuleState();
bool isDirty() const { return m_isDirty; }
void setDirty() { m_isDirty = true; }
status init(AFfilehandle file, Track *track);
status setup(AFfilehandle file, Track *track);
status reset(AFfilehandle file, Track *track);
status sync(AFfilehandle file, Track *track);
int numModules() const { return m_modules.size(); }
const std::vector<SharedPtr<Module> > &modules() const;
const std::vector<SharedPtr<Chunk> > &chunks() const;
bool mustUseAtomicNVFrames() const { return true; }
void print();
bool fileModuleHandlesSeeking() const;
private:
std::vector<SharedPtr<Module> > m_modules;
std::vector<SharedPtr<Chunk> > m_chunks;
bool m_isDirty;
SharedPtr<FileModule> m_fileModule;
SharedPtr<Module> m_fileRebufferModule;
status initFileModule(AFfilehandle file, Track *track);
status arrange(AFfilehandle file, Track *track);
void addModule(Module *module);
void addConvertIntToInt(FormatCode input, FormatCode output);
void addConvertIntToFloat(FormatCode input, FormatCode output);
void addConvertFloatToInt(FormatCode input, FormatCode output,
const PCMInfo &inputMapping, const PCMInfo &outputMapping);
void addConvertFloatToFloat(FormatCode input, FormatCode output);
};
#endif
#ifndef SIMPLE_MODULE_H
#define SIMPLE_MODULE_H
#include <algorithm>
#include <cassert>
#include <climits>
#include <functional>
class SimpleModule : public Module
{
public:
virtual void runPull() OVERRIDE;
virtual void runPush() OVERRIDE;
virtual void run(Chunk &inChunk, Chunk &outChunk) = 0;
};
struct SwapModule : public SimpleModule
{
public:
virtual const char *name() const OVERRIDE { return "swap"; }
virtual void describe() OVERRIDE
{
m_outChunk->f.byteOrder = m_inChunk->f.byteOrder == AF_BYTEORDER_BIGENDIAN ?
AF_BYTEORDER_LITTLEENDIAN : AF_BYTEORDER_BIGENDIAN;
}
virtual void run(Chunk &inChunk, Chunk &outChunk) OVERRIDE
{
switch (m_inChunk->f.bytesPerSample(false))
{
case 2:
run<2, int16_t>(inChunk, outChunk); break;
case 3:
run<3, char>(inChunk, outChunk); break;
case 4:
run<4, int32_t>(inChunk, outChunk); break;
case 8:
run<8, int64_t>(inChunk, outChunk); break;
default:
assert(false); break;
}
}
private:
template <int N, typename T>
void run(Chunk &inChunk, Chunk &outChunk)
{
int sampleCount = inChunk.f.channelCount * inChunk.frameCount;
runSwap<N, T>(reinterpret_cast<const T *>(inChunk.buffer),
reinterpret_cast<T *>(outChunk.buffer),
sampleCount);
}
template <int N, typename T>
void runSwap(const T *input, T *output, int sampleCount)
{
for (int i=0; i<sampleCount; i++)
output[i] = byteswap(input[i]);
}
};
template <>
inline void SwapModule::runSwap<3, char>(const char *input, char *output, int count)
{
for (int i=0; i<count; i++)
{
output[3*i] = input[3*i+2];
output[3*i+1] = input[3*i+1];
output[3*i+2] = input[3*i];
}
}
template <typename UnaryFunction>
void transform(const void *srcData, void *dstData, size_t count)
{
typedef typename UnaryFunction::argument_type InputType;
typedef typename UnaryFunction::result_type OutputType;
const InputType *src = reinterpret_cast<const InputType *>(srcData);
OutputType *dst = reinterpret_cast<OutputType *>(dstData);
std::transform(src, src + count, dst, UnaryFunction());
}
template <FormatCode>
struct IntTypes;
template <>
struct IntTypes<kInt8> { typedef int8_t SignedType; typedef uint8_t UnsignedType; };
template <>
struct IntTypes<kInt16> { typedef int16_t SignedType; typedef uint16_t UnsignedType; };
template <>
struct IntTypes<kInt24> { typedef int32_t SignedType; typedef uint32_t UnsignedType; };
template <>
struct IntTypes<kInt32> { typedef int32_t SignedType; typedef uint32_t UnsignedType; };
template <FormatCode Format>
struct signConverter
{
typedef typename IntTypes<Format>::SignedType SignedType;
typedef typename IntTypes<Format>::UnsignedType UnsignedType;
static const int kScaleBits = (Format + 1) * CHAR_BIT - 1;
static const int kMaxSignedValue = (((1 << (kScaleBits - 1)) - 1) << 1) + 1;
static const int kMinSignedValue = -kMaxSignedValue - 1;
struct signedToUnsigned : public std::unary_function<SignedType, UnsignedType>
{
UnsignedType operator()(SignedType x) { return x - kMinSignedValue; }
};
struct unsignedToSigned : public std::unary_function<SignedType, UnsignedType>
{
SignedType operator()(UnsignedType x) { return x + kMinSignedValue; }
};
};
class ConvertSign : public SimpleModule
{
public:
ConvertSign(FormatCode format, bool fromSigned) :
m_format(format),
m_fromSigned(fromSigned)
{
}
virtual const char *name() const OVERRIDE { return "sign"; }
virtual void describe() OVERRIDE
{
const int scaleBits = m_inChunk->f.bytesPerSample(false) * CHAR_BIT;
m_outChunk->f.sampleFormat =
m_fromSigned ? AF_SAMPFMT_UNSIGNED : AF_SAMPFMT_TWOSCOMP;
double shift = -(1 << (scaleBits - 1));
if (m_fromSigned)
shift = -shift;
m_outChunk->f.pcm.intercept += shift;
m_outChunk->f.pcm.minClip += shift;
m_outChunk->f.pcm.maxClip += shift;
}
virtual void run(Chunk &input, Chunk &output) OVERRIDE
{
size_t count = input.frameCount * m_inChunk->f.channelCount;
if (m_fromSigned)
convertSignedToUnsigned(input.buffer, output.buffer, count);
else
convertUnsignedToSigned(input.buffer, output.buffer, count);
}
private:
FormatCode m_format;
bool m_fromSigned;
template <FormatCode Format>
static void convertSignedToUnsigned(const void *src, void *dst, size_t count)
{
transform<typename signConverter<Format>::signedToUnsigned>(src, dst, count);
}
void convertSignedToUnsigned(const void *src, void *dst, size_t count)
{
switch (m_format)
{
case kInt8:
convertSignedToUnsigned<kInt8>(src, dst, count);
break;
case kInt16:
convertSignedToUnsigned<kInt16>(src, dst, count);
break;
case kInt24:
convertSignedToUnsigned<kInt24>(src, dst, count);
break;
case kInt32:
convertSignedToUnsigned<kInt32>(src, dst, count);
break;
default:
assert(false);
}
}
template <FormatCode Format>
static void convertUnsignedToSigned(const void *src, void *dst, size_t count)
{
transform<typename signConverter<Format>::unsignedToSigned>(src, dst, count);
}
void convertUnsignedToSigned(const void *src, void *dst, size_t count)
{
switch (m_format)
{
case kInt8:
convertUnsignedToSigned<kInt8>(src, dst, count);
break;
case kInt16:
convertUnsignedToSigned<kInt16>(src, dst, count);
break;
case kInt24:
convertUnsignedToSigned<kInt24>(src, dst, count);
break;
case kInt32:
convertUnsignedToSigned<kInt32>(src, dst, count);
break;
default:
assert(false);
}
}
};
struct Expand3To4Module : public SimpleModule
{
public:
Expand3To4Module(bool isSigned) : m_isSigned(isSigned)
{
}
virtual const char *name() const OVERRIDE { return "expand3to4"; }
virtual void describe() OVERRIDE
{
m_outChunk->f.packed = false;
}
virtual void run(Chunk &inChunk, Chunk &outChunk) OVERRIDE
{
int count = inChunk.f.channelCount * inChunk.frameCount;
if (m_isSigned)
run<int32_t>(reinterpret_cast<const uint8_t *>(inChunk.buffer),
reinterpret_cast<int32_t *>(outChunk.buffer),
count);
else
run<uint32_t>(reinterpret_cast<const uint8_t *>(inChunk.buffer),
reinterpret_cast<uint32_t *>(outChunk.buffer),
count);
}
private:
bool m_isSigned;
template <typename T>
void run(const uint8_t *input, T *output, int sampleCount)
{
for (int i=0; i<sampleCount; i++)
{
T t =
#ifdef WORDS_BIGENDIAN
(input[3*i] << 24) |
(input[3*i+1] << 16) |
input[3*i+2] << 8;
#else
(input[3*i+2] << 24) |
(input[3*i+1] << 16) |
input[3*i] << 8;
#endif
output[i] = t >> 8;
}
}
};
struct Compress4To3Module : public SimpleModule
{
public:
Compress4To3Module(bool isSigned) : m_isSigned(isSigned)
{
}
virtual const char *name() const OVERRIDE { return "compress4to3"; }
virtual void describe() OVERRIDE
{
m_outChunk->f.packed = true;
}
virtual void run(Chunk &inChunk, Chunk &outChunk) OVERRIDE
{
int count = inChunk.f.channelCount * inChunk.frameCount;
if (m_isSigned)
run<int32_t>(inChunk.buffer, outChunk.buffer, count);
else
run<uint32_t>(inChunk.buffer, outChunk.buffer, count);
}
private:
bool m_isSigned;
template <typename T>
void run(const void *input, void *output, int count)
{
const T *in = reinterpret_cast<const T *>(input);
uint8_t *out = reinterpret_cast<uint8_t *>(output);
for (int i=0; i<count; i++)
{
uint8_t c0, c1, c2;
extract3(in[i], c0, c1, c2);
out[3*i] = c0;
out[3*i+1] = c1;
out[3*i+2] = c2;
}
}
template <typename T>
void extract3(T in, uint8_t &c0, uint8_t &c1, uint8_t &c2)
{
#ifdef WORDS_BIGENDIAN
c0 = (in >> 16) & 0xff;
c1 = (in >> 8) & 0xff;
c2 = in & 0xff;
#else
c2 = (in >> 16) & 0xff;
c1 = (in >> 8) & 0xff;
c0 = in & 0xff;
#endif
}
};
template <typename Arg, typename Result>
struct intToFloat : public std::unary_function<Arg, Result>
{
Result operator()(Arg x) const { return x; }
};
struct ConvertIntToFloat : public SimpleModule
{
ConvertIntToFloat(FormatCode inFormat, FormatCode outFormat) :
m_inFormat(inFormat), m_outFormat(outFormat)
{
}
virtual const char *name() const OVERRIDE { return "intToFloat"; }
virtual void describe() OVERRIDE
{
m_outChunk->f.sampleFormat = m_outFormat == kDouble ?
AF_SAMPFMT_DOUBLE : AF_SAMPFMT_FLOAT;
m_outChunk->f.sampleWidth = m_outFormat == kDouble ? 64 : 32;
}
virtual void run(Chunk &inChunk, Chunk &outChunk) OVERRIDE
{
const void *src = inChunk.buffer;
void *dst = outChunk.buffer;
int count = inChunk.frameCount * inChunk.f.channelCount;
if (m_outFormat == kFloat)
{
switch (m_inFormat)
{
case kInt8:
run<int8_t, float>(src, dst, count); break;
case kInt16:
run<int16_t, float>(src, dst, count); break;
case kInt24:
case kInt32:
run<int32_t, float>(src, dst, count); break;
default:
assert(false);
}
}
else if (m_outFormat == kDouble)
{
switch (m_inFormat)
{
case kInt8:
run<int8_t, double>(src, dst, count); break;
case kInt16:
run<int16_t, double>(src, dst, count); break;
case kInt24:
case kInt32:
run<int32_t, double>(src, dst, count); break;
default:
assert(false);
}
}
}
private:
FormatCode m_inFormat, m_outFormat;
template <typename Arg, typename Result>
static void run(const void *src, void *dst, int count)
{
transform<intToFloat<Arg, Result> >(src, dst, count);
}
};
template <typename Arg, typename Result, unsigned shift>
struct lshift : public std::unary_function<Arg, Result>
{
Result operator()(const Arg &x) const { return x << shift; }
};
template <typename Arg, typename Result, unsigned shift>
struct rshift : public std::unary_function<Arg, Result>
{
Result operator()(const Arg &x) const { return x >> shift; }
};
struct ConvertInt : public SimpleModule
{
ConvertInt(FormatCode inFormat, FormatCode outFormat) :
m_inFormat(inFormat),
m_outFormat(outFormat)
{
assert(isInteger(m_inFormat));
assert(isInteger(m_outFormat));
}
virtual const char *name() const OVERRIDE { return "convertInt"; }
virtual void describe() OVERRIDE
{
getDefaultPCMMapping(m_outChunk->f.sampleWidth,
m_outChunk->f.pcm.slope,
m_outChunk->f.pcm.intercept,
m_outChunk->f.pcm.minClip,
m_outChunk->f.pcm.maxClip);
}
virtual void run(Chunk &inChunk, Chunk &outChunk) OVERRIDE
{
const void *src = inChunk.buffer;
void *dst = outChunk.buffer;
size_t count = inChunk.frameCount * inChunk.f.channelCount;
#define MASK(N, M) (((N)<<3) | (M))
#define HANDLE(N, M) \
case MASK(N, M): convertInt<N, M>(src, dst, count); break;
switch (MASK(m_inFormat, m_outFormat))
{
HANDLE(kInt8, kInt16)
HANDLE(kInt8, kInt24)
HANDLE(kInt8, kInt32)
HANDLE(kInt16, kInt8)
HANDLE(kInt16, kInt24)
HANDLE(kInt16, kInt32)
HANDLE(kInt24, kInt8)
HANDLE(kInt24, kInt16)
HANDLE(kInt24, kInt32)
HANDLE(kInt32, kInt8)
HANDLE(kInt32, kInt16)
HANDLE(kInt32, kInt24)
}
#undef MASK
#undef HANDLE
}
private:
FormatCode m_inFormat, m_outFormat;
void getDefaultPCMMapping(int &bits, double &slope, double &intercept,
double &minClip, double &maxClip)
{
bits = (m_outFormat + 1) * CHAR_BIT;
slope = (1LL << (bits - 1));
intercept = 0;
minClip = -(1 << (bits - 1));
maxClip = (1LL << (bits - 1)) - 1;
}
static bool isInteger(FormatCode code)
{
return code >= kInt8 && code <= kInt32;
}
template <FormatCode Input, FormatCode Output, bool = (Input > Output)>
struct shift;
template <FormatCode Input, FormatCode Output>
struct shift<Input, Output, true> :
public rshift<typename IntTypes<Input>::SignedType,
typename IntTypes<Output>::SignedType,
(Input - Output) * CHAR_BIT>
{
};
template <FormatCode Input, FormatCode Output>
struct shift<Input, Output, false> :
public lshift<typename IntTypes<Input>::SignedType,
typename IntTypes<Output>::SignedType,
(Output - Input) * CHAR_BIT>
{
};
template <FormatCode Input, FormatCode Output>
static void convertInt(const void *src, void *dst, int count)
{
transform<shift<Input, Output> >(src, dst, count);
}
};
template <typename Arg, typename Result>
struct floatToFloat : public std::unary_function<Arg, Result>
{
Result operator()(Arg x) const { return x; }
};
struct ConvertFloat : public SimpleModule
{
ConvertFloat(FormatCode inFormat, FormatCode outFormat) :
m_inFormat(inFormat), m_outFormat(outFormat)
{
assert((m_inFormat == kFloat && m_outFormat == kDouble) ||
(m_inFormat == kDouble && m_outFormat == kFloat));
}
virtual const char *name() const OVERRIDE { return "convertFloat"; }
virtual void describe() OVERRIDE
{
switch (m_outFormat)
{
case kFloat:
m_outChunk->f.sampleFormat = AF_SAMPFMT_FLOAT;
m_outChunk->f.sampleWidth = 32;
break;
case kDouble:
m_outChunk->f.sampleFormat = AF_SAMPFMT_DOUBLE;
m_outChunk->f.sampleWidth = 64;
break;
default:
assert(false);
}
}
virtual void run(Chunk &inChunk, Chunk &outChunk) OVERRIDE
{
const void *src = inChunk.buffer;
void *dst = outChunk.buffer;
size_t count = inChunk.frameCount * inChunk.f.channelCount;
switch (m_outFormat)
{
case kFloat:
transform<floatToFloat<double, float> >(src, dst, count);
break;
case kDouble:
transform<floatToFloat<float, double> >(src, dst, count);
break;
default:
assert(false);
}
}
private:
FormatCode m_inFormat, m_outFormat;
};
struct Clip : public SimpleModule
{
Clip(FormatCode format, const PCMInfo &outputMapping) :
m_format(format),
m_outputMapping(outputMapping)
{
}
virtual const char *name() const OVERRIDE { return "clip"; }
virtual void describe() OVERRIDE
{
m_outChunk->f.pcm = m_outputMapping;
}
virtual void run(Chunk &inChunk, Chunk &outChunk) OVERRIDE
{
const void *src = inChunk.buffer;
void *dst = outChunk.buffer;
int count = inChunk.frameCount * inChunk.f.channelCount;
switch (m_format)
{
case kInt8:
run<int8_t>(src, dst, count); break;
case kInt16:
run<int16_t>(src, dst, count); break;
case kInt24:
case kInt32:
run<int32_t>(src, dst, count); break;
case kFloat:
run<float>(src, dst, count); break;
case kDouble:
run<double>(src, dst, count); break;
default:
assert(false);
}
}
private:
FormatCode m_format;
PCMInfo m_outputMapping;
template <typename T>
void run(const void *srcData, void *dstData, int count)
{
const T minValue = m_outputMapping.minClip;
const T maxValue = m_outputMapping.maxClip;
const T *src = reinterpret_cast<const T *>(srcData);
T *dst = reinterpret_cast<T *>(dstData);
for (int i=0; i<count; i++)
{
T t = src[i];
t = std::min(t, maxValue);
t = std::max(t, minValue);
dst[i] = t;
}
}
};
struct ConvertFloatToIntClip : public SimpleModule
{
ConvertFloatToIntClip(FormatCode inputFormat, FormatCode outputFormat,
const PCMInfo &inputMapping, const PCMInfo &outputMapping) :
m_inputFormat(inputFormat),
m_outputFormat(outputFormat),
m_inputMapping(inputMapping),
m_outputMapping(outputMapping)
{
assert(m_inputFormat == kFloat || m_inputFormat == kDouble);
assert(m_outputFormat == kInt8 ||
m_outputFormat == kInt16 ||
m_outputFormat == kInt24 ||
m_outputFormat == kInt32);
}
virtual const char *name() const OVERRIDE { return "convertPCMMapping"; }
virtual void describe() OVERRIDE
{
m_outChunk->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
m_outChunk->f.sampleWidth = (m_outputFormat + 1) * CHAR_BIT;
m_outChunk->f.pcm = m_outputMapping;
}
virtual void run(Chunk &inChunk, Chunk &outChunk) OVERRIDE
{
const void *src = inChunk.buffer;
void *dst = outChunk.buffer;
int count = inChunk.frameCount * inChunk.f.channelCount;
if (m_inputFormat == kFloat)
{
switch (m_outputFormat)
{
case kInt8:
run<float, int8_t>(src, dst, count); break;
case kInt16:
run<float, int16_t>(src, dst, count); break;
case kInt24:
case kInt32:
run<float, int32_t>(src, dst, count); break;
default:
assert(false);
}
}
else if (m_inputFormat == kDouble)
{
switch (m_outputFormat)
{
case kInt8:
run<double, int8_t>(src, dst, count); break;
case kInt16:
run<double, int16_t>(src, dst, count); break;
case kInt24:
case kInt32:
run<double, int32_t>(src, dst, count); break;
default:
assert(false);
}
}
}
private:
FormatCode m_inputFormat, m_outputFormat;
PCMInfo m_inputMapping, m_outputMapping;
template <typename Input, typename Output>
void run(const void *srcData, void *dstData, int count)
{
const Input *src = reinterpret_cast<const Input *>(srcData);
Output *dst = reinterpret_cast<Output *>(dstData);
double m = m_outputMapping.slope / m_inputMapping.slope;
double b = m_outputMapping.intercept - m * m_inputMapping.intercept;
double minValue = m_outputMapping.minClip;
double maxValue = m_outputMapping.maxClip;
for (int i=0; i<count; i++)
{
double t = m * src[i] + b;
t = std::min(t, maxValue);
t = std::max(t, minValue);
dst[i] = static_cast<Output>(t);
}
}
};
struct ApplyChannelMatrix : public SimpleModule
{
public:
ApplyChannelMatrix(FormatCode format, bool isReading,
int inChannels, int outChannels,
double minClip, double maxClip, const double *matrix);
virtual ~ApplyChannelMatrix();
virtual const char *name() const OVERRIDE;
virtual void describe() OVERRIDE;
virtual void run(Chunk &inChunk, Chunk &outChunk) OVERRIDE;
private:
FormatCode m_format;
int m_inChannels, m_outChannels;
double m_minClip, m_maxClip;
double *m_matrix;
void initDefaultMatrix();
template <typename T>
void run(const void *input, void *output, int frameCount);
};
struct Transform : public SimpleModule
{
public:
Transform(FormatCode format,
const PCMInfo &inputMapping,
const PCMInfo &outputMapping) :
m_format(format),
m_inputMapping(inputMapping),
m_outputMapping(outputMapping)
{
assert(m_format == kFloat || m_format == kDouble);
}
virtual const char *name() const OVERRIDE { return "transform"; }
virtual void describe() OVERRIDE
{
m_outChunk->f.pcm = m_outputMapping;
}
virtual void run(Chunk &inChunk, Chunk &outChunk) OVERRIDE
{
int count = inChunk.frameCount * inChunk.f.channelCount;
if (m_format == kFloat)
run<float>(inChunk.buffer, outChunk.buffer, count);
else if (m_format == kDouble)
run<double>(inChunk.buffer, outChunk.buffer, count);
else
assert(false);
}
private:
FormatCode m_format;
PCMInfo m_inputMapping, m_outputMapping;
template <typename T>
void run(const void *srcData, void *dstData, int count)
{
const T *src = reinterpret_cast<const T *>(srcData);
T *dst = reinterpret_cast<T *>(dstData);
double m = m_outputMapping.slope / m_inputMapping.slope;
double b = m_outputMapping.intercept - m * m_inputMapping.intercept;
for (int i=0; i<count; i++)
dst[i] = m * src[i] + b;
}
};
#endif
#ifndef FILE_MODULE_H
#define FILE_MODULE_H
class FileModule : public Module
{
public:
virtual bool handlesSeeking() const { return false; }
virtual int bufferSize() const;
protected:
enum Mode { Compress, Decompress };
FileModule(Mode, Track *, File *fh, bool canSeek);
Mode mode() const { return m_mode; }
bool canSeek() const { return m_canSeek; }
ssize_t read(void *data, size_t nbytes);
ssize_t write(const void *data, size_t nbytes);
off_t seek(off_t offset);
off_t tell();
off_t length();
private:
Mode m_mode;
protected:
Track *m_track;
void reportReadError(AFframecount framesRead, AFframecount framesRequested);
void reportWriteError(AFframecount framesWritten, AFframecount framesRequested);
private:
File *m_fh;
bool m_canSeek;
};
#endif
#ifndef REBUFFER_MODULE_H
#define REBUFFER_MODULE_H
class RebufferModule : public Module
{
public:
enum Direction
{
FixedToVariable,
VariableToFixed
};
RebufferModule(Direction, int bytesPerFrame, int numFrames, bool multipleOf);
virtual ~RebufferModule();
virtual const char *name() const OVERRIDE { return "rebuffer"; }
virtual void maxPull() OVERRIDE;
virtual void maxPush() OVERRIDE;
virtual void runPull() OVERRIDE;
virtual void reset1() OVERRIDE;
virtual void reset2() OVERRIDE;
virtual void runPush() OVERRIDE;
virtual void sync1() OVERRIDE;
virtual void sync2() OVERRIDE;
private:
Direction m_direction;
int m_bytesPerFrame;
int m_numFrames;
bool m_multipleOf;
bool m_eof;
bool m_sentShortChunk;
char *m_buffer;
int m_offset;
char *m_savedBuffer;
int m_savedOffset;
void initFixedToVariable();
void initVariableToFixed();
};
#endif
#ifndef BlockCodec_h
#define BlockCodec_h
class BlockCodec : public FileModule
{
public:
virtual void runPull() OVERRIDE;
virtual void reset1() OVERRIDE;
virtual void reset2() OVERRIDE;
virtual void runPush() OVERRIDE;
virtual void sync1() OVERRIDE;
virtual void sync2() OVERRIDE;
protected:
int m_bytesPerPacket, m_framesPerPacket;
AFframecount m_framesToIgnore;
AFfileoffset m_savedPositionNextFrame;
AFframecount m_savedNextFrame;
BlockCodec(Mode, Track *, File *, bool canSeek);
virtual int decodeBlock(const uint8_t *encoded, int16_t *decoded) = 0;
virtual int encodeBlock(const int16_t *decoded, uint8_t *encoded) = 0;
};
#endif
#include <assert.h>
BlockCodec::BlockCodec(Mode mode, Track *track, File *fh, bool canSeek) :
FileModule(mode, track, fh, canSeek),
m_bytesPerPacket(-1),
m_framesPerPacket(-1),
m_framesToIgnore(-1),
m_savedPositionNextFrame(-1),
m_savedNextFrame(-1)
{
m_framesPerPacket = track->f.framesPerPacket;
m_bytesPerPacket = track->f.bytesPerPacket;
}
void BlockCodec::runPull()
{
AFframecount framesToRead = m_outChunk->frameCount;
AFframecount framesRead = 0;
assert(framesToRead % m_framesPerPacket == 0);
int blockCount = framesToRead / m_framesPerPacket;
ssize_t bytesRead = read(m_inChunk->buffer, m_bytesPerPacket * blockCount);
int blocksRead = bytesRead >= 0 ? bytesRead / m_bytesPerPacket : 0;
for (int i=0; i<blocksRead; i++)
{
decodeBlock(static_cast<const uint8_t *>(m_inChunk->buffer) + i * m_bytesPerPacket,
static_cast<int16_t *>(m_outChunk->buffer) + i * m_framesPerPacket * m_track->f.channelCount);
framesRead += m_framesPerPacket;
}
m_track->nextfframe += framesRead;
assert(tell() == m_track->fpos_next_frame);
if (framesRead < framesToRead)
reportReadError(framesRead, framesToRead);
m_outChunk->frameCount = framesRead;
}
void BlockCodec::reset1()
{
AFframecount nextTrackFrame = m_track->nextfframe;
m_track->nextfframe = (nextTrackFrame / m_framesPerPacket) *
m_framesPerPacket;
m_framesToIgnore = nextTrackFrame - m_track->nextfframe;
}
void BlockCodec::reset2()
{
m_track->fpos_next_frame = m_track->fpos_first_frame +
m_bytesPerPacket * (m_track->nextfframe / m_framesPerPacket);
m_track->frames2ignore += m_framesToIgnore;
assert(m_track->nextfframe % m_framesPerPacket == 0);
}
void BlockCodec::runPush()
{
AFframecount framesToWrite = m_inChunk->frameCount;
int channelCount = m_inChunk->f.channelCount;
int blockCount = (framesToWrite + m_framesPerPacket - 1) / m_framesPerPacket;
for (int i=0; i<blockCount; i++)
{
encodeBlock(static_cast<const int16_t *>(m_inChunk->buffer) + i * m_framesPerPacket * channelCount,
static_cast<uint8_t *>(m_outChunk->buffer) + i * m_bytesPerPacket);
}
ssize_t bytesWritten = write(m_outChunk->buffer, m_bytesPerPacket * blockCount);
ssize_t blocksWritten = bytesWritten >= 0 ? bytesWritten / m_bytesPerPacket : 0;
AFframecount framesWritten = std::min((AFframecount) blocksWritten * m_framesPerPacket, framesToWrite);
m_track->nextfframe += framesWritten;
m_track->totalfframes = m_track->nextfframe;
assert(tell() == m_track->fpos_next_frame);
if (framesWritten < framesToWrite)
reportWriteError(framesWritten, framesToWrite);
}
void BlockCodec::sync1()
{
m_savedPositionNextFrame = m_track->fpos_next_frame;
m_savedNextFrame = m_track->nextfframe;
}
void BlockCodec::sync2()
{
assert(tell() == m_track->fpos_next_frame);
m_track->fpos_after_data = tell();
m_track->fpos_next_frame = m_savedPositionNextFrame;
m_track->nextfframe = m_savedNextFrame;
}
#include <errno.h>
#include <string.h>
FileModule::FileModule(Mode mode, Track *track, File *fh, bool canSeek) :
m_mode(mode),
m_track(track),
m_fh(fh),
m_canSeek(canSeek)
{
track->fpos_next_frame = track->fpos_first_frame;
track->frames2ignore = 0;
}
ssize_t FileModule::read(void *data, size_t nbytes)
{
ssize_t bytesRead = m_fh->read(data, nbytes);
if (bytesRead > 0)
{
m_track->fpos_next_frame += bytesRead;
}
return bytesRead;
}
ssize_t FileModule::write(const void *data, size_t nbytes)
{
ssize_t bytesWritten = m_fh->write(data, nbytes);
if (bytesWritten > 0)
{
m_track->fpos_next_frame += bytesWritten;
m_track->data_size += bytesWritten;
}
return bytesWritten;
}
off_t FileModule::seek(off_t offset)
{
return m_fh->seek(offset, File::SeekFromBeginning);
}
off_t FileModule::tell()
{
return m_fh->tell();
}
off_t FileModule::length()
{
return m_fh->length();
}
void FileModule::reportReadError(AFframecount framesRead,
AFframecount framesToRead)
{
if (!m_track->filemodhappy)
return;
_af_error(AF_BAD_READ,
"file missing data -- read %jd frames, should be %jd",
static_cast<intmax_t>(m_track->nextfframe),
static_cast<intmax_t>(m_track->totalfframes));
m_track->filemodhappy = false;
}
void FileModule::reportWriteError(AFframecount framesWritten,
AFframecount framesToWrite)
{
if (!m_track->filemodhappy)
return;
if (framesWritten < 0)
{
_af_error(AF_BAD_WRITE,
"unable to write data (%s) -- wrote %jd out of %jd frames",
strerror(errno),
static_cast<intmax_t>(m_track->nextfframe),
static_cast<intmax_t>(m_track->nextfframe + framesToWrite));
}
else
{
_af_error(AF_BAD_WRITE,
"unable to write data (disk full) -- "
"wrote %jd out of %jd frames",
static_cast<intmax_t>(m_track->nextfframe + framesWritten),
static_cast<intmax_t>(m_track->nextfframe + framesToWrite));
}
m_track->filemodhappy = false;
}
int FileModule::bufferSize() const
{
if (mode() == Compress)
return outChunk()->frameCount * inChunk()->f.bytesPerFrame(true);
else
return inChunk()->frameCount * outChunk()->f.bytesPerFrame(true);
}
#ifndef MODULES_G711_H
#define MODULES_G711_H
class File;
class FileModule;
struct AudioFormat;
struct Track;
bool _af_g711_format_ok (AudioFormat *f);
FileModule *_AFg711initcompress (Track *, File *, bool canSeek,
bool headerless, AFframecount *chunkframes);
FileModule *_AFg711initdecompress (Track *, File *, bool canSeek,
bool headerless, AFframecount *chunkframes);
#endif
#include <assert.h>
static void ulaw2linear_buf (const uint8_t *ulaw, int16_t *linear, int nsamples)
{
for (int i=0; i < nsamples; i++)
linear[i] = _af_ulaw2linear(ulaw[i]);
}
static void linear2ulaw_buf (const int16_t *linear, uint8_t *ulaw, int nsamples)
{
for (int i=0; i < nsamples; i++)
ulaw[i] = _af_linear2ulaw(linear[i]);
}
static void alaw2linear_buf (const uint8_t *alaw, int16_t *linear, int nsamples)
{
for (int i=0; i < nsamples; i++)
linear[i] = _af_alaw2linear(alaw[i]);
}
static void linear2alaw_buf (const int16_t *linear, uint8_t *alaw, int nsamples)
{
for (int i=0; i < nsamples; i++)
alaw[i] = _af_linear2alaw(linear[i]);
}
bool _af_g711_format_ok (AudioFormat *f)
{
if (f->sampleFormat != AF_SAMPFMT_TWOSCOMP || f->sampleWidth != 16)
{
_af_error(AF_BAD_COMPRESSION,
"G.711 compression requires 16-bit signed integer format");
return false;
}
if (f->byteOrder != _AF_BYTEORDER_NATIVE)
{
_af_error(AF_BAD_COMPRESSION,
"G.711 compression requires native byte order");
return false;
}
return true;
}
class G711 : public FileModule
{
public:
static G711 *createCompress(Track *trk, File *fh, bool canSeek,
bool headerless, AFframecount *chunkframes);
static G711 *createDecompress(Track *trk, File *fh, bool canSeek,
bool headerless, AFframecount *chunkframes);
virtual const char *name() const OVERRIDE
{
return mode() == Compress ? "g711compress" : "g711decompress";
}
virtual void describe() OVERRIDE;
virtual void runPull() OVERRIDE;
virtual void reset2() OVERRIDE;
virtual void runPush() OVERRIDE;
virtual void sync1() OVERRIDE;
virtual void sync2() OVERRIDE;
private:
G711(Mode mode, Track *track, File *fh, bool canSeek);
AFfileoffset m_savedPositionNextFrame;
AFframecount m_savedNextFrame;
};
G711::G711(Mode mode, Track *track, File *fh, bool canSeek) :
FileModule(mode, track, fh, canSeek),
m_savedPositionNextFrame(-1),
m_savedNextFrame(-1)
{
if (mode == Decompress)
track->f.compressionParams = AU_NULL_PVLIST;
}
G711 *G711::createCompress(Track *track, File *fh,
bool canSeek, bool headerless, AFframecount *chunkframes)
{
return new G711(Compress, track, fh, canSeek);
}
void G711::runPush()
{
AFframecount framesToWrite = m_inChunk->frameCount;
AFframecount samplesToWrite = m_inChunk->frameCount * m_inChunk->f.channelCount;
int framesize = m_inChunk->f.channelCount;
assert(m_track->f.compressionType == AF_COMPRESSION_G711_ULAW ||
m_track->f.compressionType == AF_COMPRESSION_G711_ALAW);
if (m_track->f.compressionType == AF_COMPRESSION_G711_ULAW)
linear2ulaw_buf(static_cast<const int16_t *>(m_inChunk->buffer),
static_cast<uint8_t *>(m_outChunk->buffer), samplesToWrite);
else
linear2alaw_buf(static_cast<const int16_t *>(m_inChunk->buffer),
static_cast<uint8_t *>(m_outChunk->buffer), samplesToWrite);
ssize_t bytesWritten = write(m_outChunk->buffer, framesize * framesToWrite);
AFframecount framesWritten = bytesWritten >= 0 ? bytesWritten / framesize : 0;
if (framesWritten != framesToWrite)
reportWriteError(framesWritten, framesToWrite);
m_track->nextfframe += framesWritten;
m_track->totalfframes = m_track->nextfframe;
assert(!canSeek() || (tell() == m_track->fpos_next_frame));
}
void G711::sync1()
{
m_savedPositionNextFrame = m_track->fpos_next_frame;
m_savedNextFrame = m_track->nextfframe;
}
void G711::sync2()
{
assert(!canSeek() || (tell() == m_track->fpos_next_frame));
m_track->fpos_after_data = tell();
m_track->fpos_next_frame = m_savedPositionNextFrame;
m_track->nextfframe = m_savedNextFrame;
}
void G711::describe()
{
if (mode() == Compress)
{
m_outChunk->f.compressionType = m_track->f.compressionType;
}
else
{
m_outChunk->f.byteOrder = _AF_BYTEORDER_NATIVE;
m_outChunk->f.compressionType = AF_COMPRESSION_NONE;
}
}
G711 *G711::createDecompress(Track *track, File *fh,
bool canSeek, bool headerless, AFframecount *chunkframes)
{
return new G711(Decompress, track, fh, canSeek);
}
void G711::runPull()
{
AFframecount framesToRead = m_outChunk->frameCount;
AFframecount samplesToRead = m_outChunk->frameCount * m_outChunk->f.channelCount;
int framesize = m_outChunk->f.channelCount;
ssize_t bytesRead = read(m_inChunk->buffer, framesize * framesToRead);
AFframecount framesRead = bytesRead >= 0 ? bytesRead / framesize : 0;
if (m_track->f.compressionType == AF_COMPRESSION_G711_ULAW)
ulaw2linear_buf(static_cast<const uint8_t *>(m_inChunk->buffer),
static_cast<int16_t *>(m_outChunk->buffer), samplesToRead);
else
alaw2linear_buf(static_cast<const uint8_t *>(m_inChunk->buffer),
static_cast<int16_t *>(m_outChunk->buffer), samplesToRead);
m_track->nextfframe += framesRead;
assert(!canSeek() || (tell() == m_track->fpos_next_frame));
if (m_track->totalfframes != -1 && framesRead != framesToRead)
reportReadError(framesRead, framesToRead);
m_outChunk->frameCount = framesRead;
}
void G711::reset2()
{
int framesize = m_inChunk->f.channelCount;
m_track->fpos_next_frame = m_track->fpos_first_frame +
framesize * m_track->nextfframe;
m_track->frames2ignore = 0;
}
FileModule *_AFg711initcompress(Track *track, File *fh, bool canSeek,
bool headerless, AFframecount *chunkFrames)
{
return G711::createCompress(track, fh, canSeek, headerless, chunkFrames);
}
FileModule *_AFg711initdecompress(Track *track, File *fh, bool canSeek,
bool headerless, AFframecount *chunkFrames)
{
return G711::createDecompress(track, fh, canSeek, headerless, chunkFrames);
}
Module::Module() :
m_sink(NULL)
{
}
Module::~Module()
{
}
void Module::setSink(Module *module) { m_sink = module; }
void Module::setSource(Module *module) { m_source = module; }
const char *Module::name() const { return ""; }
void Module::describe()
{
}
void Module::maxPull()
{
m_inChunk->frameCount = m_outChunk->frameCount;
}
void Module::maxPush()
{
m_outChunk->frameCount = m_inChunk->frameCount;
}
void Module::runPull()
{
}
void Module::runPush()
{
}
void Module::pull(size_t frames)
{
m_inChunk->frameCount = frames;
m_source->runPull();
}
void Module::push(size_t frames)
{
m_outChunk->frameCount = frames;
m_sink->runPush();
}
#include <algorithm>
#include <cassert>
#include <cmath>
#include <functional>
#include <stdio.h>
ModuleState::ModuleState() :
m_isDirty(true)
{
}
ModuleState::~ModuleState()
{
}
status ModuleState::initFileModule(AFfilehandle file, Track *track)
{
const CompressionUnit *unit = _af_compression_unit_from_id(track->f.compressionType);
if (!unit)
return AF_FAIL;
if (!unit->fmtok(&track->f))
return AF_FAIL;
if (file->m_seekok &&
file->m_fh->seek(track->fpos_first_frame, File::SeekFromBeginning) !=
track->fpos_first_frame)
{
_af_error(AF_BAD_LSEEK, "unable to position file handle at beginning of sound data");
return AF_FAIL;
}
AFframecount chunkFrames;
if (file->m_access == _AF_READ_ACCESS)
m_fileModule = unit->initdecompress(track, file->m_fh, file->m_seekok,
file->m_fileFormat == AF_FILE_RAWDATA, &chunkFrames);
else
m_fileModule = unit->initcompress(track, file->m_fh, file->m_seekok,
file->m_fileFormat == AF_FILE_RAWDATA, &chunkFrames);
if (unit->needsRebuffer)
{
assert(unit->nativeSampleFormat == AF_SAMPFMT_TWOSCOMP);
RebufferModule::Direction direction =
file->m_access == _AF_WRITE_ACCESS ?
RebufferModule::VariableToFixed : RebufferModule::FixedToVariable;
m_fileRebufferModule = new RebufferModule(direction,
track->f.bytesPerFrame(false), chunkFrames,
unit->multiple_of);
}
track->filemodhappy = true;
return AF_SUCCEED;
}
status ModuleState::init(AFfilehandle file, Track *track)
{
if (initFileModule(file, track) == AF_FAIL)
return AF_FAIL;
return AF_SUCCEED;
}
bool ModuleState::fileModuleHandlesSeeking() const
{
return m_fileModule->handlesSeeking();
}
status ModuleState::setup(AFfilehandle file, Track *track)
{
AFframecount fframepos = std::llrint(track->nextvframe * track->f.sampleRate / track->v.sampleRate);
bool isReading = file->m_access == _AF_READ_ACCESS;
if (!track->v.isUncompressed())
{
_af_error(AF_BAD_NOT_IMPLEMENTED,
"library does not support compression in virtual format yet");
return AF_FAIL;
}
if (arrange(file, track) == AF_FAIL)
return AF_FAIL;
track->filemodhappy = true;
int maxbufsize = 0;
if (isReading)
{
m_chunks.back()->frameCount = _AF_ATOMIC_NVFRAMES;
for (int i=m_modules.size() - 1; i >= 0; i--)
{
SharedPtr<Chunk> inChunk = m_chunks[i];
SharedPtr<Chunk> outChunk = m_chunks[i+1];
int bufsize = outChunk->frameCount * outChunk->f.bytesPerFrame(true);
if (bufsize > maxbufsize)
maxbufsize = bufsize;
if (i != 0)
m_modules[i]->setSource(m_modules[i-1].get());
m_modules[i]->maxPull();
}
if (!track->filemodhappy)
return AF_FAIL;
int bufsize = m_fileModule->bufferSize();
if (bufsize > maxbufsize)
maxbufsize = bufsize;
}
else
{
m_chunks.front()->frameCount = _AF_ATOMIC_NVFRAMES;
for (size_t i=0; i<m_modules.size(); i++)
{
SharedPtr<Chunk> inChunk = m_chunks[i];
SharedPtr<Chunk> outChunk = m_chunks[i+1];
int bufsize = inChunk->frameCount * inChunk->f.bytesPerFrame(true);
if (bufsize > maxbufsize)
maxbufsize = bufsize;
if (i != m_modules.size() - 1)
m_modules[i]->setSink(m_modules[i+1].get());
m_modules[i]->maxPush();
}
if (!track->filemodhappy)
return AF_FAIL;
int bufsize = m_fileModule->bufferSize();
if (bufsize > maxbufsize)
maxbufsize = bufsize;
}
for (size_t i=0; i<m_chunks.size(); i++)
{
if ((isReading && i==m_chunks.size() - 1) || (!isReading && i==0))
continue;
m_chunks[i]->allocate(maxbufsize);
}
if (isReading)
{
if (track->totalfframes == -1)
track->totalvframes = -1;
else
track->totalvframes = std::llrint(track->totalfframes *
(track->v.sampleRate / track->f.sampleRate));
track->nextfframe = fframepos;
track->nextvframe = std::llrint(fframepos * track->v.sampleRate / track->f.sampleRate);
m_isDirty = false;
if (reset(file, track) == AF_FAIL)
return AF_FAIL;
}
else
{
track->nextvframe = track->totalvframes =
(AFframecount) (fframepos * track->v.sampleRate / track->f.sampleRate);
m_isDirty = false;
}
return AF_SUCCEED;
}
const std::vector<SharedPtr<Module> > &ModuleState::modules() const
{
return m_modules;
}
const std::vector<SharedPtr<Chunk> > &ModuleState::chunks() const
{
return m_chunks;
}
status ModuleState::reset(AFfilehandle file, Track *track)
{
track->filemodhappy = true;
for (std::vector<SharedPtr<Module> >::reverse_iterator i=m_modules.rbegin();
i != m_modules.rend(); ++i)
(*i)->reset1();
track->frames2ignore = 0;
if (!track->filemodhappy)
return AF_FAIL;
for (std::vector<SharedPtr<Module> >::iterator i=m_modules.begin();
i != m_modules.end(); ++i)
(*i)->reset2();
if (!track->filemodhappy)
return AF_FAIL;
return AF_SUCCEED;
}
status ModuleState::sync(AFfilehandle file, Track *track)
{
track->filemodhappy = true;
for (std::vector<SharedPtr<Module> >::reverse_iterator i=m_modules.rbegin();
i != m_modules.rend(); ++i)
(*i)->sync1();
if (!track->filemodhappy)
return AF_FAIL;
for (std::vector<SharedPtr<Module> >::iterator i=m_modules.begin();
i != m_modules.end(); ++i)
(*i)->sync2();
return AF_SUCCEED;
}
static const PCMInfo * const intmappings[6] =
{
&_af_default_signed_integer_pcm_mappings[1],
&_af_default_signed_integer_pcm_mappings[2],
&_af_default_signed_integer_pcm_mappings[3],
&_af_default_signed_integer_pcm_mappings[4],
NULL,
NULL
};
static FormatCode getFormatCode(const AudioFormat &format)
{
if (format.sampleFormat == AF_SAMPFMT_FLOAT)
return kFloat;
if (format.sampleFormat == AF_SAMPFMT_DOUBLE)
return kDouble;
if (format.isInteger())
{
switch (format.bytesPerSample(false))
{
case 1: return kInt8;
case 2: return kInt16;
case 3: return kInt24;
case 4: return kInt32;
}
}
assert(false);
return kUndefined;
}
static bool isInteger(FormatCode code) { return code >= kInt8 && code <= kInt32; }
static bool isFloat(FormatCode code) { return code >= kFloat && code <= kDouble; }
static bool isTrivialIntMapping(const AudioFormat &format, FormatCode code)
{
return intmappings[code] != NULL &&
format.pcm.slope == intmappings[code]->slope &&
format.pcm.intercept == intmappings[code]->intercept;
}
static bool isTrivialIntClip(const AudioFormat &format, FormatCode code)
{
return intmappings[code] != NULL &&
format.pcm.minClip == intmappings[code]->minClip &&
format.pcm.maxClip == intmappings[code]->maxClip;
}
status ModuleState::arrange(AFfilehandle file, Track *track)
{
bool isReading = file->m_access == _AF_READ_ACCESS;
AudioFormat in, out;
if (isReading)
{
in = track->f;
out = track->v;
}
else
{
in = track->v;
out = track->f;
}
FormatCode infc = getFormatCode(in);
FormatCode outfc = getFormatCode(out);
if (infc == kUndefined || outfc == kUndefined)
return AF_FAIL;
m_chunks.clear();
m_chunks.push_back(new Chunk());
m_chunks.back()->f = in;
m_modules.clear();
if (isReading)
{
addModule(m_fileModule.get());
addModule(m_fileRebufferModule.get());
}
if (in.byteOrder != _AF_BYTEORDER_NATIVE)
{
size_t bytesPerSample = in.bytesPerSample(!isReading);
if (bytesPerSample > 1 && in.compressionType == AF_COMPRESSION_NONE)
addModule(new SwapModule());
else
in.byteOrder = _AF_BYTEORDER_NATIVE;
}
if (in.isInteger() && in.bytesPerSample(false) == 3)
{
if (isReading || in.compressionType != AF_COMPRESSION_NONE)
addModule(new Expand3To4Module(in.isSigned()));
}
if (in.isUnsigned())
addModule(new ConvertSign(infc, false));
in.pcm = m_chunks.back()->f.pcm;
if (out.isUnsigned())
{
const double shift = intmappings[outfc]->minClip;
out.pcm.intercept += shift;
out.pcm.minClip += shift;
out.pcm.maxClip += shift;
}
if (in.pcm.minClip < in.pcm.maxClip && !isTrivialIntClip(in, infc))
addModule(new Clip(infc, in.pcm));
bool alreadyClippedOutput = false;
bool alreadyTransformedOutput = false;
bool transforming = (in.pcm.slope != out.pcm.slope ||
in.pcm.intercept != out.pcm.intercept) &&
!(isTrivialIntMapping(in, infc) &&
isTrivialIntMapping(out, outfc));
if (isInteger(infc) && transforming)
{
if (infc == kInt32 || outfc == kDouble || outfc == kInt32)
{
addConvertIntToFloat(infc, kDouble);
infc = kDouble;
}
else
{
addConvertIntToFloat(infc, kFloat);
infc = kFloat;
}
}
if (transforming && infc == kDouble && isFloat(outfc))
addModule(new Transform(infc, in.pcm, out.pcm));
if (isInteger(infc) && isInteger(outfc))
addConvertIntToInt(infc, outfc);
else if (isInteger(infc) && isFloat(outfc))
addConvertIntToFloat(infc, outfc);
else if (isFloat(infc) && isInteger(outfc))
{
addConvertFloatToInt(infc, outfc, in.pcm, out.pcm);
alreadyClippedOutput = true;
alreadyTransformedOutput = true;
}
else if (isFloat(infc) && isFloat(outfc))
addConvertFloatToFloat(infc, outfc);
if (transforming && !alreadyTransformedOutput && infc != kDouble)
addModule(new Transform(outfc, in.pcm, out.pcm));
if (in.channelCount != out.channelCount)
addModule(new ApplyChannelMatrix(outfc, isReading,
in.channelCount, out.channelCount,
in.pcm.minClip, in.pcm.maxClip,
track->channelMatrix));
if (!alreadyClippedOutput)
{
if (out.pcm.minClip < out.pcm.maxClip && !isTrivialIntClip(out, outfc))
addModule(new Clip(outfc, out.pcm));
}
if (out.isUnsigned())
addModule(new ConvertSign(outfc, true));
if (out.isInteger() && out.bytesPerSample(false) == 3)
{
if (!isReading || out.compressionType != AF_COMPRESSION_NONE)
addModule(new Compress4To3Module(out.isSigned()));
}
if (out.byteOrder != _AF_BYTEORDER_NATIVE)
{
size_t bytesPerSample = out.bytesPerSample(isReading);
if (bytesPerSample > 1 && out.compressionType == AF_COMPRESSION_NONE)
addModule(new SwapModule());
else
out.byteOrder = _AF_BYTEORDER_NATIVE;
}
if (!isReading)
{
addModule(m_fileRebufferModule.get());
addModule(m_fileModule.get());
}
return AF_SUCCEED;
}
void ModuleState::addModule(Module *module)
{
if (!module)
return;
m_modules.push_back(module);
module->setInChunk(m_chunks.back().get());
Chunk *chunk = new Chunk();
chunk->f = m_chunks.back()->f;
m_chunks.push_back(chunk);
module->setOutChunk(chunk);
module->describe();
}
void ModuleState::addConvertIntToInt(FormatCode input, FormatCode output)
{
if (input == output)
return;
assert(isInteger(input));
assert(isInteger(output));
addModule(new ConvertInt(input, output));
}
void ModuleState::addConvertIntToFloat(FormatCode input, FormatCode output)
{
addModule(new ConvertIntToFloat(input, output));
}
void ModuleState::addConvertFloatToInt(FormatCode input, FormatCode output,
const PCMInfo &inputMapping, const PCMInfo &outputMapping)
{
addModule(new ConvertFloatToIntClip(input, output, inputMapping, outputMapping));
}
void ModuleState::addConvertFloatToFloat(FormatCode input, FormatCode output)
{
if (input == output)
return;
assert((input == kFloat && output == kDouble) ||
(input == kDouble && output == kFloat));
addModule(new ConvertFloat(input, output));
}
void ModuleState::print()
{
fprintf(stderr, "modules:\n");
for (size_t i=0; i<m_modules.size(); i++)
fprintf(stderr, " %s (%p) in %p out %p\n",
m_modules[i]->name(), m_modules[i].get(),
m_modules[i]->inChunk(),
m_modules[i]->outChunk());
fprintf(stderr, "chunks:\n");
for (size_t i=0; i<m_chunks.size(); i++)
fprintf(stderr, " %p %s\n",
m_chunks[i].get(),
m_chunks[i]->f.description().c_str());
}
#ifndef MSADPCM_H
#define MSADPCM_H
class File;
class FileModule;
struct AudioFormat;
struct Track;
bool _af_ms_adpcm_format_ok (AudioFormat *f);
FileModule *_af_ms_adpcm_init_decompress(Track *, File *,
bool canSeek, bool headerless, AFframecount *chunkframes);
FileModule *_af_ms_adpcm_init_compress(Track *, File *,
bool canSeek, bool headerless, AFframecount *chunkframes);
#endif
#include <assert.h>
#include <cstdlib>
#include <limits>
#include <string.h>
struct ms_adpcm_state
{
uint8_t predictorIndex;
int delta;
int16_t sample1, sample2;
ms_adpcm_state()
{
predictorIndex = 0;
delta = 16;
sample1 = 0;
sample2 = 0;
}
};
class MSADPCM : public BlockCodec
{
public:
static MSADPCM *createDecompress(Track *, File *, bool canSeek,
bool headerless, AFframecount *chunkFrames);
static MSADPCM *createCompress(Track *, File *, bool canSeek,
bool headerless, AFframecount *chunkFrames);
virtual ~MSADPCM();
bool initializeCoefficients();
virtual const char *name() const OVERRIDE
{
return mode() == Compress ? "ms_adpcm_compress" : "ms_adpcm_decompress";
}
virtual void describe() OVERRIDE;
private:
int m_numCoefficients;
int16_t m_coefficients[256][2];
ms_adpcm_state *m_state;
MSADPCM(Mode mode, Track *track, File *fh, bool canSeek);
int decodeBlock(const uint8_t *encoded, int16_t *decoded) OVERRIDE;
int encodeBlock(const int16_t *decoded, uint8_t *encoded) OVERRIDE;
void choosePredictorForBlock(const int16_t *decoded);
};
static inline int clamp(int x, int low, int high)
{
if (x < low) return low;
if (x > high) return high;
return x;
}
static const int16_t adaptationTable[] =
{
230, 230, 230, 230, 307, 409, 512, 614,
768, 614, 512, 409, 307, 230, 230, 230
};
static int16_t decodeSample(ms_adpcm_state &state,
uint8_t code, const int16_t *coefficient)
{
int linearSample = (state.sample1 * coefficient[0] +
state.sample2 * coefficient[1]) >> 8;
linearSample += ((code & 0x08) ? (code - 0x10) : code) * state.delta;
linearSample = clamp(linearSample, MIN_INT16, MAX_INT16);
int delta = (state.delta * adaptationTable[code]) >> 8;
if (delta < 16)
delta = 16;
state.delta = delta;
state.sample2 = state.sample1;
state.sample1 = linearSample;
return static_cast<int16_t>(linearSample);
}
static uint8_t encodeSample(ms_adpcm_state &state, int16_t sample,
const int16_t *coefficient)
{
int predictor = (state.sample1 * coefficient[0] +
state.sample2 * coefficient[1]) >> 8;
int code = sample - predictor;
int bias = state.delta / 2;
if (code < 0)
bias = -bias;
code = (code + bias) / state.delta;
code = clamp(code, -8, 7) & 0xf;
predictor += ((code & 0x8) ? (code - 0x10) : code) * state.delta;
state.sample2 = state.sample1;
state.sample1 = clamp(predictor, MIN_INT16, MAX_INT16);
state.delta = (adaptationTable[code] * state.delta) >> 8;
if (state.delta < 16)
state.delta = 16;
return code;
}
int MSADPCM::decodeBlock(const uint8_t *encoded, int16_t *decoded)
{
ms_adpcm_state decoderState[2];
ms_adpcm_state *state[2];
int channelCount = m_track->f.channelCount;
int outputLength = m_framesPerPacket * sizeof (int16_t) * channelCount;
state[0] = &decoderState[0];
if (channelCount == 2)
state[1] = &decoderState[1];
else
state[1] = &decoderState[0];
for (int i=0; i<channelCount; i++)
{
state[i]->predictorIndex = *encoded++;
assert(state[i]->predictorIndex < m_numCoefficients);
}
for (int i=0; i<channelCount; i++)
{
state[i]->delta = (encoded[1]<<8) | encoded[0];
encoded += sizeof (uint16_t);
}
for (int i=0; i<channelCount; i++)
{
state[i]->sample1 = (encoded[1]<<8) | encoded[0];
encoded += sizeof (uint16_t);
}
for (int i=0; i<channelCount; i++)
{
state[i]->sample2 = (encoded[1]<<8) | encoded[0];
encoded += sizeof (uint16_t);
}
const int16_t *coefficient[2] =
{
m_coefficients[state[0]->predictorIndex],
m_coefficients[state[1]->predictorIndex]
};
for (int i=0; i<channelCount; i++)
*decoded++ = state[i]->sample2;
for (int i=0; i<channelCount; i++)
*decoded++ = state[i]->sample1;
int samplesRemaining = (m_framesPerPacket - 2) * m_track->f.channelCount;
while (samplesRemaining > 0)
{
uint8_t code;
int16_t newSample;
code = *encoded >> 4;
newSample = decodeSample(*state[0], code, coefficient[0]);
*decoded++ = newSample;
code = *encoded & 0x0f;
newSample = decodeSample(*state[1], code, coefficient[1]);
*decoded++ = newSample;
encoded++;
samplesRemaining -= 2;
}
return outputLength;
}
int MSADPCM::encodeBlock(const int16_t *decoded, uint8_t *encoded)
{
choosePredictorForBlock(decoded);
int channelCount = m_track->f.channelCount;
for (int c=0; c<channelCount; c++)
*encoded++ = m_state[c].predictorIndex;
for (int c=0; c<channelCount; c++)
{
*encoded++ = m_state[c].delta & 0xff;
*encoded++ = m_state[c].delta >> 8;
}
for (int c=0; c<channelCount; c++)
m_state[c].sample2 = *decoded++;
for (int c=0; c<channelCount; c++)
m_state[c].sample1 = *decoded++;
for (int c=0; c<channelCount; c++)
{
*encoded++ = m_state[c].sample1 & 0xff;
*encoded++ = m_state[c].sample1 >> 8;
}
for (int c=0; c<channelCount; c++)
{
*encoded++ = m_state[c].sample2 & 0xff;
*encoded++ = m_state[c].sample2 >> 8;
}
ms_adpcm_state *state[2] = { &m_state[0], &m_state[channelCount - 1] };
const int16_t *coefficient[2] =
{
m_coefficients[state[0]->predictorIndex],
m_coefficients[state[1]->predictorIndex]
};
int samplesRemaining = (m_framesPerPacket - 2) * m_track->f.channelCount;
while (samplesRemaining > 0)
{
uint8_t code1 = encodeSample(*state[0], *decoded++, coefficient[0]);
uint8_t code2 = encodeSample(*state[1], *decoded++, coefficient[1]);
*encoded++ = (code1 << 4) | code2;
samplesRemaining -= 2;
}
return m_bytesPerPacket;
}
void MSADPCM::choosePredictorForBlock(const int16_t *decoded)
{
const int kPredictorSampleLength = 3;
int channelCount = m_track->f.channelCount;
for (int c=0; c<channelCount; c++)
{
int bestPredictorIndex = 0;
int bestPredictorError = std::numeric_limits<int>::max();
for (int k=0; k<m_numCoefficients; k++)
{
int a0 = m_coefficients[k][0];
int a1 = m_coefficients[k][1];
int currentPredictorError = 0;
for (int i=2; i<2+kPredictorSampleLength; i++)
{
int error = std::abs(decoded[i*channelCount + c] -
((a0 * decoded[(i-1)*channelCount + c] +
a1 * decoded[(i-2)*channelCount + c]) >> 8));
currentPredictorError += error;
}
currentPredictorError /= 4 * kPredictorSampleLength;
if (currentPredictorError < bestPredictorError)
{
bestPredictorError = currentPredictorError;
bestPredictorIndex = k;
}
if (!currentPredictorError)
break;
}
if (bestPredictorError < 16)
bestPredictorError = 16;
m_state[c].predictorIndex = bestPredictorIndex;
m_state[c].delta = bestPredictorError;
}
}
void MSADPCM::describe()
{
m_outChunk->f.byteOrder = _AF_BYTEORDER_NATIVE;
m_outChunk->f.compressionType = AF_COMPRESSION_NONE;
m_outChunk->f.compressionParams = AU_NULL_PVLIST;
}
MSADPCM::MSADPCM(Mode mode, Track *track, File *fh, bool canSeek) :
BlockCodec(mode, track, fh, canSeek),
m_numCoefficients(0),
m_state(NULL)
{
m_state = new ms_adpcm_state[m_track->f.channelCount];
}
MSADPCM::~MSADPCM()
{
delete [] m_state;
}
bool MSADPCM::initializeCoefficients()
{
AUpvlist pv = m_track->f.compressionParams;
long l;
if (_af_pv_getlong(pv, _AF_MS_ADPCM_NUM_COEFFICIENTS, &l))
{
m_numCoefficients = l;
}
else
{
_af_error(AF_BAD_CODEC_CONFIG, "number of coefficients not set");
return false;
}
void *v;
if (_af_pv_getptr(pv, _AF_MS_ADPCM_COEFFICIENTS, &v))
{
memcpy(m_coefficients, v, m_numCoefficients * 2 * sizeof (int16_t));
}
else
{
_af_error(AF_BAD_CODEC_CONFIG, "coefficient array not set");
return false;
}
return true;
}
MSADPCM *MSADPCM::createDecompress(Track *track, File *fh,
bool canSeek, bool headerless, AFframecount *chunkFrames)
{
assert(fh->tell() == track->fpos_first_frame);
MSADPCM *msadpcm = new MSADPCM(Decompress, track, fh, canSeek);
if (!msadpcm->initializeCoefficients())
{
delete msadpcm;
return NULL;
}
*chunkFrames = msadpcm->m_framesPerPacket;
return msadpcm;
}
MSADPCM *MSADPCM::createCompress(Track *track, File *fh,
bool canSeek, bool headerless, AFframecount *chunkFrames)
{
assert(fh->tell() == track->fpos_first_frame);
MSADPCM *msadpcm = new MSADPCM(Compress, track, fh, canSeek);
if (!msadpcm->initializeCoefficients())
{
delete msadpcm;
return NULL;
}
*chunkFrames = msadpcm->m_framesPerPacket;
return msadpcm;
}
bool _af_ms_adpcm_format_ok (AudioFormat *f)
{
if (f->channelCount != 1 && f->channelCount != 2)
{
_af_error(AF_BAD_COMPRESSION,
"MS ADPCM compression requires 1 or 2 channels");
return false;
}
if (f->sampleFormat != AF_SAMPFMT_TWOSCOMP || f->sampleWidth != 16)
{
_af_error(AF_BAD_COMPRESSION,
"MS ADPCM compression requires 16-bit signed integer format");
return false;
}
if (f->byteOrder != _AF_BYTEORDER_NATIVE)
{
_af_error(AF_BAD_COMPRESSION,
"MS ADPCM compression requires native byte order");
return false;
}
return true;
}
FileModule *_af_ms_adpcm_init_decompress (Track *track, File *fh,
bool canSeek, bool headerless, AFframecount *chunkFrames)
{
return MSADPCM::createDecompress(track, fh, canSeek, headerless, chunkFrames);
}
FileModule *_af_ms_adpcm_init_compress (Track *track, File *fh,
bool canSeek, bool headerless, AFframecount *chunkFrames)
{
return MSADPCM::createCompress(track, fh, canSeek, headerless, chunkFrames);
}
#ifndef MODULES_PCM_H
#define MODULES_PCM_H
class File;
class FileModule;
struct AudioFormat;
struct Track;
bool _af_pcm_format_ok (AudioFormat *f);
FileModule *_AFpcminitcompress(Track *, File *, bool seekok,
bool headerless, AFframecount *chunkframes);
FileModule *_AFpcminitdecompress(Track *, File *, bool seekok,
bool headerless, AFframecount *chunkframes);
#endif
#include <assert.h>
#include <math.h>
bool _af_pcm_format_ok (AudioFormat *f)
{
assert(!isnan(f->pcm.slope));
assert(!isnan(f->pcm.intercept));
assert(!isnan(f->pcm.minClip));
assert(!isnan(f->pcm.maxClip));
return true;
}
class PCM : public FileModule
{
public:
static PCM *createCompress(Track *track, File *fh, bool canSeek,
bool headerless, AFframecount *chunkFrames);
static PCM *createDecompress(Track *track, File *fh, bool canSeek,
bool headerless, AFframecount *chunkFrames);
virtual const char *name() const OVERRIDE { return "pcm"; }
virtual void runPull() OVERRIDE;
virtual void reset2() OVERRIDE;
virtual void runPush() OVERRIDE;
virtual void sync1() OVERRIDE;
virtual void sync2() OVERRIDE;
private:
int m_bytesPerFrame;
int m_saved_fpos_next_frame;
int m_saved_nextfframe;
PCM(Mode, Track *, File *, bool canSeek);
};
PCM::PCM(Mode mode, Track *track, File *fh, bool canSeek) :
FileModule(mode, track, fh, canSeek),
m_bytesPerFrame(track->f.bytesPerFrame(false)),
m_saved_fpos_next_frame(-1),
m_saved_nextfframe(-1)
{
if (mode == Decompress)
track->f.compressionParams = AU_NULL_PVLIST;
}
PCM *PCM::createCompress(Track *track, File *fh, bool canSeek,
bool headerless, AFframecount *chunkframes)
{
return new PCM(Compress, track, fh, canSeek);
}
void PCM::runPush()
{
AFframecount frames2write = m_inChunk->frameCount;
AFframecount n;
ssize_t bytesWritten = write(m_inChunk->buffer, m_bytesPerFrame * frames2write);
n = bytesWritten >= 0 ? bytesWritten / m_bytesPerFrame : 0;
if (n != frames2write)
reportWriteError(n, frames2write);
m_track->nextfframe += n;
m_track->totalfframes = m_track->nextfframe;
assert(!canSeek() || (tell() == m_track->fpos_next_frame));
}
void PCM::sync1()
{
m_saved_fpos_next_frame = m_track->fpos_next_frame;
m_saved_nextfframe = m_track->nextfframe;
}
void PCM::sync2()
{
assert(!canSeek() || (tell() == m_track->fpos_next_frame));
m_track->fpos_after_data = tell();
m_track->fpos_next_frame = m_saved_fpos_next_frame;
m_track->nextfframe = m_saved_nextfframe;
}
PCM *PCM::createDecompress(Track *track, File *fh, bool canSeek,
bool headerless, AFframecount *chunkframes)
{
return new PCM(Decompress, track, fh, canSeek);
}
void PCM::runPull()
{
AFframecount framesToRead = m_outChunk->frameCount;
if (m_track->totalfframes != -1 &&
m_track->nextfframe + framesToRead > m_track->totalfframes)
{
framesToRead = m_track->totalfframes - m_track->nextfframe;
}
ssize_t bytesRead = read(m_outChunk->buffer, m_bytesPerFrame * framesToRead);
AFframecount framesRead = bytesRead >= 0 ? bytesRead / m_bytesPerFrame : 0;
m_track->nextfframe += framesRead;
assert(!canSeek() || (tell() == m_track->fpos_next_frame));
if (framesRead != framesToRead && m_track->totalfframes != -1)
reportReadError(framesRead, framesToRead);
m_outChunk->frameCount = framesRead;
}
void PCM::reset2()
{
m_track->fpos_next_frame = m_track->fpos_first_frame +
m_bytesPerFrame * m_track->nextfframe;
m_track->frames2ignore = 0;
}
FileModule *_AFpcminitcompress (Track *track, File *fh, bool canSeek,
bool headerless, AFframecount *chunkFrames)
{
return PCM::createCompress(track, fh, canSeek, headerless, chunkFrames);
}
FileModule *_AFpcminitdecompress (Track *track, File *fh, bool canSeek,
bool headerless, AFframecount *chunkFrames)
{
return PCM::createDecompress(track, fh, canSeek, headerless, chunkFrames);
}
#include <algorithm>
void SimpleModule::runPull()
{
pull(m_outChunk->frameCount);
run(*m_inChunk, *m_outChunk);
}
void SimpleModule::runPush()
{
m_outChunk->frameCount = m_inChunk->frameCount;
run(*m_inChunk, *m_outChunk);
push(m_outChunk->frameCount);
}
ApplyChannelMatrix::ApplyChannelMatrix(FormatCode format, bool isReading,
int inChannels, int outChannels,
double minClip, double maxClip, const double *matrix) :
m_format(format),
m_inChannels(inChannels),
m_outChannels(outChannels),
m_minClip(minClip),
m_maxClip(maxClip),
m_matrix(NULL)
{
m_matrix = new double[m_inChannels * m_outChannels];
if (matrix)
{
if (isReading)
{
std::copy(matrix, matrix + m_inChannels * m_outChannels, m_matrix);
}
else
{
for (int i=0; i < inChannels; i++)
for (int j=0; j < outChannels; j++)
m_matrix[j*inChannels + i] = matrix[i*outChannels + j];
}
}
else
{
initDefaultMatrix();
}
}
ApplyChannelMatrix::~ApplyChannelMatrix()
{
delete [] m_matrix;
}
const char *ApplyChannelMatrix::name() const { return "channelMatrix"; }
void ApplyChannelMatrix::describe()
{
m_outChunk->f.channelCount = m_outChannels;
m_outChunk->f.pcm.minClip = m_minClip;
m_outChunk->f.pcm.maxClip = m_maxClip;
}
void ApplyChannelMatrix::run(Chunk &inChunk, Chunk &outChunk)
{
switch (m_format)
{
case kInt8:
run<int8_t>(inChunk.buffer, outChunk.buffer, inChunk.frameCount);
break;
case kInt16:
run<int16_t>(inChunk.buffer, outChunk.buffer, inChunk.frameCount);
break;
case kInt24:
case kInt32:
run<int32_t>(inChunk.buffer, outChunk.buffer, inChunk.frameCount);
break;
case kFloat:
run<float>(inChunk.buffer, outChunk.buffer, inChunk.frameCount);
break;
case kDouble:
run<double>(inChunk.buffer, outChunk.buffer, inChunk.frameCount);
break;
default:
assert(false);
}
}
template <typename T>
void ApplyChannelMatrix::run(const void *inputData, void *outputData, int frameCount)
{
const T *input = reinterpret_cast<const T *>(inputData);
T *output = reinterpret_cast<T *>(outputData);
for (int frame=0; frame<frameCount; frame++)
{
const T *inputSave = input;
const double *m = m_matrix;
for (int outChannel=0; outChannel < m_outChannels; outChannel++)
{
input = inputSave;
double t = 0;
for (int inChannel=0; inChannel < m_inChannels; inChannel++)
t += *input++ * *m++;
*output++ = t;
}
}
}
void ApplyChannelMatrix::initDefaultMatrix()
{
const double *matrix = NULL;
if (m_inChannels==1 && m_outChannels==2)
{
static const double m[]={1,1};
matrix = m;
}
else if (m_inChannels==1 && m_outChannels==4)
{
static const double m[]={1,1,0,0};
matrix = m;
}
else if (m_inChannels==2 && m_outChannels==1)
{
static const double m[]={.5,.5};
matrix = m;
}
else if (m_inChannels==2 && m_outChannels==4)
{
static const double m[]={1,0,0,1,0,0,0,0};
matrix = m;
}
else if (m_inChannels==4 && m_outChannels==1)
{
static const double m[]={.5,.5,.5,.5};
matrix = m;
}
else if (m_inChannels==4 && m_outChannels==2)
{
static const double m[]={1,0,1,0,0,1,0,1};
matrix = m;
}
if (matrix)
{
std::copy(matrix, matrix + m_inChannels * m_outChannels, m_matrix);
}
else
{
for (int i=0; i < m_inChannels; i++)
for (int j=0; j < m_outChannels; j++)
m_matrix[j*m_inChannels + i] = (i==j) ? 1 : 0;
}
}
#include <algorithm>
#include <assert.h>
#include <string.h>
RebufferModule::RebufferModule(Direction direction, int bytesPerFrame,
int numFrames, bool multipleOf) :
m_direction(direction),
m_bytesPerFrame(bytesPerFrame),
m_numFrames(numFrames),
m_multipleOf(multipleOf),
m_eof(false),
m_sentShortChunk(false),
m_buffer(NULL),
m_offset(-1),
m_savedBuffer(NULL),
m_savedOffset(-1)
{
if (m_direction == FixedToVariable)
initFixedToVariable();
else
initVariableToFixed();
}
RebufferModule::~RebufferModule()
{
delete [] m_buffer;
delete [] m_savedBuffer;
}
void RebufferModule::initFixedToVariable()
{
m_offset = m_numFrames;
m_buffer = new char[m_numFrames * m_bytesPerFrame];
}
void RebufferModule::initVariableToFixed()
{
m_offset = 0;
m_buffer = new char[m_numFrames * m_bytesPerFrame];
m_savedBuffer = new char[m_numFrames * m_bytesPerFrame];
}
void RebufferModule::maxPull()
{
assert(m_direction == FixedToVariable);
if (m_multipleOf)
m_inChunk->frameCount = m_outChunk->frameCount + m_numFrames;
else
m_inChunk->frameCount = m_numFrames;
}
void RebufferModule::maxPush()
{
assert(m_direction == VariableToFixed);
if (m_multipleOf)
m_outChunk->frameCount = m_inChunk->frameCount + m_numFrames;
else
m_outChunk->frameCount = m_numFrames;
}
void RebufferModule::runPull()
{
int framesToPull = m_outChunk->frameCount;
const char *inBuffer = static_cast<const char *>(m_inChunk->buffer);
char *outBuffer = static_cast<char *>(m_outChunk->buffer);
assert(m_offset > 0 && m_offset <= m_numFrames);
assert(!m_sentShortChunk);
if (m_offset < m_numFrames)
{
int buffered = m_numFrames - m_offset;
int n = std::min(framesToPull, buffered);
memcpy(outBuffer, m_buffer + m_offset * m_bytesPerFrame,
n * m_bytesPerFrame);
outBuffer += buffered * m_bytesPerFrame;
framesToPull -= buffered;
m_offset += n;
}
while (!m_eof && framesToPull > 0)
{
int framesRequested;
if (m_multipleOf)
framesRequested = ((framesToPull - 1) / m_numFrames + 1) * m_numFrames;
else
framesRequested = m_numFrames;
assert(framesRequested > 0);
pull(framesRequested);
int framesReceived = m_inChunk->frameCount;
if (framesReceived != framesRequested)
m_eof = true;
memcpy(outBuffer, inBuffer,
std::min(framesToPull, framesReceived) * m_bytesPerFrame);
outBuffer += framesReceived * m_bytesPerFrame;
framesToPull -= framesReceived;
if (m_multipleOf)
assert(m_eof || framesToPull <= 0);
if (framesToPull < 0)
{
assert(m_offset == m_numFrames);
m_offset = m_numFrames + framesToPull;
assert(m_offset > 0 && m_offset <= m_numFrames);
memcpy(m_buffer + m_offset * m_bytesPerFrame,
inBuffer + (framesReceived + framesToPull) * m_bytesPerFrame,
(m_numFrames - m_offset) * m_bytesPerFrame);
}
else
{
assert(m_offset == m_numFrames);
}
}
if (m_eof && framesToPull > 0)
{
m_outChunk->frameCount -= framesToPull;
m_sentShortChunk = true;
assert(m_offset == m_numFrames);
}
else
{
assert(framesToPull <= 0);
assert(m_offset == m_numFrames + framesToPull);
}
assert(m_offset > 0 && m_offset <= m_numFrames);
}
void RebufferModule::reset1()
{
m_offset = m_numFrames;
m_eof = false;
m_sentShortChunk = false;
assert(m_offset > 0 && m_offset <= m_numFrames);
}
void RebufferModule::reset2()
{
assert(m_offset > 0 && m_offset <= m_numFrames);
}
void RebufferModule::runPush()
{
int framesToPush = m_inChunk->frameCount;
const char *inBuffer = static_cast<const char *>(m_inChunk->buffer);
char *outBuffer = static_cast<char *>(m_outChunk->buffer);
assert(m_offset >= 0 && m_offset < m_numFrames);
if (m_offset + framesToPush >= m_numFrames)
{
if (m_offset > 0)
memcpy(m_outChunk->buffer, m_buffer, m_offset * m_bytesPerFrame);
if (m_multipleOf)
{
int n = ((m_offset + framesToPush) / m_numFrames) * m_numFrames;
assert(n > m_offset);
memcpy(outBuffer + m_offset * m_bytesPerFrame,
inBuffer,
(n - m_offset) * m_bytesPerFrame);
push(n);
inBuffer += (n - m_offset) * m_bytesPerFrame;
framesToPush -= n - m_offset;
assert(framesToPush >= 0);
m_offset = 0;
}
else
{
while (m_offset + framesToPush >= m_numFrames)
{
int n = m_numFrames - m_offset;
memcpy(outBuffer + m_offset * m_bytesPerFrame,
inBuffer,
n * m_bytesPerFrame);
push(m_numFrames);
inBuffer += n * m_bytesPerFrame;
framesToPush -= n;
assert(framesToPush >= 0);
m_offset = 0;
}
}
assert(m_offset == 0);
}
assert(m_offset + framesToPush < m_numFrames);
if (framesToPush > 0)
{
memcpy(m_buffer + m_offset * m_bytesPerFrame,
inBuffer,
framesToPush * m_bytesPerFrame);
m_offset += framesToPush;
}
assert(m_offset >= 0 && m_offset < m_numFrames);
}
void RebufferModule::sync1()
{
assert(m_offset >= 0 && m_offset < m_numFrames);
memcpy(m_savedBuffer, m_buffer, m_numFrames * m_bytesPerFrame);
m_savedOffset = m_offset;
}
void RebufferModule::sync2()
{
assert(m_offset >= 0 && m_offset < m_numFrames);
memcpy(m_outChunk->buffer, m_buffer, m_offset * m_bytesPerFrame);
push(m_offset);
memcpy(m_buffer, m_savedBuffer, m_numFrames * m_bytesPerFrame);
m_offset = m_savedOffset;
assert(m_offset >= 0 && m_offset < m_numFrames);
}
#ifndef AIFF_H
#define AIFF_H
#define _AF_AIFF_NUM_INSTPARAMS 9
extern const InstParamInfo _af_aiff_inst_params[_AF_AIFF_NUM_INSTPARAMS];
#define _AF_AIFFC_NUM_COMPTYPES 3
extern const int _af_aiffc_compression_types[_AF_AIFFC_NUM_COMPTYPES];
class AIFFFile : public _AFfilehandle
{
public:
AIFFFile();
static bool recognizeAIFF(File *fh);
static bool recognizeAIFFC(File *fh);
static AFfilesetup completeSetup(AFfilesetup);
int getVersion() OVERRIDE;
status readInit(AFfilesetup) OVERRIDE;
status writeInit(AFfilesetup) OVERRIDE;
status update() OVERRIDE;
bool isInstrumentParameterValid(AUpvlist, int) OVERRIDE;
private:
AFfileoffset m_miscellaneousPosition;
AFfileoffset m_FVER_offset;
AFfileoffset m_COMM_offset;
AFfileoffset m_MARK_offset;
AFfileoffset m_INST_offset;
AFfileoffset m_AESD_offset;
AFfileoffset m_SSND_offset;
status parseFVER(const Tag &type, size_t size);
status parseAESD(const Tag &type, size_t size);
status parseMiscellaneous(const Tag &type, size_t size);
status parseINST(const Tag &type, size_t size);
status parseMARK(const Tag &type, size_t size);
status parseCOMM(const Tag &type, size_t size);
status parseSSND(const Tag &type, size_t size);
status writeCOMM();
status writeSSND();
status writeMARK();
status writeINST();
status writeFVER();
status writeAESD();
status writeMiscellaneous();
void initCompressionParams();
void initIMACompressionParams();
bool isAIFFC() const { return m_fileFormat == AF_FILE_AIFFC; }
bool readPString(char s[256]);
bool writePString(const char *);
};
#endif
#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
const InstParamInfo _af_aiff_inst_params[_AF_AIFF_NUM_INSTPARAMS] =
{
{ AF_INST_MIDI_BASENOTE, AU_PVTYPE_LONG, "MIDI base note", {60} },
{ AF_INST_NUMCENTS_DETUNE, AU_PVTYPE_LONG, "Detune in cents", {0} },
{ AF_INST_MIDI_LOVELOCITY, AU_PVTYPE_LONG, "Low velocity", {1} },
{ AF_INST_MIDI_HIVELOCITY, AU_PVTYPE_LONG, "High velocity", {127} },
{ AF_INST_MIDI_LONOTE, AU_PVTYPE_LONG, "Low note", {0} },
{ AF_INST_MIDI_HINOTE, AU_PVTYPE_LONG, "High note", {127} },
{ AF_INST_NUMDBS_GAIN, AU_PVTYPE_LONG, "Gain in dB", {0} },
{ AF_INST_SUSLOOPID, AU_PVTYPE_LONG, "Sustain loop id", {0} },
{ AF_INST_RELLOOPID, AU_PVTYPE_LONG, "Release loop id", {0} }
};
const int _af_aiffc_compression_types[_AF_AIFFC_NUM_COMPTYPES] =
{
AF_COMPRESSION_G711_ULAW,
AF_COMPRESSION_G711_ALAW,
AF_COMPRESSION_IMA
};
static const _AFfilesetup aiffDefaultFileSetup =
{
_AF_VALID_FILESETUP,
AF_FILE_AIFF,
true,
true,
true,
1,
NULL,
1,
NULL,
0,
NULL
};
#define AIFC_VERSION_1 0xa2805140
struct _INST
{
uint8_t baseNote;
int8_t detune;
uint8_t lowNote, highNote;
uint8_t lowVelocity, highVelocity;
int16_t gain;
uint16_t sustainLoopPlayMode;
uint16_t sustainLoopBegin;
uint16_t sustainLoopEnd;
uint16_t releaseLoopPlayMode;
uint16_t releaseLoopBegin;
uint16_t releaseLoopEnd;
};
AIFFFile::AIFFFile()
{
setFormatByteOrder(AF_BYTEORDER_BIGENDIAN);
m_miscellaneousPosition = 0;
m_FVER_offset = 0;
m_COMM_offset = 0;
m_MARK_offset = 0;
m_INST_offset = 0;
m_AESD_offset = 0;
m_SSND_offset = 0;
}
status AIFFFile::parseFVER(const Tag &type, size_t size)
{
assert(type == "FVER");
uint32_t timestamp;
readU32(×tamp);
return AF_SUCCEED;
}
status AIFFFile::parseAESD(const Tag &type, size_t size)
{
unsigned char aesChannelStatusData[24];
assert(type == "AESD");
assert(size == 24);
Track *track = getTrack();
track->hasAESData = true;
if (m_fh->read(aesChannelStatusData, 24) != 24)
return AF_FAIL;
memcpy(track->aesData, aesChannelStatusData, 24);
return AF_SUCCEED;
}
status AIFFFile::parseMiscellaneous(const Tag &type, size_t size)
{
int misctype = AF_MISC_UNRECOGNIZED;
assert(type == "NAME" ||
type == "AUTH" ||
type == "(c) " ||
type == "ANNO" ||
type == "APPL" ||
type == "MIDI");
if (size == 0)
return AF_FAIL;
m_miscellaneousCount++;
m_miscellaneous = (Miscellaneous *) _af_realloc(m_miscellaneous,
m_miscellaneousCount * sizeof (Miscellaneous));
if (type == "NAME")
misctype = AF_MISC_NAME;
else if (type == "AUTH")
misctype = AF_MISC_AUTH;
else if (type == "(c) ")
misctype = AF_MISC_COPY;
else if (type == "ANNO")
misctype = AF_MISC_ANNO;
else if (type == "APPL")
misctype = AF_MISC_APPL;
else if (type == "MIDI")
misctype = AF_MISC_MIDI;
m_miscellaneous[m_miscellaneousCount - 1].id = m_miscellaneousCount;
m_miscellaneous[m_miscellaneousCount - 1].type = misctype;
m_miscellaneous[m_miscellaneousCount - 1].size = size;
m_miscellaneous[m_miscellaneousCount - 1].position = 0;
m_miscellaneous[m_miscellaneousCount - 1].buffer = _af_malloc(size);
m_fh->read(m_miscellaneous[m_miscellaneousCount - 1].buffer, size);
return AF_SUCCEED;
}
status AIFFFile::parseINST(const Tag &type, size_t size)
{
uint8_t baseNote;
int8_t detune;
uint8_t lowNote, highNote, lowVelocity, highVelocity;
int16_t gain;
uint16_t sustainLoopPlayMode, sustainLoopBegin, sustainLoopEnd;
uint16_t releaseLoopPlayMode, releaseLoopBegin, releaseLoopEnd;
Instrument *instrument = (Instrument *) _af_calloc(1, sizeof (Instrument));
instrument->id = AF_DEFAULT_INST;
instrument->values = (AFPVu *) _af_calloc(_AF_AIFF_NUM_INSTPARAMS, sizeof (AFPVu));
instrument->loopCount = 2;
instrument->loops = (Loop *) _af_calloc(2, sizeof (Loop));
m_instrumentCount = 1;
m_instruments = instrument;
readU8(&baseNote);
readS8(&detune);
readU8(&lowNote);
readU8(&highNote);
readU8(&lowVelocity);
readU8(&highVelocity);
readS16(&gain);
instrument->values[0].l = baseNote;
instrument->values[1].l = detune;
instrument->values[2].l = lowVelocity;
instrument->values[3].l = highVelocity;
instrument->values[4].l = lowNote;
instrument->values[5].l = highNote;
instrument->values[6].l = gain;
instrument->values[7].l = 1;
instrument->values[8].l = 2;
readU16(&sustainLoopPlayMode);
readU16(&sustainLoopBegin);
readU16(&sustainLoopEnd);
readU16(&releaseLoopPlayMode);
readU16(&releaseLoopBegin);
readU16(&releaseLoopEnd);
instrument->loops[0].id = 1;
instrument->loops[0].mode = sustainLoopPlayMode;
instrument->loops[0].beginMarker = sustainLoopBegin;
instrument->loops[0].endMarker = sustainLoopEnd;
instrument->loops[0].trackid = AF_DEFAULT_TRACK;
instrument->loops[1].id = 2;
instrument->loops[1].mode = releaseLoopPlayMode;
instrument->loops[1].beginMarker = releaseLoopBegin;
instrument->loops[1].endMarker = releaseLoopEnd;
instrument->loops[1].trackid = AF_DEFAULT_TRACK;
return AF_SUCCEED;
}
status AIFFFile::parseMARK(const Tag &type, size_t size)
{
assert(type == "MARK");
Track *track = getTrack();
uint16_t numMarkers;
readU16(&numMarkers);
track->markerCount = numMarkers;
if (numMarkers)
track->markers = _af_marker_new(numMarkers);
for (unsigned i=0; i<numMarkers; i++)
{
uint16_t markerID = 0;
uint32_t markerPosition = 0;
uint8_t sizeByte = 0;
char *markerName = NULL;
readU16(&markerID);
readU32(&markerPosition);
m_fh->read(&sizeByte, 1);
markerName = (char *) _af_malloc(sizeByte + 1);
m_fh->read(markerName, sizeByte);
markerName[sizeByte] = '\0';
if ((sizeByte % 2) == 0)
m_fh->seek(1, File::SeekFromCurrent);
track->markers[i].id = markerID;
track->markers[i].position = markerPosition;
track->markers[i].name = markerName;
track->markers[i].comment = _af_strdup("");
}
return AF_SUCCEED;
}
status AIFFFile::parseCOMM(const Tag &type, size_t size)
{
assert(type == "COMM");
Track *track = getTrack();
uint16_t numChannels;
uint32_t numSampleFrames;
uint16_t sampleSize;
unsigned char sampleRate[10];
readU16(&numChannels);
track->f.channelCount = numChannels;
if (!numChannels)
{
_af_error(AF_BAD_CHANNELS, "invalid file with 0 channels");
return AF_FAIL;
}
readU32(&numSampleFrames);
track->totalfframes = numSampleFrames;
readU16(&sampleSize);
track->f.sampleWidth = sampleSize;
m_fh->read(sampleRate, 10);
track->f.sampleRate = _af_convert_from_ieee_extended(sampleRate);
track->f.compressionType = AF_COMPRESSION_NONE;
track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
track->f.byteOrder = AF_BYTEORDER_BIGENDIAN;
track->f.framesPerPacket = 1;
if (isAIFFC())
{
Tag compressionID;
char compressionName[256];
readTag(&compressionID);
readPString(compressionName);
if (compressionID == "NONE" || compressionID == "twos")
{
track->f.compressionType = AF_COMPRESSION_NONE;
}
else if (compressionID == "in24")
{
track->f.compressionType = AF_COMPRESSION_NONE;
track->f.sampleWidth = 24;
}
else if (compressionID == "in32")
{
track->f.compressionType = AF_COMPRESSION_NONE;
track->f.sampleWidth = 32;
}
else if (compressionID == "ACE2" ||
compressionID == "ACE8" ||
compressionID == "MAC3" ||
compressionID == "MAC6")
{
_af_error(AF_BAD_NOT_IMPLEMENTED, "AIFF-C format does not support Apple's proprietary %s compression format", compressionName);
return AF_FAIL;
}
else if (compressionID == "ulaw" || compressionID == "ULAW")
{
track->f.compressionType = AF_COMPRESSION_G711_ULAW;
track->f.byteOrder = _AF_BYTEORDER_NATIVE;
track->f.sampleWidth = 16;
track->f.bytesPerPacket = track->f.channelCount;
}
else if (compressionID == "alaw" || compressionID == "ALAW")
{
track->f.compressionType = AF_COMPRESSION_G711_ALAW;
track->f.byteOrder = _AF_BYTEORDER_NATIVE;
track->f.sampleWidth = 16;
track->f.bytesPerPacket = track->f.channelCount;
}
else if (compressionID == "fl32" || compressionID == "FL32")
{
track->f.sampleFormat = AF_SAMPFMT_FLOAT;
track->f.sampleWidth = 32;
track->f.compressionType = AF_COMPRESSION_NONE;
}
else if (compressionID == "fl64" || compressionID == "FL64")
{
track->f.sampleFormat = AF_SAMPFMT_DOUBLE;
track->f.sampleWidth = 64;
track->f.compressionType = AF_COMPRESSION_NONE;
}
else if (compressionID == "sowt")
{
track->f.compressionType = AF_COMPRESSION_NONE;
track->f.byteOrder = AF_BYTEORDER_LITTLEENDIAN;
}
else if (compressionID == "ima4")
{
track->f.sampleWidth = 16;
track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
track->f.compressionType = AF_COMPRESSION_IMA;
track->f.byteOrder = _AF_BYTEORDER_NATIVE;
initIMACompressionParams();
track->totalfframes *= 64;
}
else
{
_af_error(AF_BAD_NOT_IMPLEMENTED, "AIFF-C compression type '%s' not currently supported",
compressionID.name().c_str());
return AF_FAIL;
}
}
if (track->f.isUncompressed())
track->f.computeBytesPerPacketPCM();
if (_af_set_sample_format(&track->f, track->f.sampleFormat, track->f.sampleWidth) == AF_FAIL)
return AF_FAIL;
return AF_SUCCEED;
}
status AIFFFile::parseSSND(const Tag &type, size_t size)
{
assert(type == "SSND");
Track *track = getTrack();
uint32_t offset, blockSize;
readU32(&offset);
readU32(&blockSize);
track->data_size = size - 8 - offset;
track->fpos_first_frame = m_fh->tell() + offset;
return AF_SUCCEED;
}
status AIFFFile::readInit(AFfilesetup setup)
{
uint32_t type, size, formtype;
bool hasCOMM = false;
bool hasFVER = false;
bool hasSSND = false;
m_fh->seek(0, File::SeekFromBeginning);
m_fh->read(&type, 4);
readU32(&size);
m_fh->read(&formtype, 4);
if (memcmp(&type, "FORM", 4) != 0 ||
(memcmp(&formtype, "AIFF", 4) && memcmp(&formtype, "AIFC", 4)))
return AF_FAIL;
if (!allocateTrack())
return AF_FAIL;
size_t index = 4;
while (index < size)
{
Tag chunkid;
uint32_t chunksize = 0;
status result = AF_SUCCEED;
readTag(&chunkid);
readU32(&chunksize);
if (chunkid == "COMM")
{
hasCOMM = true;
result = parseCOMM(chunkid, chunksize);
}
else if (chunkid == "FVER")
{
hasFVER = true;
parseFVER(chunkid, chunksize);
}
else if (chunkid == "INST")
{
parseINST(chunkid, chunksize);
}
else if (chunkid == "MARK")
{
parseMARK(chunkid, chunksize);
}
else if (chunkid == "AESD")
{
parseAESD(chunkid, chunksize);
}
else if (chunkid == "NAME" ||
chunkid == "AUTH" ||
chunkid == "(c) " ||
chunkid == "ANNO" ||
chunkid == "APPL" ||
chunkid == "MIDI")
{
parseMiscellaneous(chunkid, chunksize);
}
else if (chunkid == "SSND")
{
if (hasSSND)
{
_af_error(AF_BAD_AIFF_SSND, "AIFF file has more than one SSND chunk");
return AF_FAIL;
}
hasSSND = true;
result = parseSSND(chunkid, chunksize);
}
if (result == AF_FAIL)
return AF_FAIL;
index += chunksize + 8;
if ((index % 2) != 0)
index++;
m_fh->seek(index + 8, File::SeekFromBeginning);
}
if (!hasCOMM)
{
_af_error(AF_BAD_AIFF_COMM, "bad AIFF COMM chunk");
}
if (isAIFFC() && !hasFVER)
{
_af_error(AF_BAD_HEADER, "FVER chunk is required in AIFF-C");
}
return AF_SUCCEED;
}
bool AIFFFile::recognizeAIFF(File *fh)
{
uint8_t buffer[8];
fh->seek(0, File::SeekFromBeginning);
if (fh->read(buffer, 8) != 8 || memcmp(buffer, "FORM", 4) != 0)
return false;
if (fh->read(buffer, 4) != 4 || memcmp(buffer, "AIFF", 4) != 0)
return false;
return true;
}
bool AIFFFile::recognizeAIFFC(File *fh)
{
uint8_t buffer[8];
fh->seek(0, File::SeekFromBeginning);
if (fh->read(buffer, 8) != 8 || memcmp(buffer, "FORM", 4) != 0)
return false;
if (fh->read(buffer, 4) != 4 || memcmp(buffer, "AIFC", 4) != 0)
return false;
return true;
}
AFfilesetup AIFFFile::completeSetup(AFfilesetup setup)
{
bool isAIFF = setup->fileFormat == AF_FILE_AIFF;
if (setup->trackSet && setup->trackCount != 1)
{
_af_error(AF_BAD_NUMTRACKS, "AIFF/AIFF-C file must have 1 track");
return AF_NULL_FILESETUP;
}
TrackSetup *track = setup->getTrack();
if (!track)
return AF_NULL_FILESETUP;
if (track->sampleFormatSet)
{
if (track->f.sampleFormat == AF_SAMPFMT_UNSIGNED)
{
_af_error(AF_BAD_FILEFMT, "AIFF/AIFF-C format does not support unsigned data");
return AF_NULL_FILESETUP;
}
else if (isAIFF && track->f.sampleFormat != AF_SAMPFMT_TWOSCOMP)
{
_af_error(AF_BAD_FILEFMT, "AIFF format supports only two's complement integer data");
return AF_NULL_FILESETUP;
}
}
else
_af_set_sample_format(&track->f, AF_SAMPFMT_TWOSCOMP,
track->f.sampleWidth);
if (track->f.sampleFormat == AF_SAMPFMT_TWOSCOMP &&
(track->f.sampleWidth < 1 || track->f.sampleWidth > 32))
{
_af_error(AF_BAD_WIDTH,
"invalid sample width %d for AIFF/AIFF-C file "
"(must be 1-32)", track->f.sampleWidth);
return AF_NULL_FILESETUP;
}
if (isAIFF && track->f.compressionType != AF_COMPRESSION_NONE)
{
_af_error(AF_BAD_FILESETUP,
"AIFF does not support compression; use AIFF-C");
return AF_NULL_FILESETUP;
}
if (track->f.compressionType != AF_COMPRESSION_NONE &&
track->f.compressionType != AF_COMPRESSION_G711_ULAW &&
track->f.compressionType != AF_COMPRESSION_G711_ALAW &&
track->f.compressionType != AF_COMPRESSION_IMA)
{
_af_error(AF_BAD_NOT_IMPLEMENTED, "compression format not supported in AIFF-C");
return AF_NULL_FILESETUP;
}
if (track->f.isUncompressed() &&
track->byteOrderSet &&
track->f.byteOrder != AF_BYTEORDER_BIGENDIAN &&
track->f.isByteOrderSignificant())
{
_af_error(AF_BAD_BYTEORDER,
"AIFF/AIFF-C format supports only big-endian data");
return AF_NULL_FILESETUP;
}
if (track->f.isUncompressed())
track->f.byteOrder = AF_BYTEORDER_BIGENDIAN;
if (setup->instrumentSet)
{
if (setup->instrumentCount != 0 && setup->instrumentCount != 1)
{
_af_error(AF_BAD_NUMINSTS, "AIFF/AIFF-C file must have 0 or 1 instrument chunk");
return AF_NULL_FILESETUP;
}
if (setup->instruments != 0 &&
setup->instruments[0].loopCount != 2)
{
_af_error(AF_BAD_NUMLOOPS, "AIFF/AIFF-C file with instrument must also have 2 loops");
return AF_NULL_FILESETUP;
}
}
if (setup->miscellaneousSet)
{
for (int i=0; i<setup->miscellaneousCount; i++)
{
switch (setup->miscellaneous[i].type)
{
case AF_MISC_COPY:
case AF_MISC_AUTH:
case AF_MISC_NAME:
case AF_MISC_ANNO:
case AF_MISC_APPL:
case AF_MISC_MIDI:
break;
default:
_af_error(AF_BAD_MISCTYPE, "invalid miscellaneous type %d for AIFF/AIFF-C file", setup->miscellaneous[i].type);
return AF_NULL_FILESETUP;
}
}
}
return _af_filesetup_copy(setup, &aiffDefaultFileSetup, true);
}
bool AIFFFile::isInstrumentParameterValid(AUpvlist list, int i)
{
int param, type;
AUpvgetparam(list, i, ¶m);
AUpvgetvaltype(list, i, &type);
if (type != AU_PVTYPE_LONG)
return false;
long lval;
AUpvgetval(list, i, &lval);
switch (param)
{
case AF_INST_MIDI_BASENOTE:
return ((lval >= 0) && (lval <= 127));
case AF_INST_NUMCENTS_DETUNE:
return ((lval >= -50) && (lval <= 50));
case AF_INST_MIDI_LOVELOCITY:
return ((lval >= 1) && (lval <= 127));
case AF_INST_MIDI_HIVELOCITY:
return ((lval >= 1) && (lval <= 127));
case AF_INST_MIDI_LONOTE:
return ((lval >= 0) && (lval <= 127));
case AF_INST_MIDI_HINOTE:
return ((lval >= 0) && (lval <= 127));
case AF_INST_NUMDBS_GAIN:
case AF_INST_SUSLOOPID:
case AF_INST_RELLOOPID:
return true;
default:
return false;
break;
}
return true;
}
int AIFFFile::getVersion()
{
if (isAIFFC())
return AIFC_VERSION_1;
return 0;
}
status AIFFFile::writeInit(AFfilesetup setup)
{
if (initFromSetup(setup) == AF_FAIL)
return AF_FAIL;
initCompressionParams();
uint32_t fileSize = 0;
m_fh->write("FORM", 4);
writeU32(&fileSize);
if (isAIFFC())
m_fh->write("AIFC", 4);
else
m_fh->write("AIFF", 4);
if (isAIFFC())
writeFVER();
writeCOMM();
writeMARK();
writeINST();
writeAESD();
writeMiscellaneous();
writeSSND();
return AF_SUCCEED;
}
status AIFFFile::update()
{
uint32_t length = m_fh->length();
length -= 8;
m_fh->seek(4, File::SeekFromBeginning);
writeU32(&length);
if (isAIFFC())
writeFVER();
writeCOMM();
writeMARK();
writeINST();
writeAESD();
writeMiscellaneous();
writeSSND();
return AF_SUCCEED;
}
status AIFFFile::writeCOMM()
{
if (m_COMM_offset == 0)
m_COMM_offset = m_fh->tell();
else
m_fh->seek(m_COMM_offset, File::SeekFromBeginning);
Track *track = getTrack();
Tag compressionTag;
char compressionName[256];
if (isAIFFC())
{
if (track->f.compressionType == AF_COMPRESSION_NONE)
{
if (track->f.sampleFormat == AF_SAMPFMT_TWOSCOMP)
{
compressionTag = "NONE";
strcpy(compressionName, "not compressed");
}
else if (track->f.sampleFormat == AF_SAMPFMT_FLOAT)
{
compressionTag = "fl32";
strcpy(compressionName, "32-bit Floating Point");
}
else if (track->f.sampleFormat == AF_SAMPFMT_DOUBLE)
{
compressionTag = "fl64";
strcpy(compressionName, "64-bit Floating Point");
}
else if (track->f.sampleFormat == AF_SAMPFMT_UNSIGNED)
{
_af_error(AF_BAD_SAMPFMT,
"AIFF/AIFF-C format does not support unsigned data");
assert(0);
return AF_FAIL;
}
}
else if (track->f.compressionType == AF_COMPRESSION_G711_ULAW)
{
compressionTag = "ulaw";
strcpy(compressionName, "CCITT G.711 u-law");
}
else if (track->f.compressionType == AF_COMPRESSION_G711_ALAW)
{
compressionTag = "alaw";
strcpy(compressionName, "CCITT G.711 A-law");
}
else if (track->f.compressionType == AF_COMPRESSION_IMA)
{
compressionTag = "ima4";
strcpy(compressionName, "IMA 4:1 compression");
}
}
m_fh->write("COMM", 4);
uint32_t chunkSize;
if (isAIFFC())
chunkSize = 22 + strlen(compressionName) + 1;
else
chunkSize = 18;
writeU32(&chunkSize);
uint16_t channelCount = track->f.channelCount;
writeU16(&channelCount);
uint32_t frameCount = track->totalfframes;
if (track->f.compressionType == AF_COMPRESSION_IMA)
frameCount = track->totalfframes / track->f.framesPerPacket;
writeU32(&frameCount);
uint16_t sampleSize = track->f.sampleWidth;
writeU16(&sampleSize);
uint8_t sampleRate[10];
_af_convert_to_ieee_extended(track->f.sampleRate, sampleRate);
m_fh->write(sampleRate, 10);
if (isAIFFC())
{
writeTag(&compressionTag);
writePString(compressionName);
}
return AF_SUCCEED;
}
status AIFFFile::writeAESD()
{
Track *track = getTrack();
if (!track->hasAESData)
return AF_SUCCEED;
if (m_AESD_offset == 0)
m_AESD_offset = m_fh->tell();
else
m_fh->seek(m_AESD_offset, File::SeekFromBeginning);
if (m_fh->write("AESD", 4) < 4)
return AF_FAIL;
uint32_t size = 24;
if (!writeU32(&size))
return AF_FAIL;
if (m_fh->write(track->aesData, 24) < 24)
return AF_FAIL;
return AF_SUCCEED;
}
status AIFFFile::writeSSND()
{
Track *track = getTrack();
if (m_SSND_offset == 0)
m_SSND_offset = m_fh->tell();
else
m_fh->seek(m_SSND_offset, File::SeekFromBeginning);
m_fh->write("SSND", 4);
uint32_t chunkSize = track->data_size + 8;
writeU32(&chunkSize);
uint32_t zero = 0;
writeU32(&zero);
writeU32(&zero);
if (track->fpos_first_frame == 0)
track->fpos_first_frame = m_fh->tell();
return AF_SUCCEED;
}
status AIFFFile::writeINST()
{
uint32_t length = 20;
struct _INST instrumentdata;
instrumentdata.sustainLoopPlayMode =
afGetLoopMode(this, AF_DEFAULT_INST, 1);
instrumentdata.sustainLoopBegin =
afGetLoopStart(this, AF_DEFAULT_INST, 1);
instrumentdata.sustainLoopEnd =
afGetLoopEnd(this, AF_DEFAULT_INST, 1);
instrumentdata.releaseLoopPlayMode =
afGetLoopMode(this, AF_DEFAULT_INST, 2);
instrumentdata.releaseLoopBegin =
afGetLoopStart(this, AF_DEFAULT_INST, 2);
instrumentdata.releaseLoopEnd =
afGetLoopEnd(this, AF_DEFAULT_INST, 2);
m_fh->write("INST", 4);
writeU32(&length);
instrumentdata.baseNote =
afGetInstParamLong(this, AF_DEFAULT_INST, AF_INST_MIDI_BASENOTE);
writeU8(&instrumentdata.baseNote);
instrumentdata.detune =
afGetInstParamLong(this, AF_DEFAULT_INST, AF_INST_NUMCENTS_DETUNE);
writeS8(&instrumentdata.detune);
instrumentdata.lowNote =
afGetInstParamLong(this, AF_DEFAULT_INST, AF_INST_MIDI_LONOTE);
writeU8(&instrumentdata.lowNote);
instrumentdata.highNote =
afGetInstParamLong(this, AF_DEFAULT_INST, AF_INST_MIDI_HINOTE);
writeU8(&instrumentdata.highNote);
instrumentdata.lowVelocity =
afGetInstParamLong(this, AF_DEFAULT_INST, AF_INST_MIDI_LOVELOCITY);
writeU8(&instrumentdata.lowVelocity);
instrumentdata.highVelocity =
afGetInstParamLong(this, AF_DEFAULT_INST, AF_INST_MIDI_HIVELOCITY);
writeU8(&instrumentdata.highVelocity);
instrumentdata.gain =
afGetInstParamLong(this, AF_DEFAULT_INST, AF_INST_NUMDBS_GAIN);
writeS16(&instrumentdata.gain);
writeU16(&instrumentdata.sustainLoopPlayMode);
writeU16(&instrumentdata.sustainLoopBegin);
writeU16(&instrumentdata.sustainLoopEnd);
writeU16(&instrumentdata.releaseLoopPlayMode);
writeU16(&instrumentdata.releaseLoopBegin);
writeU16(&instrumentdata.releaseLoopEnd);
return AF_SUCCEED;
}
status AIFFFile::writeMARK()
{
Track *track = getTrack();
if (!track->markerCount)
return AF_SUCCEED;
if (m_MARK_offset == 0)
m_MARK_offset = m_fh->tell();
else
m_fh->seek(m_MARK_offset, File::SeekFromBeginning);
Tag markTag("MARK");
uint32_t length = 0;
writeTag(&markTag);
writeU32(&length);
AFfileoffset chunkStartPosition = m_fh->tell();
uint16_t numMarkers = track->markerCount;
writeU16(&numMarkers);
for (unsigned i=0; i<numMarkers; i++)
{
uint16_t id = track->markers[i].id;
writeU16(&id);
uint32_t position = track->markers[i].position;
writeU32(&position);
const char *name = track->markers[i].name;
assert(name);
writePString(name);
}
AFfileoffset chunkEndPosition = m_fh->tell();
length = chunkEndPosition - chunkStartPosition;
m_fh->seek(chunkStartPosition - 4, File::SeekFromBeginning);
writeU32(&length);
m_fh->seek(chunkEndPosition, File::SeekFromBeginning);
return AF_SUCCEED;
}
status AIFFFile::writeFVER()
{
uint32_t chunkSize, timeStamp;
assert(isAIFFC());
if (m_FVER_offset == 0)
m_FVER_offset = m_fh->tell();
else
m_fh->seek(m_FVER_offset, File::SeekFromBeginning);
m_fh->write("FVER", 4);
chunkSize = 4;
writeU32(&chunkSize);
timeStamp = AIFC_VERSION_1;
writeU32(&timeStamp);
return AF_SUCCEED;
}
status AIFFFile::writeMiscellaneous()
{
if (m_miscellaneousPosition == 0)
m_miscellaneousPosition = m_fh->tell();
else
m_fh->seek(m_miscellaneousPosition, File::SeekFromBeginning);
for (int i=0; i<m_miscellaneousCount; i++)
{
Miscellaneous *misc = &m_miscellaneous[i];
Tag chunkType;
uint32_t chunkSize;
uint8_t padByte = 0;
switch (misc->type)
{
case AF_MISC_NAME:
chunkType = "NAME"; break;
case AF_MISC_AUTH:
chunkType = "AUTH"; break;
case AF_MISC_COPY:
chunkType = "(c) "; break;
case AF_MISC_ANNO:
chunkType = "ANNO"; break;
case AF_MISC_MIDI:
chunkType = "MIDI"; break;
case AF_MISC_APPL:
chunkType = "APPL"; break;
}
writeTag(&chunkType);
chunkSize = misc->size;
writeU32(&chunkSize);
if (misc->buffer != NULL)
m_fh->write(misc->buffer, misc->size);
else
m_fh->seek(misc->size, File::SeekFromCurrent);
if (misc->size % 2 != 0)
writeU8(&padByte);
}
return AF_SUCCEED;
}
void AIFFFile::initCompressionParams()
{
Track *track = getTrack();
if (track->f.compressionType == AF_COMPRESSION_IMA)
initIMACompressionParams();
}
void AIFFFile::initIMACompressionParams()
{
Track *track = getTrack();
track->f.bytesPerPacket = 34 * track->f.channelCount;
track->f.framesPerPacket = 64;
AUpvlist pv = AUpvnew(1);
AUpvsetparam(pv, 0, _AF_IMA_ADPCM_TYPE);
AUpvsetvaltype(pv, 0, AU_PVTYPE_LONG);
long l = _AF_IMA_ADPCM_TYPE_QT;
AUpvsetval(pv, 0, &l);
track->f.compressionParams = pv;
}
bool AIFFFile::readPString(char s[256])
{
uint8_t length;
if (m_fh->read(&length, 1) != 1)
return false;
if (m_fh->read(s, length) != static_cast<ssize_t>(length))
return false;
s[length] = '\0';
return true;
}
bool AIFFFile::writePString(const char *s)
{
size_t length = strlen(s);
if (length > 255)
return false;
uint8_t sizeByte = static_cast<uint8_t>(length);
if (m_fh->write(&sizeByte, 1) != 1)
return false;
if (m_fh->write(s, length) != (ssize_t) length)
return false;
if ((length % 2) == 0)
{
uint8_t zero = 0;
if (m_fh->write(&zero, 1) != 1)
return false;
}
return true;
}
#include <assert.h>
#include <stdio.h>
size_t AudioFormat::bytesPerSample(bool stretch3to4) const
{
switch (sampleFormat)
{
case AF_SAMPFMT_FLOAT:
return sizeof (float);
case AF_SAMPFMT_DOUBLE:
return sizeof (double);
default:
{
int size = (sampleWidth + 7) / 8;
if (compressionType == AF_COMPRESSION_NONE &&
size == 3 && stretch3to4)
size = 4;
return size;
}
}
}
size_t AudioFormat::bytesPerFrame(bool stretch3to4) const
{
return bytesPerSample(stretch3to4) * channelCount;
}
size_t AudioFormat::bytesPerSample() const
{
return bytesPerSample(!isPacked());
}
size_t AudioFormat::bytesPerFrame() const
{
return bytesPerFrame(!isPacked());
}
bool AudioFormat::isInteger() const
{
return sampleFormat == AF_SAMPFMT_TWOSCOMP ||
sampleFormat == AF_SAMPFMT_UNSIGNED;
}
bool AudioFormat::isSigned() const
{
return sampleFormat == AF_SAMPFMT_TWOSCOMP;
}
bool AudioFormat::isUnsigned() const
{
return sampleFormat == AF_SAMPFMT_UNSIGNED;
}
bool AudioFormat::isFloat() const
{
return sampleFormat == AF_SAMPFMT_FLOAT ||
sampleFormat == AF_SAMPFMT_DOUBLE;
}
bool AudioFormat::isCompressed() const
{
return compressionType != AF_COMPRESSION_NONE;
}
bool AudioFormat::isUncompressed() const
{
return compressionType == AF_COMPRESSION_NONE;
}
void AudioFormat::computeBytesPerPacketPCM()
{
assert(isUncompressed());
int bytesPerSample = (sampleWidth + 7) / 8;
bytesPerPacket = bytesPerSample * channelCount;
}
std::string AudioFormat::description() const
{
std::string d;
char s[1024];
sprintf(s, "{ %7.2f Hz %d ch ", sampleRate, channelCount);
d += s;
switch (sampleFormat)
{
case AF_SAMPFMT_TWOSCOMP:
sprintf(s, "%db 2 ", sampleWidth);
break;
case AF_SAMPFMT_UNSIGNED:
sprintf(s, "%db u ", sampleWidth);
break;
case AF_SAMPFMT_FLOAT:
sprintf(s, "flt ");
break;
case AF_SAMPFMT_DOUBLE:
sprintf(s, "dbl ");
break;
default:
assert(false);
break;
}
d += s;
sprintf(s, "(%.30g+-%.30g [%.30g,%.30g]) ",
pcm.intercept, pcm.slope,
pcm.minClip, pcm.maxClip);
d += s;
switch (byteOrder)
{
case AF_BYTEORDER_BIGENDIAN:
d += "big ";
break;
case AF_BYTEORDER_LITTLEENDIAN:
d += "little ";
break;
default:
assert(false);
break;
}
if (isCompressed())
{
const CompressionUnit *unit = _af_compression_unit_from_id(compressionType);
assert(unit);
d += "compression: ";
d += unit->label;
}
return d;
}
#include <string.h>
Buffer::Buffer() : m_data(0), m_size(0)
{
}
Buffer::Buffer(size_t size) : m_data(0), m_size(0)
{
if (size)
m_data = ::operator new(size);
if (m_data)
{
m_size = size;
}
}
Buffer::Buffer(const void *data, size_t size) : m_data(0), m_size(0)
{
if (size)
m_data = ::operator new(size);
if (m_data)
{
::memcpy(m_data, data, m_size);
m_size = size;
}
}
Buffer::~Buffer()
{
::operator delete(m_data);
}
#include <assert.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
class FilePOSIX : public File
{
public:
FilePOSIX(int fd, AccessMode mode) : File(mode), m_fd(fd) { }
virtual ~FilePOSIX() { close(); }
virtual int close() OVERRIDE;
virtual ssize_t read(void *data, size_t nbytes) OVERRIDE;
virtual ssize_t write(const void *data, size_t nbytes) OVERRIDE;
virtual off_t length() OVERRIDE;
virtual off_t seek(off_t offset, SeekOrigin origin) OVERRIDE;
virtual off_t tell() OVERRIDE;
private:
int m_fd;
};
class FileVF : public File
{
public:
FileVF(AFvirtualfile *vf, AccessMode mode) : File(mode), m_vf(vf) { }
virtual ~FileVF() { close(); }
virtual int close() OVERRIDE;
virtual ssize_t read(void *data, size_t nbytes) OVERRIDE;
virtual ssize_t write(const void *data, size_t nbytes) OVERRIDE;
virtual off_t length() OVERRIDE;
virtual off_t seek(off_t offset, SeekOrigin origin) OVERRIDE;
virtual off_t tell() OVERRIDE;
private:
AFvirtualfile *m_vf;
};
File *File::open(const char *path, File::AccessMode mode)
{
int flags = 0;
if (mode == ReadAccess)
flags = O_RDONLY;
else if (mode == WriteAccess)
flags = O_CREAT | O_WRONLY | O_TRUNC;
#if defined(WIN32) || defined(__CYGWIN__)
flags |= O_BINARY;
#endif
int fd = ::open(path, flags, 0666);
if (fd == -1)
return NULL;
File *file = new FilePOSIX(fd, mode);
return file;
}
File *File::create(int fd, File::AccessMode mode)
{
return new FilePOSIX(fd, mode);
}
File *File::create(AFvirtualfile *vf, File::AccessMode mode)
{
return new FileVF(vf, mode);
}
File::~File()
{
}
bool File::canSeek()
{
return seek(0, File::SeekFromCurrent) != -1;
}
int FilePOSIX::close()
{
if (m_fd == -1)
return 0;
int result = ::close(m_fd);
m_fd = -1;
return result;
}
ssize_t FilePOSIX::read(void *data, size_t nbytes)
{
return ::read(m_fd, data, nbytes);
}
ssize_t FilePOSIX::write(const void *data, size_t nbytes)
{
return ::write(m_fd, data, nbytes);
}
off_t FilePOSIX::length()
{
off_t current = tell();
if (current == -1)
return -1;
off_t length = seek(0, SeekFromEnd);
if (length == -1)
return -1;
seek(current, SeekFromBeginning);
return length;
}
off_t FilePOSIX::seek(off_t offset, File::SeekOrigin origin)
{
int whence;
switch (origin)
{
case SeekFromBeginning: whence = SEEK_SET; break;
case SeekFromCurrent: whence = SEEK_CUR; break;
case SeekFromEnd: whence = SEEK_END; break;
default: assert(false); return -1;
}
return ::lseek(m_fd, offset, whence);
}
off_t FilePOSIX::tell()
{
return seek(0, File::SeekFromCurrent);
}
int FileVF::close()
{
if (m_vf)
af_virtual_file_destroy(m_vf);
m_vf = 0;
return 0;
}
ssize_t FileVF::read(void *data, size_t nbytes)
{
return m_vf->read(m_vf, data, nbytes);
}
ssize_t FileVF::write(const void *data, size_t nbytes)
{
return m_vf->write(m_vf, data, nbytes);
}
off_t FileVF::length()
{
return m_vf->length(m_vf);
}
off_t FileVF::seek(off_t offset, SeekOrigin origin)
{
if (origin == SeekFromEnd)
offset += length();
return m_vf->seek(m_vf, offset, origin == SeekFromCurrent);
}
off_t FileVF::tell()
{
return m_vf->tell(m_vf);
}
#include <stdlib.h>
#include <assert.h>
static void freeInstParams (AFPVu *values, int fileFormat)
{
if (!values)
return;
int parameterCount = _af_units[fileFormat].instrumentParameterCount;
for (int i=0; i<parameterCount; i++)
{
if (_af_units[fileFormat].instrumentParameters[i].type == AU_PVTYPE_PTR)
free(values[i].v);
}
free(values);
}
_AFfilehandle *_AFfilehandle::create(int fileFormat)
{
switch (fileFormat)
{
case AF_FILE_RAWDATA:
return new RawFile();
case AF_FILE_AIFF:
case AF_FILE_AIFFC:
return new AIFFFile();
case AF_FILE_WAVE:
return new WAVEFile();
default:
return NULL;
}
}
_AFfilehandle::_AFfilehandle()
{
m_valid = _AF_VALID_FILEHANDLE;
m_access = 0;
m_seekok = false;
m_fh = NULL;
m_fileName = NULL;
m_fileFormat = AF_FILE_UNKNOWN;
m_trackCount = 0;
m_tracks = NULL;
m_instrumentCount = 0;
m_instruments = NULL;
m_miscellaneousCount = 0;
m_miscellaneous = NULL;
m_formatByteOrder = 0;
}
_AFfilehandle::~_AFfilehandle()
{
m_valid = 0;
free(m_fileName);
delete [] m_tracks;
m_tracks = NULL;
m_trackCount = 0;
if (m_instruments)
{
for (int i=0; i<m_instrumentCount; i++)
{
free(m_instruments[i].loops);
m_instruments[i].loops = NULL;
m_instruments[i].loopCount = 0;
freeInstParams(m_instruments[i].values, m_fileFormat);
m_instruments[i].values = NULL;
}
free(m_instruments);
m_instruments = NULL;
}
m_instrumentCount = 0;
if (m_miscellaneous)
{
for (int i=0; i<m_miscellaneousCount; i++)
free(m_miscellaneous[i].buffer);
free(m_miscellaneous);
m_miscellaneous = NULL;
}
m_miscellaneousCount = 0;
}
Track *_AFfilehandle::allocateTrack()
{
assert(!m_trackCount);
assert(!m_tracks);
m_trackCount = 1;
m_tracks = new Track[1];
return m_tracks;
}
Track *_AFfilehandle::getTrack(int trackID)
{
for (int i=0; i<m_trackCount; i++)
if (m_tracks[i].id == trackID)
return &m_tracks[i];
_af_error(AF_BAD_TRACKID, "bad track id %d", trackID);
return NULL;
}
bool _AFfilehandle::checkCanRead()
{
if (m_access != _AF_READ_ACCESS)
{
_af_error(AF_BAD_NOREADACC, "file not opened for read access");
return false;
}
return true;
}
bool _AFfilehandle::checkCanWrite()
{
if (m_access != _AF_WRITE_ACCESS)
{
_af_error(AF_BAD_NOWRITEACC, "file not opened for write access");
return false;
}
return true;
}
Instrument *_AFfilehandle::getInstrument(int instrumentID)
{
for (int i = 0; i < m_instrumentCount; i++)
if (m_instruments[i].id == instrumentID)
return &m_instruments[i];
_af_error(AF_BAD_INSTID, "invalid instrument id %d", instrumentID);
return NULL;
}
Miscellaneous *_AFfilehandle::getMiscellaneous(int miscellaneousID)
{
for (int i=0; i<m_miscellaneousCount; i++)
{
if (m_miscellaneous[i].id == miscellaneousID)
return &m_miscellaneous[i];
}
_af_error(AF_BAD_MISCID, "bad miscellaneous id %d", miscellaneousID);
return NULL;
}
status _AFfilehandle::initFromSetup(AFfilesetup setup)
{
if (copyTracksFromSetup(setup) == AF_FAIL)
return AF_FAIL;
if (copyInstrumentsFromSetup(setup) == AF_FAIL)
return AF_FAIL;
if (copyMiscellaneousFromSetup(setup) == AF_FAIL)
return AF_FAIL;
return AF_SUCCEED;
}
status _AFfilehandle::copyTracksFromSetup(AFfilesetup setup)
{
if ((m_trackCount = setup->trackCount) == 0)
{
m_tracks = NULL;
return AF_SUCCEED;
}
m_tracks = new Track[m_trackCount];
if (!m_tracks)
return AF_FAIL;
for (int i=0; i<m_trackCount; i++)
{
Track *track = &m_tracks[i];
TrackSetup *trackSetup = &setup->tracks[i];
track->id = trackSetup->id;
track->f = trackSetup->f;
if (track->copyMarkers(trackSetup) == AF_FAIL)
return AF_FAIL;
track->hasAESData = trackSetup->aesDataSet;
}
return AF_SUCCEED;
}
status _AFfilehandle::copyInstrumentsFromSetup(AFfilesetup setup)
{
if ((m_instrumentCount = setup->instrumentCount) == 0)
{
m_instruments = NULL;
return AF_SUCCEED;
}
m_instruments = static_cast<Instrument *>(_af_calloc(m_instrumentCount,
sizeof (Instrument)));
if (!m_instruments)
return AF_FAIL;
for (int i=0; i<m_instrumentCount; i++)
{
m_instruments[i].id = setup->instruments[i].id;
if ((m_instruments[i].loopCount = setup->instruments[i].loopCount) == 0)
{
m_instruments[i].loops = NULL;
}
else
{
m_instruments[i].loops =
static_cast<Loop *>(_af_calloc(m_instruments[i].loopCount,
sizeof (Loop)));
if (!m_instruments[i].loops)
return AF_FAIL;
for (int j=0; j<m_instruments[i].loopCount; j++)
{
Loop *loop = &m_instruments[i].loops[j];
loop->id = setup->instruments[i].loops[j].id;
loop->mode = AF_LOOP_MODE_NOLOOP;
loop->count = 0;
loop->trackid = AF_DEFAULT_TRACK;
loop->beginMarker = 2*j + 1;
loop->endMarker = 2*j + 2;
}
}
int instParamCount;
if ((instParamCount = _af_units[setup->fileFormat].instrumentParameterCount) == 0)
{
m_instruments[i].values = NULL;
}
else
{
m_instruments[i].values =
static_cast<AFPVu *>(_af_calloc(instParamCount, sizeof (AFPVu)));
if (!m_instruments[i].values)
return AF_FAIL;
for (int j=0; j<instParamCount; j++)
{
m_instruments[i].values[j] = _af_units[setup->fileFormat].instrumentParameters[j].defaultValue;
}
}
}
return AF_SUCCEED;
}
status _AFfilehandle::copyMiscellaneousFromSetup(AFfilesetup setup)
{
if ((m_miscellaneousCount = setup->miscellaneousCount) == 0)
{
m_miscellaneous = NULL;
return AF_SUCCEED;
}
m_miscellaneous = static_cast<Miscellaneous *>(_af_calloc(m_miscellaneousCount,
sizeof (Miscellaneous)));
if (!m_miscellaneous)
return AF_FAIL;
for (int i=0; i<m_miscellaneousCount; i++)
{
m_miscellaneous[i].id = setup->miscellaneous[i].id;
m_miscellaneous[i].type = setup->miscellaneous[i].type;
m_miscellaneous[i].size = setup->miscellaneous[i].size;
m_miscellaneous[i].position = 0;
m_miscellaneous[i].buffer = NULL;
}
return AF_SUCCEED;
}
template <typename T>
static bool readValue(File *f, T *value)
{
return f->read(value, sizeof (*value)) == sizeof (*value);
}
template <typename T>
static bool writeValue(File *f, const T *value)
{
return f->write(value, sizeof (*value)) == sizeof (*value);
}
template <typename T>
static T swapValue(T value, int order)
{
if (order == AF_BYTEORDER_BIGENDIAN)
return bigToHost(value);
else if (order == AF_BYTEORDER_LITTLEENDIAN)
return littleToHost(value);
return value;
}
template <typename T>
static bool readSwap(File *f, T *value, int order)
{
if (!readValue(f, value)) return false;
*value = swapValue(*value, order);
return true;
}
template <typename T>
static bool writeSwap(File *f, const T *value, int order)
{
T t = swapValue(*value, order);
return writeValue(f, &t);
}
bool _AFfilehandle::readU8(uint8_t *v) { return readValue(m_fh, v); }
bool _AFfilehandle::readS8(int8_t *v) { return readValue(m_fh, v); }
bool _AFfilehandle::readU16(uint16_t *v)
{
return readSwap(m_fh, v, m_formatByteOrder);
}
bool _AFfilehandle::readS16(int16_t *v)
{
return readSwap(m_fh, v, m_formatByteOrder);
}
bool _AFfilehandle::readU32(uint32_t *v)
{
return readSwap(m_fh, v, m_formatByteOrder);
}
bool _AFfilehandle::readS32(int32_t *v)
{
return readSwap(m_fh, v, m_formatByteOrder);
}
bool _AFfilehandle::readU64(uint64_t *v)
{
return readSwap(m_fh, v, m_formatByteOrder);
}
bool _AFfilehandle::readS64(int64_t *v)
{
return readSwap(m_fh, v, m_formatByteOrder);
}
bool _AFfilehandle::readFloat(float *v)
{
return readSwap(m_fh, v, m_formatByteOrder);
}
bool _AFfilehandle::readDouble(double *v)
{
return readSwap(m_fh, v, m_formatByteOrder);
}
bool _AFfilehandle::writeU8(const uint8_t *v) { return writeValue(m_fh, v); }
bool _AFfilehandle::writeS8(const int8_t *v) { return writeValue(m_fh, v); }
bool _AFfilehandle::writeU16(const uint16_t *v)
{
return writeSwap(m_fh, v, m_formatByteOrder);
}
bool _AFfilehandle::writeS16(const int16_t *v)
{
return writeSwap(m_fh, v, m_formatByteOrder);
}
bool _AFfilehandle::writeU32(const uint32_t *v)
{
return writeSwap(m_fh, v, m_formatByteOrder);
}
bool _AFfilehandle::writeS32(const int32_t *v)
{
return writeSwap(m_fh, v, m_formatByteOrder);
}
bool _AFfilehandle::writeU64(const uint64_t *v)
{
return writeSwap(m_fh, v, m_formatByteOrder);
}
bool _AFfilehandle::writeS64(const int64_t *v)
{
return writeSwap(m_fh, v, m_formatByteOrder);
}
bool _AFfilehandle::writeFloat(const float *v)
{
return writeSwap(m_fh, v, m_formatByteOrder);
}
bool _AFfilehandle::writeDouble(const double *v)
{
return writeSwap(m_fh, v, m_formatByteOrder);
}
bool _AFfilehandle::readTag(Tag *t)
{
uint32_t v;
if (m_fh->read(&v, sizeof (v)) == sizeof (v))
{
*t = Tag(v);
return true;
}
return false;
}
bool _AFfilehandle::writeTag(const Tag *t)
{
uint32_t v = t->value();
return m_fh->write(&v, sizeof (v)) == sizeof (v);
}
#include <stdlib.h>
bool InstrumentSetup::allocateLoops(int count)
{
freeLoops();
loops = (LoopSetup *) _af_calloc(count, sizeof (LoopSetup));
if (loops)
{
loopCount = count;
return true;
}
return false;
}
void InstrumentSetup::freeLoops()
{
if (loops)
free(loops);
loops = NULL;
loopCount = 0;
}
void afInitInstIDs (AFfilesetup setup, const int *instids, int ninsts)
{
if (!_af_filesetup_ok(setup))
return;
if (!_af_unique_ids(instids, ninsts, "instrument", AF_BAD_INSTID))
return;
_af_setup_free_instruments(setup);
setup->instrumentCount = ninsts;
setup->instrumentSet = true;
setup->instruments = _af_instsetup_new(setup->instrumentCount);
for (int i=0; i < setup->instrumentCount; i++)
setup->instruments[i].id = instids[i];
}
int afGetInstIDs (AFfilehandle file, int *instids)
{
if (!_af_filehandle_ok(file))
return -1;
if (instids)
for (int i=0; i < file->m_instrumentCount; i++)
instids[i] = file->m_instruments[i].id;
return file->m_instrumentCount;
}
void _af_instparam_set (AFfilehandle file, int instid, AUpvlist pvlist, int npv)
{
if (!_af_filehandle_ok(file))
return;
if (!file->checkCanWrite())
return;
Instrument *instrument = file->getInstrument(instid);
if (!instrument)
return;
if (AUpvgetmaxitems(pvlist) < npv)
npv = AUpvgetmaxitems(pvlist);
for (int i=0; i < npv; i++)
{
int param;
AUpvgetparam(pvlist, i, ¶m);
int j;
if ((j = _af_instparam_index_from_id(file->m_fileFormat, param)) == -1)
continue;
if (!file->isInstrumentParameterValid(pvlist, i))
continue;
int type = _af_units[file->m_fileFormat].instrumentParameters[j].type;
switch (type)
{
case AU_PVTYPE_LONG:
AUpvgetval(pvlist, i, &instrument->values[j].l);
break;
case AU_PVTYPE_DOUBLE:
AUpvgetval(pvlist, i, &instrument->values[j].d);
break;
case AU_PVTYPE_PTR:
AUpvgetval(pvlist, i, &instrument->values[j].v);
break;
default:
return;
}
}
}
void afSetInstParams (AFfilehandle file, int instid, AUpvlist pvlist, int npv)
{
_af_instparam_set(file, instid, pvlist, npv);
}
void afSetInstParamLong (AFfilehandle file, int instid, int param, long value)
{
AUpvlist pvlist = AUpvnew(1);
AUpvsetparam(pvlist, 0, param);
AUpvsetvaltype(pvlist, 0, AU_PVTYPE_LONG);
AUpvsetval(pvlist, 0, &value);
_af_instparam_set(file, instid, pvlist, 1);
AUpvfree(pvlist);
}
void _af_instparam_get (AFfilehandle file, int instid, AUpvlist pvlist, int npv,
bool forceLong)
{
if (!_af_filehandle_ok(file))
return;
Instrument *instrument = file->getInstrument(instid);
if (!instrument)
return;
if (AUpvgetmaxitems(pvlist) < npv)
npv = AUpvgetmaxitems(pvlist);
for (int i=0; i < npv; i++)
{
int param;
AUpvgetparam(pvlist, i, ¶m);
int j;
if ((j = _af_instparam_index_from_id(file->m_fileFormat, param)) == -1)
continue;
int type = _af_units[file->m_fileFormat].instrumentParameters[j].type;
if (forceLong && type != AU_PVTYPE_LONG)
{
_af_error(AF_BAD_INSTPTYPE, "type of instrument parameter %d is not AU_PVTYPE_LONG", param);
continue;
}
AUpvsetvaltype(pvlist, i, type);
switch (type)
{
case AU_PVTYPE_LONG:
AUpvsetval(pvlist, i, &instrument->values[j].l);
break;
case AU_PVTYPE_DOUBLE:
AUpvsetval(pvlist, i, &instrument->values[j].d);
break;
case AU_PVTYPE_PTR:
AUpvsetval(pvlist, i, &instrument->values[j].v);
break;
default:
_af_error(AF_BAD_INSTPTYPE, "invalid instrument parameter type %d", type);
return;
}
}
}
void afGetInstParams (AFfilehandle file, int inst, AUpvlist pvlist, int npv)
{
_af_instparam_get(file, inst, pvlist, npv, false);
}
long afGetInstParamLong (AFfilehandle file, int inst, int param)
{
long val;
AUpvlist pvlist = AUpvnew(1);
AUpvsetparam(pvlist, 0, param);
AUpvsetvaltype(pvlist, 0, AU_PVTYPE_LONG);
_af_instparam_get(file, inst, pvlist, 1, true);
AUpvgetval(pvlist, 0, &val);
AUpvfree(pvlist);
return(val);
}
int _af_instparam_index_from_id (int filefmt, int id)
{
int i;
for (i = 0; i < _af_units[filefmt].instrumentParameterCount; i++)
if (_af_units[filefmt].instrumentParameters[i].id == id)
break;
if (i == _af_units[filefmt].instrumentParameterCount)
{
_af_error(AF_BAD_INSTPID, "invalid instrument parameter id %d",
id);
return -1;
}
return i;
}
Loop *Instrument::getLoop(int loopID)
{
for (int i=0; i<loopCount; i++)
if (loops[i].id == loopID)
return &loops[i];
_af_error(AF_BAD_LOOPID, "no loop with id %d for instrument %d\n",
loopID, id);
return NULL;
}
void afInitLoopIDs (AFfilesetup setup, int instid, const int *loopids, int nloops)
{
if (!_af_filesetup_ok(setup))
return;
if (!_af_unique_ids(loopids, nloops, "loop", AF_BAD_LOOPID))
return;
InstrumentSetup *instrument = setup->getInstrument(instid);
if (!instrument)
return;
instrument->freeLoops();
if (!instrument->allocateLoops(nloops))
return;
for (int i=0; i < nloops; i++)
instrument->loops[i].id = loopids[i];
}
int afGetLoopIDs (AFfilehandle file, int instid, int *loopids)
{
if (!_af_filehandle_ok(file))
return AF_FAIL;
Instrument *instrument = file->getInstrument(instid);
if (!instrument)
return AF_FAIL;
if (loopids)
for (int i=0; i < instrument->loopCount; i++)
loopids[i] = instrument->loops[i].id;
return instrument->loopCount;
}
static Loop *getLoop (AFfilehandle handle, int instid, int loopid,
bool mustWrite)
{
if (!_af_filehandle_ok(handle))
return NULL;
if (mustWrite && !handle->checkCanWrite())
return NULL;
Instrument *instrument = handle->getInstrument(instid);
if (!instrument)
return NULL;
return instrument->getLoop(loopid);
}
void afSetLoopMode (AFfilehandle file, int instid, int loopid, int mode)
{
Loop *loop = getLoop(file, instid, loopid, true);
if (!loop)
return;
if (mode != AF_LOOP_MODE_NOLOOP &&
mode != AF_LOOP_MODE_FORW &&
mode != AF_LOOP_MODE_FORWBAKW)
{
_af_error(AF_BAD_LOOPMODE, "unrecognized loop mode %d", mode);
return;
}
loop->mode = mode;
}
int afGetLoopMode (AFfilehandle file, int instid, int loopid)
{
Loop *loop = getLoop(file, instid, loopid, false);
if (!loop)
return -1;
return loop->mode;
}
int afSetLoopCount (AFfilehandle file, int instid, int loopid, int count)
{
Loop *loop = getLoop(file, instid, loopid, true);
if (!loop)
return AF_FAIL;
if (count < 1)
{
_af_error(AF_BAD_LOOPCOUNT, "invalid loop count: %d", count);
return AF_FAIL;
}
loop->count = count;
return AF_SUCCEED;
}
int afGetLoopCount(AFfilehandle file, int instid, int loopid)
{
Loop *loop = getLoop(file, instid, loopid, false);
if (!loop)
return -1;
return loop->count;
}
void afSetLoopStart(AFfilehandle file, int instid, int loopid, int markid)
{
Loop *loop = getLoop(file, instid, loopid, true);
if (!loop)
return;
loop->beginMarker = markid;
}
int afGetLoopStart (AFfilehandle file, int instid, int loopid)
{
Loop *loop = getLoop(file, instid, loopid, false);
if (!loop)
return -1;
return loop->beginMarker;
}
int afSetLoopStartFrame (AFfilehandle file, int instid, int loopid, AFframecount startFrame)
{
Loop *loop = getLoop(file, instid, loopid, true);
if (!loop)
return -1;
if (startFrame < 0)
{
_af_error(AF_BAD_FRAME, "loop start frame must not be negative");
return AF_FAIL;
}
int trackid = loop->trackid;
int beginMarker = loop->beginMarker;
afSetMarkPosition(file, trackid, beginMarker, startFrame);
return AF_SUCCEED;
}
AFframecount afGetLoopStartFrame (AFfilehandle file, int instid, int loopid)
{
Loop *loop = getLoop(file, instid, loopid, false);
if (!loop)
return -1;
int trackid = loop->trackid;
int beginMarker = loop->beginMarker;
return afGetMarkPosition(file, trackid, beginMarker);
}
void afSetLoopTrack (AFfilehandle file, int instid, int loopid, int track)
{
Loop *loop = getLoop(file, instid, loopid, true);
if (!loop) return;
loop->trackid = track;
}
int afGetLoopTrack (AFfilehandle file, int instid, int loopid)
{
Loop *loop = getLoop(file, instid, loopid, false);
if (!loop)
return -1;
return loop->trackid;
}
void afSetLoopEnd (AFfilehandle file, int instid, int loopid, int markid)
{
Loop *loop = getLoop(file, instid, loopid, true);
if (!loop)
return;
loop->endMarker = markid;
}
int afGetLoopEnd (AFfilehandle file, int instid, int loopid)
{
Loop *loop = getLoop(file, instid, loopid, false);
if (!loop)
return -1;
return loop->endMarker;
}
int afSetLoopEndFrame (AFfilehandle file, int instid, int loopid, AFframecount endFrame)
{
Loop *loop = getLoop(file, instid, loopid, true);
if (!loop)
return -1;
if (endFrame < 0)
{
_af_error(AF_BAD_FRAME, "loop end frame must not be negative");
return AF_FAIL;
}
int trackid = loop->trackid;
int endMarker = loop->endMarker;
afSetMarkPosition(file, trackid, endMarker, endFrame);
return AF_SUCCEED;
}
AFframecount afGetLoopEndFrame (AFfilehandle file, int instid, int loopid)
{
Loop *loop = getLoop(file, instid, loopid, false);
if (!loop)
return -1;
int trackid = loop->trackid;
int endMarker = loop->endMarker;
return afGetMarkPosition(file, trackid, endMarker);
}
#include <string.h>
#include <stdlib.h>
#include <assert.h>
void afInitMarkIDs(AFfilesetup setup, int trackid, const int *markids, int nmarks)
{
if (!_af_filesetup_ok(setup))
return;
TrackSetup *track = setup->getTrack(trackid);
if (!track)
return;
if (track->markers != NULL)
{
for (int i=0; i<track->markerCount; i++)
{
if (track->markers[i].name != NULL)
free(track->markers[i].name);
if (track->markers[i].comment != NULL)
free(track->markers[i].comment);
}
free(track->markers);
}
track->markers = (MarkerSetup *) _af_calloc(nmarks, sizeof (struct MarkerSetup));
track->markerCount = nmarks;
for (int i=0; i<nmarks; i++)
{
track->markers[i].id = markids[i];
track->markers[i].name = _af_strdup("");
track->markers[i].comment = _af_strdup("");
}
track->markersSet = true;
}
void afInitMarkName(AFfilesetup setup, int trackid, int markid,
const char *namestr)
{
int markno;
int length;
if (!_af_filesetup_ok(setup))
return;
TrackSetup *track = setup->getTrack(trackid);
if (!track)
return;
for (markno=0; markno<track->markerCount; markno++)
{
if (track->markers[markno].id == markid)
break;
}
if (markno == track->markerCount)
{
_af_error(AF_BAD_MARKID, "no marker id %d for file setup", markid);
return;
}
length = strlen(namestr);
if (length > 255)
{
_af_error(AF_BAD_STRLEN,
"warning: marker name truncated to 255 characters");
length = 255;
}
if (track->markers[markno].name)
free(track->markers[markno].name);
if ((track->markers[markno].name = (char *) _af_malloc(length+1)) == NULL)
return;
strncpy(track->markers[markno].name, namestr, length);
track->markers[markno].name[length] = '\0';
}
void afInitMarkComment(AFfilesetup setup, int trackid, int markid,
const char *commstr)
{
int markno;
int length;
if (!_af_filesetup_ok(setup))
return;
TrackSetup *track = setup->getTrack(trackid);
if (!track)
return;
for (markno=0; markno<track->markerCount; markno++)
{
if (track->markers[markno].id == markid)
break;
}
if (markno == track->markerCount)
{
_af_error(AF_BAD_MARKID, "no marker id %d for file setup", markid);
return;
}
length = strlen(commstr);
if (track->markers[markno].comment)
free(track->markers[markno].comment);
if ((track->markers[markno].comment = (char *) _af_malloc(length+1)) == NULL)
return;
strcpy(track->markers[markno].comment, commstr);
}
char *afGetMarkName (AFfilehandle file, int trackid, int markid)
{
if (!_af_filehandle_ok(file))
return NULL;
Track *track = file->getTrack(trackid);
if (!track)
return NULL;
Marker *marker = track->getMarker(markid);
if (!marker)
return NULL;
return marker->name;
}
char *afGetMarkComment (AFfilehandle file, int trackid, int markid)
{
if (!_af_filehandle_ok(file))
return NULL;
Track *track = file->getTrack(trackid);
if (!track)
return NULL;
Marker *marker = track->getMarker(markid);
if (!marker)
return NULL;
return marker->comment;
}
void afSetMarkPosition (AFfilehandle file, int trackid, int markid,
AFframecount position)
{
if (!_af_filehandle_ok(file))
return;
if (!file->checkCanWrite())
return;
Track *track = file->getTrack(trackid);
if (!track)
return;
Marker *marker = track->getMarker(markid);
if (!marker)
return;
if (position < 0)
{
_af_error(AF_BAD_MARKPOS, "invalid marker position %jd",
static_cast<intmax_t>(position));
position = 0;
}
marker->position = position;
}
int afGetMarkIDs (AFfilehandle file, int trackid, int markids[])
{
if (!_af_filehandle_ok(file))
return -1;
Track *track = file->getTrack(trackid);
if (!track)
return -1;
if (markids != NULL)
{
for (int i=0; i<track->markerCount; i++)
{
markids[i] = track->markers[i].id;
}
}
return track->markerCount;
}
AFframecount afGetMarkPosition (AFfilehandle file, int trackid, int markid)
{
if (!_af_filehandle_ok(file))
return 0L;
Track *track = file->getTrack(trackid);
if (!track)
return 0L;
Marker *marker = track->getMarker(markid);
if (!marker)
return 0L;
return marker->position;
}
Marker *_af_marker_new (int count)
{
Marker *markers = (Marker *) _af_calloc(count, sizeof (Marker));
if (markers == NULL)
return NULL;
return markers;
}
#include <algorithm>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
void afInitMiscIDs (AFfilesetup setup, const int *ids, int nids)
{
if (!_af_filesetup_ok(setup))
return;
if (setup->miscellaneous != NULL)
{
free(setup->miscellaneous);
}
setup->miscellaneousCount = nids;
if (nids == 0)
setup->miscellaneous = NULL;
else
{
setup->miscellaneous = (MiscellaneousSetup *) _af_calloc(nids,
sizeof (MiscellaneousSetup));
if (setup->miscellaneous == NULL)
return;
for (int i=0; i<nids; i++)
{
setup->miscellaneous[i].id = ids[i];
setup->miscellaneous[i].type = 0;
setup->miscellaneous[i].size = 0;
}
}
setup->miscellaneousSet = true;
}
int afGetMiscIDs (AFfilehandle file, int *ids)
{
if (!_af_filehandle_ok(file))
return -1;
if (ids != NULL)
{
for (int i=0; i<file->m_miscellaneousCount; i++)
{
ids[i] = file->m_miscellaneous[i].id;
}
}
return file->m_miscellaneousCount;
}
void afInitMiscType (AFfilesetup setup, int miscellaneousid, int type)
{
if (!_af_filesetup_ok(setup))
return;
MiscellaneousSetup *miscellaneous = setup->getMiscellaneous(miscellaneousid);
if (miscellaneous)
miscellaneous->type = type;
}
int afGetMiscType (AFfilehandle file, int miscellaneousid)
{
if (!_af_filehandle_ok(file))
return -1;
Miscellaneous *miscellaneous = file->getMiscellaneous(miscellaneousid);
if (miscellaneous)
return miscellaneous->type;
return -1;
}
void afInitMiscSize (AFfilesetup setup, int miscellaneousid, int size)
{
if (!_af_filesetup_ok(setup))
return;
MiscellaneousSetup *miscellaneous = setup->getMiscellaneous(miscellaneousid);
if (miscellaneous)
miscellaneous->size = size;
}
int afGetMiscSize (AFfilehandle file, int miscellaneousid)
{
if (!_af_filehandle_ok(file))
return -1;
Miscellaneous *miscellaneous = file->getMiscellaneous(miscellaneousid);
if (miscellaneous)
return miscellaneous->size;
return -1;
}
int afWriteMisc (AFfilehandle file, int miscellaneousid, const void *buf, int bytes)
{
if (!_af_filehandle_ok(file))
return -1;
if (!file->checkCanWrite())
return -1;
Miscellaneous *miscellaneous = file->getMiscellaneous(miscellaneousid);
if (!miscellaneous)
return -1;
if (bytes <= 0)
{
_af_error(AF_BAD_MISCSIZE, "invalid size (%d) for miscellaneous chunk", bytes);
return -1;
}
if (miscellaneous->buffer == NULL && miscellaneous->size != 0)
{
miscellaneous->buffer = _af_malloc(miscellaneous->size);
if (miscellaneous->buffer == NULL)
return -1;
memset(miscellaneous->buffer, 0, miscellaneous->size);
}
int localsize = std::min(bytes,
miscellaneous->size - miscellaneous->position);
memcpy((char *) miscellaneous->buffer + miscellaneous->position,
buf, localsize);
miscellaneous->position += localsize;
return localsize;
}
int afReadMisc (AFfilehandle file, int miscellaneousid, void *buf, int bytes)
{
if (!_af_filehandle_ok(file))
return -1;
if (!file->checkCanRead())
return -1;
Miscellaneous *miscellaneous = file->getMiscellaneous(miscellaneousid);
if (!miscellaneous)
return -1;
if (bytes <= 0)
{
_af_error(AF_BAD_MISCSIZE, "invalid size (%d) for miscellaneous chunk", bytes);
return -1;
}
int localsize = std::min(bytes,
miscellaneous->size - miscellaneous->position);
memcpy(buf, (char *) miscellaneous->buffer + miscellaneous->position,
localsize);
miscellaneous->position += localsize;
return localsize;
}
int afSeekMisc (AFfilehandle file, int miscellaneousid, int offset)
{
if (!_af_filehandle_ok(file))
return -1;
Miscellaneous *miscellaneous = file->getMiscellaneous(miscellaneousid);
if (!miscellaneous)
return -1;
if (offset >= miscellaneous->size)
{
_af_error(AF_BAD_MISCSEEK,
"offset %d too big for miscellaneous chunk %d "
"(%d data bytes)",
offset, miscellaneousid, miscellaneous->size);
return -1;
}
miscellaneous->position = offset;
return offset;
}
PacketTable::PacketTable(int64_t numValidFrames, int32_t primingFrames,
int32_t remainderFrames) :
m_numValidFrames(numValidFrames),
m_primingFrames(primingFrames),
m_remainderFrames(remainderFrames)
{
}
PacketTable::PacketTable()
{
m_numValidFrames = 0;
m_primingFrames = 0;
m_remainderFrames = 0;
}
PacketTable::~PacketTable()
{
}
void PacketTable::setNumValidFrames(int64_t numValidFrames)
{
m_numValidFrames = numValidFrames;
}
void PacketTable::setPrimingFrames(int32_t primingFrames)
{
m_primingFrames = primingFrames;
}
void PacketTable::setRemainderFrames(int32_t remainderFrames)
{
m_remainderFrames = remainderFrames;
}
void PacketTable::append(size_t bytesPerPacket)
{
m_bytesPerPacket.push_back(bytesPerPacket);
}
AFfileoffset PacketTable::startOfPacket(size_t packet) const
{
AFfileoffset offset = 0;
for (size_t i=0; i<packet; i++)
offset += m_bytesPerPacket[i];
return offset;
}
static const _AFfilesetup rawDefaultFileSetup =
{
_AF_VALID_FILESETUP,
AF_FILE_RAWDATA,
true,
true,
true,
1,
NULL,
0,
NULL,
0,
NULL
};
const int _af_raw_compression_types[_AF_RAW_NUM_COMPTYPES] =
{
AF_COMPRESSION_G711_ULAW,
AF_COMPRESSION_G711_ALAW
};
bool RawFile::recognize(File *fh)
{
return false;
}
status RawFile::readInit(AFfilesetup fileSetup)
{
if (!fileSetup)
{
_af_error(AF_BAD_FILESETUP, "a valid AFfilesetup is required for reading raw data");
return AF_FAIL;
}
if (initFromSetup(fileSetup) == AF_FAIL)
return AF_FAIL;
TrackSetup *trackSetup = fileSetup->getTrack();
if (!trackSetup)
return AF_FAIL;
Track *track = getTrack();
if (trackSetup->dataOffsetSet)
track->fpos_first_frame = trackSetup->dataOffset;
else
track->fpos_first_frame = 0;
if (trackSetup->frameCountSet)
{
track->totalfframes = trackSetup->frameCount;
}
else
{
AFfileoffset filesize = m_fh->length();
if (filesize == -1)
track->totalfframes = -1;
else
{
if (track->fpos_first_frame > filesize)
{
_af_error(AF_BAD_FILESETUP, "data offset is larger than file size");
return AF_FAIL;
}
filesize -= track->fpos_first_frame;
track->totalfframes = filesize / (int) _af_format_frame_size(&track->f, false);
}
track->data_size = filesize;
}
return AF_SUCCEED;
}
status RawFile::writeInit(AFfilesetup setup)
{
if (initFromSetup(setup) == AF_FAIL)
return AF_FAIL;
TrackSetup *trackSetup = setup->getTrack();
if (!trackSetup)
return AF_FAIL;
Track *track = getTrack();
if (trackSetup->dataOffsetSet)
track->fpos_first_frame = trackSetup->dataOffset;
else
track->fpos_first_frame = 0;
return AF_SUCCEED;
}
status RawFile::update()
{
return AF_SUCCEED;
}
AFfilesetup RawFile::completeSetup(AFfilesetup setup)
{
AFfilesetup newSetup;
if (setup->trackSet && setup->trackCount != 1)
{
_af_error(AF_BAD_FILESETUP, "raw file must have exactly one track");
return AF_NULL_FILESETUP;
}
TrackSetup *track = setup->getTrack();
if (!track)
{
_af_error(AF_BAD_FILESETUP, "could not access track in file setup");
return AF_NULL_FILESETUP;
}
if (track->aesDataSet)
{
_af_error(AF_BAD_FILESETUP, "raw file cannot have AES data");
return AF_NULL_FILESETUP;
}
if (track->markersSet && track->markerCount != 0)
{
_af_error(AF_BAD_NUMMARKS, "raw file cannot have markers");
return AF_NULL_FILESETUP;
}
if (setup->instrumentSet && setup->instrumentCount != 0)
{
_af_error(AF_BAD_NUMINSTS, "raw file cannot have instruments");
return AF_NULL_FILESETUP;
}
if (setup->miscellaneousSet && setup->miscellaneousCount != 0)
{
_af_error(AF_BAD_NUMMISC, "raw file cannot have miscellaneous data");
return AF_NULL_FILESETUP;
}
newSetup = (_AFfilesetup *) _af_malloc(sizeof (_AFfilesetup));
*newSetup = rawDefaultFileSetup;
newSetup->tracks = (TrackSetup *) _af_malloc(sizeof (TrackSetup));
newSetup->tracks[0] = setup->tracks[0];
newSetup->tracks[0].f.compressionParams = NULL;
newSetup->tracks[0].markerCount = 0;
newSetup->tracks[0].markers = NULL;
return newSetup;
}
#include <stdlib.h>
#include <string.h>
static const _AFfilesetup _af_default_file_setup =
{
_AF_VALID_FILESETUP,
#if WORDS_BIGENDIAN
AF_FILE_AIFFC,
#else
AF_FILE_WAVE,
#endif
false,
false,
false,
1,
NULL,
1,
NULL,
0,
NULL
};
static const InstrumentSetup _af_default_instrumentsetup =
{
0,
2,
NULL,
false
};
static const TrackSetup _af_default_tracksetup =
{
0,
{
44100.0,
AF_SAMPFMT_TWOSCOMP,
16,
_AF_BYTEORDER_NATIVE,
{ SLOPE_INT16, 0, MIN_INT16, MAX_INT16 },
2,
AF_COMPRESSION_NONE,
NULL
},
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
4,
NULL,
0,
0
};
TrackSetup *_af_tracksetup_new (int trackCount)
{
TrackSetup *tracks;
if (trackCount == 0)
return NULL;
tracks = (TrackSetup *) _af_calloc(trackCount, sizeof (TrackSetup));
if (tracks == NULL)
return NULL;
for (int i=0; i<trackCount; i++)
{
tracks[i] = _af_default_tracksetup;
tracks[i].id = AF_DEFAULT_TRACK + i;
_af_set_sample_format(&tracks[i].f, tracks[i].f.sampleFormat,
tracks[i].f.sampleWidth);
if (tracks[i].markerCount == 0)
tracks[i].markers = NULL;
else
{
tracks[i].markers = (MarkerSetup *) _af_calloc(tracks[i].markerCount,
sizeof (MarkerSetup));
if (tracks[i].markers == NULL)
return NULL;
for (int j=0; j<tracks[i].markerCount; j++)
{
tracks[i].markers[j].id = j+1;
tracks[i].markers[j].name = _af_strdup("");
if (tracks[i].markers[j].name == NULL)
return NULL;
tracks[i].markers[j].comment = _af_strdup("");
if (tracks[i].markers[j].comment == NULL)
return NULL;
}
}
}
return tracks;
}
InstrumentSetup *_af_instsetup_new (int instrumentCount)
{
InstrumentSetup *instruments;
if (instrumentCount == 0)
return NULL;
instruments = (InstrumentSetup *) _af_calloc(instrumentCount, sizeof (InstrumentSetup));
if (instruments == NULL)
return NULL;
for (int i=0; i<instrumentCount; i++)
{
instruments[i] = _af_default_instrumentsetup;
instruments[i].id = AF_DEFAULT_INST + i;
if (instruments[i].loopCount == 0)
instruments[i].loops = NULL;
else
{
instruments[i].loops = (LoopSetup *) _af_calloc(instruments[i].loopCount, sizeof (LoopSetup));
if (instruments[i].loops == NULL)
return NULL;
for (int j=0; j<instruments[i].loopCount; j++)
instruments[i].loops[j].id = j+1;
}
}
return instruments;
}
AFfilesetup afNewFileSetup (void)
{
AFfilesetup setup;
setup = (_AFfilesetup *) _af_malloc(sizeof (_AFfilesetup));
if (setup == NULL) return AF_NULL_FILESETUP;
*setup = _af_default_file_setup;
setup->tracks = _af_tracksetup_new(setup->trackCount);
setup->instruments = _af_instsetup_new(setup->instrumentCount);
if (setup->miscellaneousCount == 0)
setup->miscellaneous = NULL;
else
{
setup->miscellaneous = (MiscellaneousSetup *) _af_calloc(setup->miscellaneousCount,
sizeof (MiscellaneousSetup));
for (int i=0; i<setup->miscellaneousCount; i++)
{
setup->miscellaneous[i].id = i+1;
setup->miscellaneous[i].type = 0;
setup->miscellaneous[i].size = 0;
}
}
return setup;
}
void _af_setup_free_markers (AFfilesetup setup, int trackno)
{
if (setup->tracks[trackno].markerCount != 0)
{
for (int i=0; i<setup->tracks[trackno].markerCount; i++)
{
free(setup->tracks[trackno].markers[i].name);
free(setup->tracks[trackno].markers[i].comment);
}
free(setup->tracks[trackno].markers);
}
setup->tracks[trackno].markers = NULL;
setup->tracks[trackno].markerCount = 0;
}
void _af_setup_free_tracks (AFfilesetup setup)
{
if (setup->tracks)
{
for (int i=0; i<setup->trackCount; i++)
{
_af_setup_free_markers(setup, i);
}
free(setup->tracks);
}
setup->tracks = NULL;
setup->trackCount = 0;
}
void _af_setup_free_instruments (AFfilesetup setup)
{
if (setup->instruments)
{
for (int i=0; i < setup->instrumentCount; i++)
setup->instruments[i].freeLoops();
free(setup->instruments);
}
setup->instruments = NULL;
setup->instrumentCount = 0;
}
void afFreeFileSetup (AFfilesetup setup)
{
if (!_af_filesetup_ok(setup))
return;
_af_setup_free_tracks(setup);
_af_setup_free_instruments(setup);
if (setup->miscellaneousCount)
{
free(setup->miscellaneous);
setup->miscellaneous = NULL;
setup->miscellaneousCount = 0;
}
memset(setup, 0, sizeof (_AFfilesetup));
free(setup);
}
void afInitFileFormat (AFfilesetup setup, int filefmt)
{
if (!_af_filesetup_ok(setup))
return;
if (filefmt < 0 || filefmt >= _AF_NUM_UNITS)
{
_af_error(AF_BAD_FILEFMT, "unrecognized file format %d",
filefmt);
return;
}
if (!_af_units[filefmt].implemented)
{
_af_error(AF_BAD_NOT_IMPLEMENTED,
"%s format not currently supported",
_af_units[filefmt].name);
return;
}
setup->fileFormat = filefmt;
}
void afInitChannels (AFfilesetup setup, int trackid, int channels)
{
if (!_af_filesetup_ok(setup))
return;
TrackSetup *track = setup->getTrack(trackid);
if (!track)
return;
if (channels < 1)
{
_af_error(AF_BAD_CHANNELS, "invalid number of channels %d",
channels);
return;
}
track->f.channelCount = channels;
track->channelCountSet = true;
}
void afInitSampleFormat (AFfilesetup setup, int trackid, int sampfmt, int sampwidth)
{
if (!_af_filesetup_ok(setup))
return;
TrackSetup *track = setup->getTrack(trackid);
if (!track)
return;
_af_set_sample_format(&track->f, sampfmt, sampwidth);
track->sampleFormatSet = true;
track->sampleWidthSet = true;
}
void afInitByteOrder (AFfilesetup setup, int trackid, int byteorder)
{
if (!_af_filesetup_ok(setup))
return;
TrackSetup *track = setup->getTrack(trackid);
if (!track)
return;
if (byteorder != AF_BYTEORDER_BIGENDIAN &&
byteorder != AF_BYTEORDER_LITTLEENDIAN)
{
_af_error(AF_BAD_BYTEORDER, "invalid byte order %d", byteorder);
return;
}
track->f.byteOrder = byteorder;
track->byteOrderSet = true;
}
void afInitRate (AFfilesetup setup, int trackid, double rate)
{
if (!_af_filesetup_ok(setup))
return;
TrackSetup *track = setup->getTrack(trackid);
if (!track)
return;
if (rate <= 0.0)
{
_af_error(AF_BAD_RATE, "invalid sample rate %.30g", rate);
return;
}
track->f.sampleRate = rate;
track->rateSet = true;
}
void afInitDataOffset (AFfilesetup setup, int trackid, AFfileoffset offset)
{
if (!_af_filesetup_ok(setup))
return;
TrackSetup *track = setup->getTrack(trackid);
if (!track)
return;
if (offset < 0)
{
_af_error(AF_BAD_DATAOFFSET, "invalid data offset %jd",
static_cast<intmax_t>(offset));
return;
}
track->dataOffset = offset;
track->dataOffsetSet = true;
}
void afInitFrameCount (AFfilesetup setup, int trackid, AFfileoffset count)
{
if (!_af_filesetup_ok(setup))
return;
TrackSetup *track = setup->getTrack(trackid);
if (!track)
return;
if (count < 0)
{
_af_error(AF_BAD_FRAMECNT, "invalid frame count %jd",
static_cast<intmax_t>(count));
return;
}
track->frameCount = count;
track->frameCountSet = true;
}
#define alloccopy(type, n, var, copyfrom) \
{ \
if (n == 0) \
var = NULL; \
else \
{ \
if ((var = (type *) _af_calloc(n, sizeof (type))) == NULL) \
goto fail; \
memcpy((var), (copyfrom), (n) * sizeof (type)); \
} \
}
AFfilesetup _af_filesetup_copy (const _AFfilesetup *setup,
const _AFfilesetup *defaultSetup, bool copyMarks)
{
AFfilesetup newsetup;
int instrumentCount, miscellaneousCount, trackCount;
newsetup = (_AFfilesetup *) _af_malloc(sizeof (_AFfilesetup));
if (newsetup == AF_NULL_FILESETUP)
return AF_NULL_FILESETUP;
*newsetup = *defaultSetup;
newsetup->tracks = NULL;
newsetup->instruments = NULL;
newsetup->miscellaneous = NULL;
trackCount = setup->trackSet ? setup->trackCount :
newsetup->trackSet ? newsetup->trackCount : 0;
alloccopy(TrackSetup, trackCount, newsetup->tracks, setup->tracks);
newsetup->trackCount = trackCount;
instrumentCount = setup->instrumentSet ? setup->instrumentCount :
newsetup->instrumentSet ? newsetup->instrumentCount : 0;
alloccopy(InstrumentSetup, instrumentCount, newsetup->instruments, setup->instruments);
newsetup->instrumentCount = instrumentCount;
miscellaneousCount = setup->miscellaneousSet ? setup->miscellaneousCount :
newsetup->miscellaneousSet ? newsetup->miscellaneousCount : 0;
alloccopy(MiscellaneousSetup, miscellaneousCount, newsetup->miscellaneous, setup->miscellaneous);
newsetup->miscellaneousCount = miscellaneousCount;
for (int i=0; i<setup->trackCount; i++)
{
TrackSetup *track = &newsetup->tracks[i];
if (!setup->tracks[i].markersSet && !copyMarks)
{
track->markers = NULL;
track->markerCount = 0;
continue;
}
alloccopy(MarkerSetup, setup->tracks[i].markerCount,
track->markers, setup->tracks[i].markers);
track->markerCount = setup->tracks[i].markerCount;
for (int j=0; j<setup->tracks[i].markerCount; j++)
{
track->markers[j].name =
_af_strdup(setup->tracks[i].markers[j].name);
if (track->markers[j].name == NULL)
goto fail;
track->markers[j].comment =
_af_strdup(setup->tracks[i].markers[j].comment);
if (track->markers[j].comment == NULL)
goto fail;
}
}
for (int i=0; i<newsetup->instrumentCount; i++)
{
InstrumentSetup *instrument = &newsetup->instruments[i];
alloccopy(LoopSetup, setup->instruments[i].loopCount,
instrument->loops, setup->instruments[i].loops);
}
return newsetup;
fail:
if (newsetup->miscellaneous)
free(newsetup->miscellaneous);
if (newsetup->instruments)
free(newsetup->instruments);
if (newsetup->tracks)
free(newsetup->tracks);
if (newsetup)
free(newsetup);
return AF_NULL_FILESETUP;
}
TrackSetup *_AFfilesetup::getTrack(int trackID)
{
for (int i=0; i<trackCount; i++)
{
if (tracks[i].id == trackID)
return &tracks[i];
}
_af_error(AF_BAD_TRACKID, "bad track id %d", trackID);
return NULL;
}
InstrumentSetup *_AFfilesetup::getInstrument(int instrumentID)
{
for (int i=0; i < instrumentCount; i++)
if (instruments[i].id == instrumentID)
return &instruments[i];
_af_error(AF_BAD_INSTID, "invalid instrument id %d", instrumentID);
return NULL;
}
MiscellaneousSetup *_AFfilesetup::getMiscellaneous(int miscellaneousID)
{
for (int i=0; i<miscellaneousCount; i++)
{
if (miscellaneous[i].id == miscellaneousID)
return &miscellaneous[i];
}
_af_error(AF_BAD_MISCID, "bad miscellaneous id %d", miscellaneousID);
return NULL;
}
#include <assert.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
void afInitTrackIDs (AFfilesetup file, const int *trackids, int trackCount)
{
assert(file);
assert(trackids);
assert(trackCount == 1);
assert(trackids[0] == AF_DEFAULT_TRACK);
}
int afGetTrackIDs (AFfilehandle file, int *trackids)
{
assert(file);
if (trackids != NULL)
trackids[0] = AF_DEFAULT_TRACK;
return 1;
}
Track::Track()
{
id = AF_DEFAULT_TRACK;
f.compressionParams = NULL;
v.compressionParams = NULL;
channelMatrix = NULL;
markerCount = 0;
markers = NULL;
hasAESData = false;
memset(aesData, 0, 24);
totalfframes = 0;
nextfframe = 0;
frames2ignore = 0;
fpos_first_frame = 0;
fpos_next_frame = 0;
fpos_after_data = 0;
totalvframes = 0;
nextvframe = 0;
data_size = 0;
}
Track::~Track()
{
if (f.compressionParams)
{
AUpvfree(f.compressionParams);
f.compressionParams = NULL;
}
if (v.compressionParams)
{
AUpvfree(v.compressionParams);
v.compressionParams = NULL;
}
free(channelMatrix);
channelMatrix = NULL;
if (markers)
{
for (int j=0; j<markerCount; j++)
{
free(markers[j].name);
markers[j].name = NULL;
free(markers[j].comment);
markers[j].comment = NULL;
}
free(markers);
markers = NULL;
}
}
void Track::print()
{
fprintf(stderr, "totalfframes %jd\n", (intmax_t) totalfframes);
fprintf(stderr, "nextfframe %jd\n", (intmax_t) nextfframe);
fprintf(stderr, "frames2ignore %jd\n", (intmax_t) frames2ignore);
fprintf(stderr, "fpos_first_frame %jd\n", (intmax_t) fpos_first_frame);
fprintf(stderr, "fpos_next_frame %jd\n", (intmax_t) fpos_next_frame);
fprintf(stderr, "fpos_after_data %jd\n", (intmax_t) fpos_after_data);
fprintf(stderr, "totalvframes %jd\n", (intmax_t) totalvframes);
fprintf(stderr, "nextvframe %jd\n", (intmax_t) nextvframe);
fprintf(stderr, "data_size %jd\n", (intmax_t) data_size);
}
Marker *Track::getMarker(int markerID)
{
for (int i=0; i<markerCount; i++)
if (markers[i].id == markerID)
return &markers[i];
_af_error(AF_BAD_MARKID, "no marker with id %d found in track %d",
markerID, id);
return NULL;
}
status Track::copyMarkers(TrackSetup *setup)
{
if ((markerCount = setup->markerCount) == 0)
{
markers = NULL;
return AF_SUCCEED;
}
markers = _af_marker_new(markerCount);
if (!markers)
return AF_FAIL;
for (int i=0; i<markerCount; i++)
{
markers[i].id = setup->markers[i].id;
markers[i].name = _af_strdup(setup->markers[i].name);
if (!markers[i].name)
return AF_FAIL;
markers[i].comment = _af_strdup(setup->markers[i].comment);
if (!markers[i].comment)
return AF_FAIL;
markers[i].position = 0;
}
return AF_SUCCEED;
}
void Track::computeTotalFileFrames()
{
if (f.bytesPerPacket && f.framesPerPacket)
totalfframes = (data_size / f.bytesPerPacket) * f.framesPerPacket;
}
#include <stdio.h>
#include <string.h>
bool UUID::operator==(const UUID &u) const
{
return !memcmp(data, u.data, 16);
}
bool UUID::operator!=(const UUID &u) const
{
return memcmp(data, u.data, 16) != 0;
}
std::string UUID::name() const
{
char s[37];
uint32_t u1 =
(data[0] << 24) |
(data[1] << 16) |
(data[2] << 8) |
data[3];
uint16_t u2 =
(data[4] << 8) |
data[5];
uint16_t u3 =
(data[6] << 8) |
data[7];
uint16_t u4 =
(data[8] << 8) |
data[9];
snprintf(s, 37, "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
u1, u2, u3, u4,
data[10], data[11], data[12], data[13], data[14], data[15]);
return std::string(s);
}
#include <assert.h>
#include <math.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
enum
{
WAVE_FORMAT_UNKNOWN = 0x0000,
WAVE_FORMAT_PCM = 0x0001,
WAVE_FORMAT_ADPCM = 0x0002,
WAVE_FORMAT_IEEE_FLOAT = 0x0003,
WAVE_FORMAT_VSELP = 0x0004,
WAVE_FORMAT_IBM_CVSD = 0x0005,
WAVE_FORMAT_ALAW = 0x0006,
WAVE_FORMAT_MULAW = 0x0007,
WAVE_FORMAT_OKI_ADPCM = 0x0010,
WAVE_FORMAT_DVI_ADPCM = 0x0011,
WAVE_FORMAT_MEDIASPACE_ADPCM = 0x0012,
WAVE_FORMAT_SIERRA_ADPCM = 0x0013,
WAVE_FORMAT_G723_ADPCM = 0x0014,
WAVE_FORMAT_DIGISTD = 0x0015,
WAVE_FORMAT_DIGIFIX = 0x0016,
WAVE_FORMAT_DIALOGIC_OKI_ADPCM = 0x0017,
WAVE_FORMAT_MEDIAVISION_ADPCM = 0x0018,
WAVE_FORMAT_CU_CODEC = 0x0019,
WAVE_FORMAT_YAMAHA_ADPCM = 0x0020,
WAVE_FORMAT_SONARC = 0x0021,
WAVE_FORMAT_DSP_TRUESPEECH = 0x0022,
WAVE_FORMAT_ECHOSC1 = 0x0023,
WAVE_FORMAT_AUDIOFILE_AF36 = 0x0024,
WAVE_FORMAT_APTX = 0x0025,
WAVE_FORMAT_DOLBY_AC2 = 0x0030,
WAVE_FORMAT_GSM610 = 0x0031,
WAVE_FORMAT_MSNAUDIO = 0x0032,
WAVE_FORMAT_ANTEX_ADPCME = 0x0033,
WAVE_FORMAT_MPEG = 0x0050,
WAVE_FORMAT_MPEGLAYER3 = 0x0055,
WAVE_FORMAT_LUCENT_G723 = 0x0059,
WAVE_FORMAT_G726_ADPCM = 0x0064,
WAVE_FORMAT_G722_ADPCM = 0x0065,
IBM_FORMAT_MULAW = 0x0101,
IBM_FORMAT_ALAW = 0x0102,
IBM_FORMAT_ADPCM = 0x0103,
WAVE_FORMAT_CREATIVE_ADPCM = 0x0200,
WAVE_FORMAT_EXTENSIBLE = 0xfffe
};
const int _af_wave_compression_types[_AF_WAVE_NUM_COMPTYPES] =
{
AF_COMPRESSION_G711_ULAW,
AF_COMPRESSION_G711_ALAW,
AF_COMPRESSION_IMA,
AF_COMPRESSION_MS_ADPCM
};
const InstParamInfo _af_wave_inst_params[_AF_WAVE_NUM_INSTPARAMS] =
{
{ AF_INST_MIDI_BASENOTE, AU_PVTYPE_LONG, "MIDI base note", {60} },
{ AF_INST_NUMCENTS_DETUNE, AU_PVTYPE_LONG, "Detune in cents", {0} },
{ AF_INST_MIDI_LOVELOCITY, AU_PVTYPE_LONG, "Low velocity", {1} },
{ AF_INST_MIDI_HIVELOCITY, AU_PVTYPE_LONG, "High velocity", {127} },
{ AF_INST_MIDI_LONOTE, AU_PVTYPE_LONG, "Low note", {0} },
{ AF_INST_MIDI_HINOTE, AU_PVTYPE_LONG, "High note", {127} },
{ AF_INST_NUMDBS_GAIN, AU_PVTYPE_LONG, "Gain in dB", {0} }
};
static const _AFfilesetup waveDefaultFileSetup =
{
_AF_VALID_FILESETUP,
AF_FILE_WAVE,
true,
true,
true,
1,
NULL,
0,
NULL,
0,
NULL
};
static const UUID _af_wave_guid_pcm =
{{
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71
}};
static const UUID _af_wave_guid_ieee_float =
{{
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71
}};
static const UUID _af_wave_guid_ulaw =
{{
0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71
}};
static const UUID _af_wave_guid_alaw =
{{
0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71
}};
WAVEFile::WAVEFile()
{
setFormatByteOrder(AF_BYTEORDER_LITTLEENDIAN);
m_factOffset = 0;
m_miscellaneousOffset = 0;
m_markOffset = 0;
m_dataSizeOffset = 0;
m_msadpcmNumCoefficients = 0;
}
status WAVEFile::parseFrameCount(const Tag &id, uint32_t size)
{
Track *track = getTrack();
uint32_t totalFrames;
readU32(&totalFrames);
track->totalfframes = totalFrames;
return AF_SUCCEED;
}
status WAVEFile::parseFormat(const Tag &id, uint32_t size)
{
Track *track = getTrack();
uint16_t formatTag;
readU16(&formatTag);
uint16_t channelCount;
readU16(&channelCount);
uint32_t sampleRate;
readU32(&sampleRate);
uint32_t averageBytesPerSecond;
readU32(&averageBytesPerSecond);
uint16_t blockAlign;
readU16(&blockAlign);
if (!channelCount)
{
_af_error(AF_BAD_CHANNELS, "invalid file with 0 channels");
return AF_FAIL;
}
track->f.channelCount = channelCount;
track->f.sampleRate = sampleRate;
track->f.byteOrder = AF_BYTEORDER_LITTLEENDIAN;
track->f.compressionType = AF_COMPRESSION_NONE;
track->f.framesPerPacket = 1;
switch (formatTag)
{
case WAVE_FORMAT_PCM:
{
uint16_t bitsPerSample;
readU16(&bitsPerSample);
track->f.sampleWidth = bitsPerSample;
if (bitsPerSample == 0 || bitsPerSample > 32)
{
_af_error(AF_BAD_WIDTH,
"bad sample width of %d bits",
bitsPerSample);
return AF_FAIL;
}
if (bitsPerSample <= 8)
track->f.sampleFormat = AF_SAMPFMT_UNSIGNED;
else
track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
}
break;
case WAVE_FORMAT_MULAW:
case IBM_FORMAT_MULAW:
track->f.sampleWidth = 16;
track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
track->f.byteOrder = _AF_BYTEORDER_NATIVE;
track->f.compressionType = AF_COMPRESSION_G711_ULAW;
track->f.bytesPerPacket = track->f.channelCount;
break;
case WAVE_FORMAT_ALAW:
case IBM_FORMAT_ALAW:
track->f.sampleWidth = 16;
track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
track->f.byteOrder = _AF_BYTEORDER_NATIVE;
track->f.compressionType = AF_COMPRESSION_G711_ALAW;
track->f.bytesPerPacket = track->f.channelCount;
break;
case WAVE_FORMAT_IEEE_FLOAT:
{
uint16_t bitsPerSample;
readU16(&bitsPerSample);
if (bitsPerSample == 64)
{
track->f.sampleWidth = 64;
track->f.sampleFormat = AF_SAMPFMT_DOUBLE;
}
else
{
track->f.sampleWidth = 32;
track->f.sampleFormat = AF_SAMPFMT_FLOAT;
}
}
break;
case WAVE_FORMAT_ADPCM:
{
uint16_t bitsPerSample, extraByteCount,
samplesPerBlock, numCoefficients;
if (track->f.channelCount != 1 &&
track->f.channelCount != 2)
{
_af_error(AF_BAD_CHANNELS,
"WAVE file with MS ADPCM compression "
"must have 1 or 2 channels");
}
readU16(&bitsPerSample);
readU16(&extraByteCount);
readU16(&samplesPerBlock);
readU16(&numCoefficients);
assert(numCoefficients >= 7 && numCoefficients <= 255);
m_msadpcmNumCoefficients = numCoefficients;
for (int i=0; i<m_msadpcmNumCoefficients; i++)
{
readS16(&m_msadpcmCoefficients[i][0]);
readS16(&m_msadpcmCoefficients[i][1]);
}
track->f.sampleWidth = 16;
track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
track->f.compressionType = AF_COMPRESSION_MS_ADPCM;
track->f.byteOrder = _AF_BYTEORDER_NATIVE;
track->f.framesPerPacket = samplesPerBlock;
track->f.bytesPerPacket = blockAlign;
AUpvlist pv = AUpvnew(2);
AUpvsetparam(pv, 0, _AF_MS_ADPCM_NUM_COEFFICIENTS);
AUpvsetvaltype(pv, 0, AU_PVTYPE_LONG);
long l = m_msadpcmNumCoefficients;
AUpvsetval(pv, 0, &l);
AUpvsetparam(pv, 1, _AF_MS_ADPCM_COEFFICIENTS);
AUpvsetvaltype(pv, 1, AU_PVTYPE_PTR);
void *v = m_msadpcmCoefficients;
AUpvsetval(pv, 1, &v);
track->f.compressionParams = pv;
}
break;
case WAVE_FORMAT_DVI_ADPCM:
{
uint16_t bitsPerSample, extraByteCount, samplesPerBlock;
readU16(&bitsPerSample);
readU16(&extraByteCount);
readU16(&samplesPerBlock);
if (bitsPerSample != 4)
{
_af_error(AF_BAD_NOT_IMPLEMENTED,
"IMA ADPCM compression supports only 4 bits per sample");
}
int bytesPerBlock = (samplesPerBlock + 14) / 8 * 4 * channelCount;
if (bytesPerBlock > blockAlign || (samplesPerBlock % 8) != 1)
{
_af_error(AF_BAD_CODEC_CONFIG,
"Invalid samples per block for IMA ADPCM compression");
}
track->f.sampleWidth = 16;
track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
track->f.compressionType = AF_COMPRESSION_IMA;
track->f.byteOrder = _AF_BYTEORDER_NATIVE;
initIMACompressionParams();
track->f.framesPerPacket = samplesPerBlock;
track->f.bytesPerPacket = blockAlign;
}
break;
case WAVE_FORMAT_EXTENSIBLE:
{
uint16_t bitsPerSample;
readU16(&bitsPerSample);
uint16_t extraByteCount;
readU16(&extraByteCount);
uint16_t reserved;
readU16(&reserved);
uint32_t channelMask;
readU32(&channelMask);
UUID subformat;
readUUID(&subformat);
if (subformat == _af_wave_guid_pcm)
{
track->f.sampleWidth = bitsPerSample;
if (bitsPerSample == 0 || bitsPerSample > 32)
{
_af_error(AF_BAD_WIDTH,
"bad sample width of %d bits",
bitsPerSample);
return AF_FAIL;
}
if (reserved <= bitsPerSample &&
(reserved + 7) / 8 == (bitsPerSample + 7) / 8)
track->f.sampleWidth = reserved;
if (bitsPerSample <= 8)
track->f.sampleFormat = AF_SAMPFMT_UNSIGNED;
else
track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
}
else if (subformat == _af_wave_guid_ieee_float)
{
if (bitsPerSample == 64)
{
track->f.sampleWidth = 64;
track->f.sampleFormat = AF_SAMPFMT_DOUBLE;
}
else
{
track->f.sampleWidth = 32;
track->f.sampleFormat = AF_SAMPFMT_FLOAT;
}
}
else if (subformat == _af_wave_guid_alaw ||
subformat == _af_wave_guid_ulaw)
{
track->f.compressionType = subformat == _af_wave_guid_alaw ?
AF_COMPRESSION_G711_ALAW : AF_COMPRESSION_G711_ULAW;
track->f.sampleWidth = 16;
track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
track->f.byteOrder = _AF_BYTEORDER_NATIVE;
track->f.bytesPerPacket = channelCount;
}
else
{
_af_error(AF_BAD_NOT_IMPLEMENTED, "WAVE extensible data format %s is not currently supported", subformat.name().c_str());
return AF_FAIL;
}
}
break;
case WAVE_FORMAT_YAMAHA_ADPCM:
case WAVE_FORMAT_OKI_ADPCM:
case WAVE_FORMAT_CREATIVE_ADPCM:
case IBM_FORMAT_ADPCM:
_af_error(AF_BAD_NOT_IMPLEMENTED, "WAVE ADPCM data format 0x%x is not currently supported", formatTag);
return AF_FAIL;
break;
case WAVE_FORMAT_MPEG:
_af_error(AF_BAD_NOT_IMPLEMENTED, "WAVE MPEG data format is not supported");
return AF_FAIL;
break;
case WAVE_FORMAT_MPEGLAYER3:
_af_error(AF_BAD_NOT_IMPLEMENTED, "WAVE MPEG layer 3 data format is not supported");
return AF_FAIL;
break;
default:
_af_error(AF_BAD_NOT_IMPLEMENTED, "WAVE file data format 0x%x not currently supported != 0xfffe ? %d, != EXTENSIBLE? %d", formatTag, formatTag != 0xfffe, formatTag != WAVE_FORMAT_EXTENSIBLE);
return AF_FAIL;
break;
}
if (track->f.isUncompressed())
track->f.computeBytesPerPacketPCM();
_af_set_sample_format(&track->f, track->f.sampleFormat, track->f.sampleWidth);
return AF_SUCCEED;
}
status WAVEFile::parseData(const Tag &id, uint32_t size)
{
Track *track = getTrack();
track->fpos_first_frame = m_fh->tell();
track->data_size = size;
return AF_SUCCEED;
}
status WAVEFile::parsePlayList(const Tag &id, uint32_t size)
{
uint32_t segmentCount;
readU32(&segmentCount);
if (segmentCount == 0)
{
m_instrumentCount = 0;
m_instruments = NULL;
return AF_SUCCEED;
}
for (unsigned segment=0; segment<segmentCount; segment++)
{
uint32_t startMarkID, loopLength, loopCount;
readU32(&startMarkID);
readU32(&loopLength);
readU32(&loopCount);
}
return AF_SUCCEED;
}
status WAVEFile::parseCues(const Tag &id, uint32_t size)
{
Track *track = getTrack();
uint32_t markerCount;
readU32(&markerCount);
track->markerCount = markerCount;
if (markerCount == 0)
{
track->markers = NULL;
return AF_SUCCEED;
}
if ((track->markers = _af_marker_new(markerCount)) == NULL)
return AF_FAIL;
for (unsigned i=0; i<markerCount; i++)
{
uint32_t id, position, chunkid;
uint32_t chunkByteOffset, blockByteOffset;
uint32_t sampleFrameOffset;
Marker *marker = &track->markers[i];
readU32(&id);
readU32(&position);
readU32(&chunkid);
readU32(&chunkByteOffset);
readU32(&blockByteOffset);
readU32(&sampleFrameOffset);
marker->id = id;
marker->position = sampleFrameOffset;
marker->name = _af_strdup("");
marker->comment = _af_strdup("");
}
return AF_SUCCEED;
}
status WAVEFile::parseADTLSubChunk(const Tag &id, uint32_t size)
{
Track *track = getTrack();
AFfileoffset endPos = m_fh->tell() + size;
while (m_fh->tell() < endPos)
{
Tag chunkID;
uint32_t chunkSize;
readTag(&chunkID);
readU32(&chunkSize);
if (chunkID == "labl" || chunkID == "note")
{
uint32_t id;
long length=chunkSize-4;
char *p = (char *) _af_malloc(length);
readU32(&id);
m_fh->read(p, length);
Marker *marker = track->getMarker(id);
if (marker)
{
if (chunkID == "labl")
{
free(marker->name);
marker->name = p;
}
else if (chunkID == "note")
{
free(marker->comment);
marker->comment = p;
}
else
free(p);
}
else
free(p);
if ((chunkSize % 2) != 0)
m_fh->seek(1, File::SeekFromCurrent);
}
else
{
m_fh->seek(chunkSize + (chunkSize % 2), File::SeekFromCurrent);
}
}
return AF_SUCCEED;
}
status WAVEFile::parseINFOSubChunk(const Tag &id, uint32_t size)
{
AFfileoffset endPos = m_fh->tell() + size;
while (m_fh->tell() < endPos)
{
int misctype = AF_MISC_UNRECOGNIZED;
Tag miscid;
uint32_t miscsize;
readTag(&miscid);
readU32(&miscsize);
if (miscid == "IART")
misctype = AF_MISC_AUTH;
else if (miscid == "INAM")
misctype = AF_MISC_NAME;
else if (miscid == "ICOP")
misctype = AF_MISC_COPY;
else if (miscid == "ICMT")
misctype = AF_MISC_ICMT;
else if (miscid == "ICRD")
misctype = AF_MISC_ICRD;
else if (miscid == "ISFT")
misctype = AF_MISC_ISFT;
if (misctype != AF_MISC_UNRECOGNIZED)
{
char *string = (char *) _af_malloc(miscsize);
m_fh->read(string, miscsize);
m_miscellaneousCount++;
m_miscellaneous = (Miscellaneous *) _af_realloc(m_miscellaneous, sizeof (Miscellaneous) * m_miscellaneousCount);
m_miscellaneous[m_miscellaneousCount-1].id = m_miscellaneousCount;
m_miscellaneous[m_miscellaneousCount-1].type = misctype;
m_miscellaneous[m_miscellaneousCount-1].size = miscsize;
m_miscellaneous[m_miscellaneousCount-1].position = 0;
m_miscellaneous[m_miscellaneousCount-1].buffer = string;
}
else
{
m_fh->seek(miscsize, File::SeekFromCurrent);
}
if (miscsize % 2 != 0)
m_fh->seek(1, File::SeekFromCurrent);
}
return AF_SUCCEED;
}
status WAVEFile::parseList(const Tag &id, uint32_t size)
{
Tag typeID;
readTag(&typeID);
size-=4;
if (typeID == "adtl")
{
return parseADTLSubChunk(typeID, size);
}
else if (typeID == "INFO")
{
return parseINFOSubChunk(typeID, size);
}
else
{
m_fh->seek(size, File::SeekFromCurrent);
return AF_SUCCEED;
}
return AF_SUCCEED;
}
status WAVEFile::parseInstrument(const Tag &id, uint32_t size)
{
uint8_t baseNote;
int8_t detune, gain;
uint8_t lowNote, highNote, lowVelocity, highVelocity;
uint8_t padByte;
readU8(&baseNote);
readS8(&detune);
readS8(&gain);
readU8(&lowNote);
readU8(&highNote);
readU8(&lowVelocity);
readU8(&highVelocity);
readU8(&padByte);
return AF_SUCCEED;
}
bool WAVEFile::recognize(File *fh)
{
uint8_t buffer[8];
fh->seek(0, File::SeekFromBeginning);
if (fh->read(buffer, 8) != 8 || memcmp(buffer, "RIFF", 4) != 0)
return false;
if (fh->read(buffer, 4) != 4 || memcmp(buffer, "WAVE", 4) != 0)
return false;
return true;
}
status WAVEFile::readInit(AFfilesetup setup)
{
Tag type, formtype;
uint32_t size;
uint32_t index = 0;
bool hasFormat = false;
bool hasData = false;
bool hasFrameCount = false;
Track *track = allocateTrack();
m_fh->seek(0, File::SeekFromBeginning);
readTag(&type);
readU32(&size);
readTag(&formtype);
assert(type == "RIFF");
assert(formtype == "WAVE");
index += 4;
while (index < size)
{
Tag chunkid;
uint32_t chunksize = 0;
status result;
readTag(&chunkid);
readU32(&chunksize);
if (chunkid == "fmt ")
{
result = parseFormat(chunkid, chunksize);
if (result == AF_FAIL)
return AF_FAIL;
hasFormat = true;
}
else if (chunkid == "data")
{
if (!hasFormat)
{
_af_error(AF_BAD_HEADER, "missing format chunk in WAVE file");
return AF_FAIL;
}
result = parseData(chunkid, chunksize);
if (result == AF_FAIL)
return AF_FAIL;
hasData = true;
}
else if (chunkid == "inst")
{
result = parseInstrument(chunkid, chunksize);
if (result == AF_FAIL)
return AF_FAIL;
}
else if (chunkid == "fact")
{
hasFrameCount = true;
result = parseFrameCount(chunkid, chunksize);
if (result == AF_FAIL)
return AF_FAIL;
}
else if (chunkid == "cue ")
{
result = parseCues(chunkid, chunksize);
if (result == AF_FAIL)
return AF_FAIL;
}
else if (chunkid == "LIST" || chunkid == "list")
{
result = parseList(chunkid, chunksize);
if (result == AF_FAIL)
return AF_FAIL;
}
else if (chunkid == "INST")
{
result = parseInstrument(chunkid, chunksize);
if (result == AF_FAIL)
return AF_FAIL;
}
else if (chunkid == "plst")
{
result = parsePlayList(chunkid, chunksize);
if (result == AF_FAIL)
return AF_FAIL;
}
index += chunksize + 8;
if ((index % 2) != 0)
index++;
m_fh->seek(index + 8, File::SeekFromBeginning);
}
if (!hasFormat || !hasData)
{
return AF_FAIL;
}
if (!hasFrameCount)
{
if (track->f.bytesPerPacket && track->f.framesPerPacket)
{
track->computeTotalFileFrames();
}
else
{
_af_error(AF_BAD_HEADER, "Frame count required but not found");
return AF_FAIL;
}
}
return AF_SUCCEED;
}
AFfilesetup WAVEFile::completeSetup(AFfilesetup setup)
{
if (setup->trackSet && setup->trackCount != 1)
{
_af_error(AF_BAD_NUMTRACKS, "WAVE file must have 1 track");
return AF_NULL_FILESETUP;
}
TrackSetup *track = setup->getTrack();
if (!track)
return AF_NULL_FILESETUP;
if (track->f.isCompressed())
{
if (!track->sampleFormatSet)
_af_set_sample_format(&track->f, AF_SAMPFMT_TWOSCOMP, 16);
else
_af_set_sample_format(&track->f, track->f.sampleFormat, track->f.sampleWidth);
}
else if (track->sampleFormatSet)
{
switch (track->f.sampleFormat)
{
case AF_SAMPFMT_FLOAT:
if (track->sampleWidthSet &&
track->f.sampleWidth != 32)
{
_af_error(AF_BAD_WIDTH,
"Warning: invalid sample width for floating-point WAVE file: %d (must be 32 bits)\n",
track->f.sampleWidth);
_af_set_sample_format(&track->f, AF_SAMPFMT_FLOAT, 32);
}
break;
case AF_SAMPFMT_DOUBLE:
if (track->sampleWidthSet &&
track->f.sampleWidth != 64)
{
_af_error(AF_BAD_WIDTH,
"Warning: invalid sample width for double-precision floating-point WAVE file: %d (must be 64 bits)\n",
track->f.sampleWidth);
_af_set_sample_format(&track->f, AF_SAMPFMT_DOUBLE, 64);
}
break;
case AF_SAMPFMT_UNSIGNED:
if (track->sampleWidthSet)
{
if (track->f.sampleWidth < 1 || track->f.sampleWidth > 32)
{
_af_error(AF_BAD_WIDTH, "invalid sample width for WAVE file: %d (must be 1-32 bits)\n", track->f.sampleWidth);
return AF_NULL_FILESETUP;
}
if (track->f.sampleWidth > 8)
{
_af_error(AF_BAD_SAMPFMT, "WAVE integer data of more than 8 bits must be two's complement signed");
_af_set_sample_format(&track->f, AF_SAMPFMT_TWOSCOMP, track->f.sampleWidth);
}
}
else
_af_set_sample_format(&track->f, track->f.sampleFormat, 8);
break;
case AF_SAMPFMT_TWOSCOMP:
if (track->sampleWidthSet)
{
if (track->f.sampleWidth < 1 || track->f.sampleWidth > 32)
{
_af_error(AF_BAD_WIDTH, "invalid sample width %d for WAVE file (must be 1-32)", track->f.sampleWidth);
return AF_NULL_FILESETUP;
}
else if (track->f.sampleWidth <= 8)
{
_af_error(AF_BAD_SAMPFMT, "Warning: WAVE format integer data of 1-8 bits must be unsigned; setting sample format to unsigned");
_af_set_sample_format(&track->f, AF_SAMPFMT_UNSIGNED, track->f.sampleWidth);
}
}
else
_af_set_sample_format(&track->f, track->f.sampleFormat, 16);
break;
}
}
else
{
if (!track->sampleWidthSet)
{
track->f.sampleWidth = 16;
track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
}
else
{
if (track->f.sampleWidth < 1 || track->f.sampleWidth > 32)
{
_af_error(AF_BAD_WIDTH, "invalid sample width %d for WAVE file (must be 1-32)", track->f.sampleWidth);
return AF_NULL_FILESETUP;
}
else if (track->f.sampleWidth > 8)
track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
else
track->f.sampleFormat = AF_SAMPFMT_UNSIGNED;
}
}
if (track->f.compressionType != AF_COMPRESSION_NONE &&
track->f.compressionType != AF_COMPRESSION_G711_ULAW &&
track->f.compressionType != AF_COMPRESSION_G711_ALAW &&
track->f.compressionType != AF_COMPRESSION_IMA &&
track->f.compressionType != AF_COMPRESSION_MS_ADPCM)
{
_af_error(AF_BAD_NOT_IMPLEMENTED, "compression format not supported in WAVE format");
return AF_NULL_FILESETUP;
}
if (track->f.isUncompressed() &&
track->byteOrderSet &&
track->f.byteOrder != AF_BYTEORDER_LITTLEENDIAN &&
track->f.isByteOrderSignificant())
{
_af_error(AF_BAD_BYTEORDER, "WAVE format only supports little-endian data");
return AF_NULL_FILESETUP;
}
if (track->f.isUncompressed())
track->f.byteOrder = AF_BYTEORDER_LITTLEENDIAN;
if (track->aesDataSet)
{
_af_error(AF_BAD_FILESETUP, "WAVE files cannot have AES data");
return AF_NULL_FILESETUP;
}
if (setup->instrumentSet)
{
if (setup->instrumentCount > 1)
{
_af_error(AF_BAD_NUMINSTS, "WAVE files can have 0 or 1 instrument");
return AF_NULL_FILESETUP;
}
else if (setup->instrumentCount == 1)
{
if (setup->instruments[0].loopSet &&
setup->instruments[0].loopCount > 0 &&
(!track->markersSet || track->markerCount == 0))
{
_af_error(AF_BAD_NUMMARKS, "WAVE files with loops must contain at least 1 marker");
return AF_NULL_FILESETUP;
}
}
}
if (setup->miscellaneousSet)
{
for (int i=0; i<setup->miscellaneousCount; i++)
{
switch (setup->miscellaneous[i].type)
{
case AF_MISC_COPY:
case AF_MISC_AUTH:
case AF_MISC_NAME:
case AF_MISC_ICRD:
case AF_MISC_ISFT:
case AF_MISC_ICMT:
break;
default:
_af_error(AF_BAD_MISCTYPE, "illegal miscellaneous type [%d] for WAVE file", setup->miscellaneous[i].type);
return AF_NULL_FILESETUP;
}
}
}
AFfilesetup newsetup = _af_filesetup_copy(setup, &waveDefaultFileSetup, false);
if (setup->instrumentSet && setup->instrumentCount > 0 &&
setup->instruments[0].loopSet)
{
free(newsetup->instruments[0].loops);
newsetup->instruments[0].loopCount = 0;
}
return newsetup;
}
bool WAVEFile::isInstrumentParameterValid(AUpvlist list, int i)
{
int param, type;
AUpvgetparam(list, i, ¶m);
AUpvgetvaltype(list, i, &type);
if (type != AU_PVTYPE_LONG)
return false;
long lval;
AUpvgetval(list, i, &lval);
switch (param)
{
case AF_INST_MIDI_BASENOTE:
return ((lval >= 0) && (lval <= 127));
case AF_INST_NUMCENTS_DETUNE:
return ((lval >= -50) && (lval <= 50));
case AF_INST_MIDI_LOVELOCITY:
return ((lval >= 1) && (lval <= 127));
case AF_INST_MIDI_HIVELOCITY:
return ((lval >= 1) && (lval <= 127));
case AF_INST_MIDI_LONOTE:
return ((lval >= 0) && (lval <= 127));
case AF_INST_MIDI_HINOTE:
return ((lval >= 0) && (lval <= 127));
case AF_INST_NUMDBS_GAIN:
return true;
default:
return false;
}
return true;
}
status WAVEFile::writeFormat()
{
uint16_t formatTag, channelCount;
uint32_t sampleRate, averageBytesPerSecond;
uint16_t blockAlign;
uint32_t chunkSize;
uint16_t bitsPerSample;
Track *track = getTrack();
m_fh->write("fmt ", 4);
switch (track->f.compressionType)
{
case AF_COMPRESSION_NONE:
chunkSize = 16;
if (track->f.sampleFormat == AF_SAMPFMT_FLOAT ||
track->f.sampleFormat == AF_SAMPFMT_DOUBLE)
{
formatTag = WAVE_FORMAT_IEEE_FLOAT;
}
else if (track->f.sampleFormat == AF_SAMPFMT_TWOSCOMP ||
track->f.sampleFormat == AF_SAMPFMT_UNSIGNED)
{
formatTag = WAVE_FORMAT_PCM;
}
else
{
_af_error(AF_BAD_COMPTYPE, "bad sample format");
return AF_FAIL;
}
blockAlign = _af_format_frame_size(&track->f, false);
bitsPerSample = 8 * _af_format_sample_size(&track->f, false);
break;
case AF_COMPRESSION_G711_ULAW:
chunkSize = 18;
formatTag = IBM_FORMAT_MULAW;
blockAlign = track->f.channelCount;
bitsPerSample = 8;
break;
case AF_COMPRESSION_G711_ALAW:
chunkSize = 18;
formatTag = IBM_FORMAT_ALAW;
blockAlign = track->f.channelCount;
bitsPerSample = 8;
break;
case AF_COMPRESSION_IMA:
chunkSize = 20;
formatTag = WAVE_FORMAT_DVI_ADPCM;
blockAlign = track->f.bytesPerPacket;
bitsPerSample = 4;
break;
case AF_COMPRESSION_MS_ADPCM:
chunkSize = 50;
formatTag = WAVE_FORMAT_ADPCM;
blockAlign = track->f.bytesPerPacket;
bitsPerSample = 4;
break;
default:
_af_error(AF_BAD_COMPTYPE, "bad compression type");
return AF_FAIL;
}
writeU32(&chunkSize);
writeU16(&formatTag);
channelCount = track->f.channelCount;
writeU16(&channelCount);
sampleRate = track->f.sampleRate;
writeU32(&sampleRate);
averageBytesPerSecond =
track->f.sampleRate * _af_format_frame_size(&track->f, false);
if (track->f.compressionType == AF_COMPRESSION_IMA ||
track->f.compressionType == AF_COMPRESSION_MS_ADPCM)
averageBytesPerSecond = track->f.sampleRate * track->f.bytesPerPacket /
track->f.framesPerPacket;
writeU32(&averageBytesPerSecond);
writeU16(&blockAlign);
writeU16(&bitsPerSample);
if (track->f.compressionType == AF_COMPRESSION_G711_ULAW ||
track->f.compressionType == AF_COMPRESSION_G711_ALAW)
{
uint16_t zero = 0;
writeU16(&zero);
}
else if (track->f.compressionType == AF_COMPRESSION_IMA)
{
uint16_t extraByteCount = 2;
writeU16(&extraByteCount);
uint16_t samplesPerBlock = track->f.framesPerPacket;
writeU16(&samplesPerBlock);
}
else if (track->f.compressionType == AF_COMPRESSION_MS_ADPCM)
{
uint16_t extraByteCount = 2 + 2 + m_msadpcmNumCoefficients * 4;
writeU16(&extraByteCount);
uint16_t samplesPerBlock = track->f.framesPerPacket;
writeU16(&samplesPerBlock);
uint16_t numCoefficients = m_msadpcmNumCoefficients;
writeU16(&numCoefficients);
for (int i=0; i<m_msadpcmNumCoefficients; i++)
{
writeS16(&m_msadpcmCoefficients[i][0]);
writeS16(&m_msadpcmCoefficients[i][1]);
}
}
return AF_SUCCEED;
}
status WAVEFile::writeFrameCount()
{
uint32_t factSize = 4;
uint32_t totalFrameCount;
Track *track = getTrack();
if (track->f.compressionType == AF_COMPRESSION_NONE &&
(track->f.sampleFormat == AF_SAMPFMT_TWOSCOMP ||
track->f.sampleFormat == AF_SAMPFMT_UNSIGNED))
return AF_SUCCEED;
if (m_factOffset == 0)
m_factOffset = m_fh->tell();
else
m_fh->seek(m_factOffset, File::SeekFromBeginning);
m_fh->write("fact", 4);
writeU32(&factSize);
totalFrameCount = track->totalfframes;
writeU32(&totalFrameCount);
return AF_SUCCEED;
}
status WAVEFile::writeData()
{
Track *track = getTrack();
m_fh->write("data", 4);
m_dataSizeOffset = m_fh->tell();
uint32_t chunkSize = track->data_size;
writeU32(&chunkSize);
track->fpos_first_frame = m_fh->tell();
return AF_SUCCEED;
}
status WAVEFile::update()
{
Track *track = getTrack();
if (track->fpos_first_frame != 0)
{
uint32_t dataLength, fileLength;
writeFrameCount();
m_fh->seek(m_dataSizeOffset, File::SeekFromBeginning);
dataLength = (uint32_t) track->data_size;
writeU32(&dataLength);
fileLength = (uint32_t) m_fh->length();
fileLength -= 8;
m_fh->seek(4, File::SeekFromBeginning);
writeU32(&fileLength);
}
writeMiscellaneous();
writeCues();
return AF_SUCCEED;
}
static bool misc_type_to_wave (int misctype, Tag *miscid)
{
if (misctype == AF_MISC_AUTH)
*miscid = "IART";
else if (misctype == AF_MISC_NAME)
*miscid = "INAM";
else if (misctype == AF_MISC_COPY)
*miscid = "ICOP";
else if (misctype == AF_MISC_ICMT)
*miscid = "ICMT";
else if (misctype == AF_MISC_ICRD)
*miscid = "ICRD";
else if (misctype == AF_MISC_ISFT)
*miscid = "ISFT";
else
return false;
return true;
}
status WAVEFile::writeMiscellaneous()
{
if (m_miscellaneousCount != 0)
{
uint32_t miscellaneousBytes;
uint32_t chunkSize;
miscellaneousBytes = 12;
for (int i=0; i<m_miscellaneousCount; i++)
{
Tag miscid;
if (!misc_type_to_wave(m_miscellaneous[i].type, &miscid))
continue;
miscellaneousBytes += 8;
miscellaneousBytes += m_miscellaneous[i].size;
if (m_miscellaneous[i].size % 2 != 0)
miscellaneousBytes++;
assert(miscellaneousBytes % 2 == 0);
}
if (m_miscellaneousOffset == 0)
m_miscellaneousOffset = m_fh->tell();
else
m_fh->seek(m_miscellaneousOffset, File::SeekFromBeginning);
m_fh->write("LIST", 4);
chunkSize = miscellaneousBytes-8;
writeU32(&chunkSize);
m_fh->write("INFO", 4);
for (int i=0; i<m_miscellaneousCount; i++)
{
uint32_t miscsize = m_miscellaneous[i].size;
Tag miscid;
if (!misc_type_to_wave(m_miscellaneous[i].type, &miscid))
continue;
writeTag(&miscid);
writeU32(&miscsize);
if (m_miscellaneous[i].buffer != NULL)
{
uint8_t zero = 0;
m_fh->write(m_miscellaneous[i].buffer, m_miscellaneous[i].size);
if ((m_miscellaneous[i].size%2) != 0)
writeU8(&zero);
}
else
{
int size;
size = m_miscellaneous[i].size;
if ((size % 2) != 0)
size++;
m_fh->seek(size, File::SeekFromCurrent);
}
}
}
return AF_SUCCEED;
}
status WAVEFile::writeCues()
{
Track *track = getTrack();
if (!track->markerCount)
return AF_SUCCEED;
if (m_markOffset == 0)
m_markOffset = m_fh->tell();
else
m_fh->seek(m_markOffset, File::SeekFromBeginning);
Tag cue("cue ");
writeTag(&cue);
uint32_t cueChunkSize = 4 + track->markerCount * 24;
writeU32(&cueChunkSize);
uint32_t numCues = track->markerCount;
writeU32(&numCues);
for (int i=0; i<track->markerCount; i++)
{
uint32_t identifier = track->markers[i].id;
writeU32(&identifier);
uint32_t position = i;
writeU32(&position);
Tag data("data");
writeTag(&data);
uint32_t chunkStart = 0;
writeU32(&chunkStart);
uint32_t blockStart = 0;
writeU32(&blockStart);
AFframecount markPosition = track->markers[i].position;
uint32_t sampleOffset = markPosition;
writeU32(&sampleOffset);
}
uint32_t listChunkSize = 4;
for (int i=0; i<track->markerCount; i++)
{
const char *name = track->markers[i].name;
const char *comment = track->markers[i].comment;
listChunkSize += 12 + zStringLength(name);
listChunkSize += 12 + zStringLength(comment);
}
Tag list("LIST");
writeTag(&list);
writeU32(&listChunkSize);
Tag adtl("adtl");
writeTag(&adtl);
for (int i=0; i<track->markerCount; i++)
{
uint32_t cuePointID = track->markers[i].id;
const char *name = track->markers[i].name;
uint32_t labelSize = 4 + zStringLength(name);
Tag lablTag("labl");
writeTag(&lablTag);
writeU32(&labelSize);
writeU32(&cuePointID);
writeZString(name);
const char *comment = track->markers[i].comment;
uint32_t noteSize = 4 + zStringLength(comment);
Tag noteTag("note");
writeTag(¬eTag);
writeU32(¬eSize);
writeU32(&cuePointID);
writeZString(comment);
}
return AF_SUCCEED;
}
bool WAVEFile::writeZString(const char *s)
{
ssize_t lengthPlusNull = strlen(s) + 1;
if (m_fh->write(s, lengthPlusNull) != lengthPlusNull)
return false;
if (lengthPlusNull & 1)
{
uint8_t zero = 0;
if (!writeU8(&zero))
return false;
}
return true;
}
size_t WAVEFile::zStringLength(const char *s)
{
size_t lengthPlusNull = strlen(s) + 1;
return lengthPlusNull + (lengthPlusNull & 1);
}
status WAVEFile::writeInit(AFfilesetup setup)
{
if (initFromSetup(setup) == AF_FAIL)
return AF_FAIL;
initCompressionParams();
uint32_t zero = 0;
m_fh->seek(0, File::SeekFromBeginning);
m_fh->write("RIFF", 4);
m_fh->write(&zero, 4);
m_fh->write("WAVE", 4);
writeMiscellaneous();
writeCues();
writeFormat();
writeFrameCount();
writeData();
return AF_SUCCEED;
}
bool WAVEFile::readUUID(UUID *u)
{
return m_fh->read(u->data, 16) == 16;
}
bool WAVEFile::writeUUID(const UUID *u)
{
return m_fh->write(u->data, 16) == 16;
}
void WAVEFile::initCompressionParams()
{
Track *track = getTrack();
if (track->f.compressionType == AF_COMPRESSION_IMA)
initIMACompressionParams();
else if (track->f.compressionType == AF_COMPRESSION_MS_ADPCM)
initMSADPCMCompressionParams();
}
void WAVEFile::initIMACompressionParams()
{
Track *track = getTrack();
track->f.framesPerPacket = 505;
track->f.bytesPerPacket = 256 * track->f.channelCount;
AUpvlist pv = AUpvnew(1);
AUpvsetparam(pv, 0, _AF_IMA_ADPCM_TYPE);
AUpvsetvaltype(pv, 0, AU_PVTYPE_LONG);
long l = _AF_IMA_ADPCM_TYPE_WAVE;
AUpvsetval(pv, 0, &l);
track->f.compressionParams = pv;
}
void WAVEFile::initMSADPCMCompressionParams()
{
const int16_t coefficients[7][2] =
{
{ 256, 0 },
{ 512, -256 },
{ 0, 0 },
{ 192, 64 },
{ 240, 0 },
{ 460, -208 },
{ 392, -232 }
};
memcpy(m_msadpcmCoefficients, coefficients, sizeof (int16_t) * 7 * 2);
m_msadpcmNumCoefficients = 7;
Track *track = getTrack();
track->f.framesPerPacket = 500;
track->f.bytesPerPacket = 256 * track->f.channelCount;
AUpvlist pv = AUpvnew(2);
AUpvsetparam(pv, 0, _AF_MS_ADPCM_NUM_COEFFICIENTS);
AUpvsetvaltype(pv, 0, AU_PVTYPE_LONG);
long l = m_msadpcmNumCoefficients;
AUpvsetval(pv, 0, &l);
AUpvsetparam(pv, 1, _AF_MS_ADPCM_COEFFICIENTS);
AUpvsetvaltype(pv, 1, AU_PVTYPE_PTR);
void *v = m_msadpcmCoefficients;
AUpvsetval(pv, 1, &v);
track->f.compressionParams = pv;
}
#include <string.h>
#include <assert.h>
void afInitAESChannelData (AFfilesetup setup, int trackid)
{
if (!_af_filesetup_ok(setup))
return;
TrackSetup *track = setup->getTrack(trackid);
if (!track)
return;
track->aesDataSet = true;
}
void afInitAESChannelDataTo (AFfilesetup setup, int trackid, int willBeData)
{
if (!_af_filesetup_ok(setup))
return;
TrackSetup *track = setup->getTrack(trackid);
if (!track)
return;
track->aesDataSet = willBeData;
}
int afGetAESChannelData (AFfilehandle file, int trackid, unsigned char buf[24])
{
if (!_af_filehandle_ok(file))
return -1;
Track *track = file->getTrack(trackid);
if (!track)
return -1;
if (!track->hasAESData)
{
if (buf)
memset(buf, 0, 24);
return 0;
}
if (buf)
memcpy(buf, track->aesData, 24);
return 1;
}
void afSetAESChannelData (AFfilehandle file, int trackid, unsigned char buf[24])
{
if (!_af_filehandle_ok(file))
return;
Track *track = file->getTrack(trackid);
if (!track)
return;
if (!file->checkCanWrite())
return;
if (track->hasAESData)
{
memcpy(track->aesData, buf, 24);
}
else
{
_af_error(AF_BAD_NOAESDATA,
"unable to store AES channel status data for track %d",
trackid);
}
}
#include <stdlib.h>
AFvirtualfile *af_virtual_file_new()
{
return (AFvirtualfile *) calloc(sizeof (AFvirtualfile), 1);
}
void af_virtual_file_destroy(AFvirtualfile *vfile)
{
vfile->destroy(vfile);
free(vfile);
}
#include <stdlib.h>
#include <string.h>
#include <assert.h>
AUpvlist AUpvnew (int maxitems)
{
AUpvlist aupvlist;
int i;
if (maxitems <= 0)
return AU_NULL_PVLIST;
aupvlist = (AUpvlist) malloc(sizeof (struct _AUpvlist));
assert(aupvlist);
if (aupvlist == NULL)
return AU_NULL_PVLIST;
aupvlist->items = (struct _AUpvitem *)calloc(maxitems, sizeof (struct _AUpvitem));
assert(aupvlist->items);
if (aupvlist->items == NULL)
{
free(aupvlist);
return AU_NULL_PVLIST;
}
for (i=0; i<maxitems; i++)
{
aupvlist->items[i].valid = _AU_VALID_PVITEM;
aupvlist->items[i].type = AU_PVTYPE_LONG;
aupvlist->items[i].parameter = 0;
memset(&aupvlist->items[i].value, 0, sizeof (aupvlist->items[i].value));
}
aupvlist->valid = _AU_VALID_PVLIST;
aupvlist->count = maxitems;
return aupvlist;
}
int AUpvgetmaxitems (AUpvlist list)
{
assert(list);
if (list == AU_NULL_PVLIST)
return AU_BAD_PVLIST;
if (list->valid != _AU_VALID_PVLIST)
return AU_BAD_PVLIST;
return list->count;
}
int AUpvfree (AUpvlist list)
{
assert(list);
assert(list->items);
if (list == AU_NULL_PVLIST)
return AU_BAD_PVLIST;
if (list->valid != _AU_VALID_PVLIST)
return AU_BAD_PVLIST;
if ((list->items != _AU_NULL_PVITEM) &&
(list->items[0].valid == _AU_VALID_PVITEM))
{
free(list->items);
}
free(list);
return _AU_SUCCESS;
}
int AUpvsetparam (AUpvlist list, int item, int param)
{
assert(list);
assert(list->items);
assert(item >= 0);
assert(item < list->count);
if (list == AU_NULL_PVLIST)
return AU_BAD_PVLIST;
if (list->valid != _AU_VALID_PVLIST)
return AU_BAD_PVLIST;
if ((item < 0) || (item > list->count - 1))
return AU_BAD_PVITEM;
if (list->items[item].valid != _AU_VALID_PVITEM)
return AU_BAD_PVLIST;
list->items[item].parameter = param;
return _AU_SUCCESS;
}
int AUpvsetvaltype (AUpvlist list, int item, int type)
{
assert(list);
assert(list->items);
assert(item >= 0);
assert(item < list->count);
if (list == AU_NULL_PVLIST)
return AU_BAD_PVLIST;
if (list->valid != _AU_VALID_PVLIST)
return AU_BAD_PVLIST;
if ((item < 0) || (item > list->count - 1))
return AU_BAD_PVITEM;
if (list->items[item].valid != _AU_VALID_PVITEM)
return AU_BAD_PVLIST;
list->items[item].type = type;
return _AU_SUCCESS;
}
int AUpvsetval (AUpvlist list, int item, void *val)
{
assert(list);
assert(list->items);
assert(item >= 0);
assert(item < list->count);
if (list == AU_NULL_PVLIST)
return AU_BAD_PVLIST;
if (list->valid != _AU_VALID_PVLIST)
return AU_BAD_PVLIST;
if ((item < 0) || (item > list->count - 1))
return AU_BAD_PVITEM;
if (list->items[item].valid != _AU_VALID_PVITEM)
return AU_BAD_PVLIST;
switch (list->items[item].type)
{
case AU_PVTYPE_LONG:
list->items[item].value.l = *((long *) val);
break;
case AU_PVTYPE_DOUBLE:
list->items[item].value.d = *((double *) val);
break;
case AU_PVTYPE_PTR:
list->items[item].value.v = *((void **) val);
break;
default:
assert(0);
return AU_BAD_PVLIST;
}
return _AU_SUCCESS;
}
int AUpvgetparam (AUpvlist list, int item, int *param)
{
assert(list);
assert(list->items);
assert(item >= 0);
assert(item < list->count);
if (list == AU_NULL_PVLIST)
return AU_BAD_PVLIST;
if (list->valid != _AU_VALID_PVLIST)
return AU_BAD_PVLIST;
if ((item < 0) || (item > list->count - 1))
return AU_BAD_PVITEM;
if (list->items[item].valid != _AU_VALID_PVITEM)
return AU_BAD_PVLIST;
*param = list->items[item].parameter;
return _AU_SUCCESS;
}
int AUpvgetvaltype (AUpvlist list, int item, int *type)
{
assert(list);
assert(list->items);
assert(item >= 0);
assert(item < list->count);
if (list == AU_NULL_PVLIST)
return AU_BAD_PVLIST;
if (list->valid != _AU_VALID_PVLIST)
return AU_BAD_PVLIST;
if ((item < 0) || (item > list->count - 1))
return AU_BAD_PVITEM;
if (list->items[item].valid != _AU_VALID_PVITEM)
return AU_BAD_PVLIST;
*type = list->items[item].type;
return _AU_SUCCESS;
}
int AUpvgetval (AUpvlist list, int item, void *val)
{
assert(list);
assert(list->items);
assert(item >= 0);
assert(item < list->count);
if (list == AU_NULL_PVLIST)
return AU_BAD_PVLIST;
if (list->valid != _AU_VALID_PVLIST)
return AU_BAD_PVLIST;
if ((item < 0) || (item > list->count - 1))
return AU_BAD_PVITEM;
if (list->items[item].valid != _AU_VALID_PVITEM)
return AU_BAD_PVLIST;
switch (list->items[item].type)
{
case AU_PVTYPE_LONG:
*((long *) val) = list->items[item].value.l;
break;
case AU_PVTYPE_DOUBLE:
*((double *) val) = list->items[item].value.d;
break;
case AU_PVTYPE_PTR:
*((void **) val) = list->items[item].value.v;
break;
}
return _AU_SUCCESS;
}
#include <assert.h>
const CompressionUnit *_af_compression_unit_from_id (int compressionid)
{
for (int i=0; i<_AF_NUM_COMPRESSION; i++)
if (_af_compression[i].compressionID == compressionid)
return &_af_compression[i];
_af_error(AF_BAD_COMPTYPE, "compression type %d not available", compressionid);
return NULL;
}
int afGetCompression (AFfilehandle file, int trackid)
{
if (!_af_filehandle_ok(file))
return -1;
Track *track = file->getTrack(trackid);
if (!track)
return -1;
return track->f.compressionType;
}
void afInitCompression (AFfilesetup setup, int trackid, int compression)
{
if (!_af_filesetup_ok(setup))
return;
TrackSetup *track = setup->getTrack(trackid);
if (!track)
return;
if (!_af_compression_unit_from_id(compression))
return;
track->compressionSet = true;
track->f.compressionType = compression;
}
#if 0
int afGetCompressionParams (AFfilehandle file, int trackid,
int *compression, AUpvlist pvlist, int numitems)
{
assert(file);
assert(trackid == AF_DEFAULT_TRACK);
}
void afInitCompressionParams (AFfilesetup setup, int trackid,
int compression, AUpvlist pvlist, int numitems)
{
assert(setup);
assert(trackid == AF_DEFAULT_TRACK);
}
#endif
#include <assert.h>
#include <stdlib.h>
#include <string.h>
int afWriteFrames (AFfilehandle file, int trackid, const void *samples,
int nvframes2write)
{
SharedPtr<Module> firstmod;
SharedPtr<Chunk> userc;
int bytes_per_vframe;
AFframecount vframe;
if (!_af_filehandle_ok(file))
return -1;
if (!file->checkCanWrite())
return -1;
Track *track = file->getTrack(trackid);
if (!track)
return -1;
if (track->ms->isDirty() && track->ms->setup(file, track) == AF_FAIL)
return -1;
if (!track->ms->fileModuleHandlesSeeking() &&
file->m_seekok &&
file->m_fh->seek(track->fpos_next_frame, File::SeekFromBeginning) !=
track->fpos_next_frame)
{
_af_error(AF_BAD_LSEEK, "unable to position write pointer at next frame");
return -1;
}
bytes_per_vframe = _af_format_frame_size(&track->v, true);
firstmod = track->ms->modules().front();
userc = track->ms->chunks().front();
track->filemodhappy = true;
vframe = 0;
#ifdef UNLIMITED_CHUNK_NVFRAMES
if (!trk->ms->mustUseAtomicNVFrames())
{
userc->buffer = (char *) samples;
userc->frameCount = nvframes2write;
firstmod->runPush();
if (trk->filemodhappy)
vframe += userc->frameCount;
}
else
#else
assert(track->ms->mustUseAtomicNVFrames());
#endif
{
while (vframe < nvframes2write)
{
userc->buffer = (char *) samples + bytes_per_vframe * vframe;
if (vframe <= nvframes2write - _AF_ATOMIC_NVFRAMES)
userc->frameCount = _AF_ATOMIC_NVFRAMES;
else
userc->frameCount = nvframes2write - vframe;
firstmod->runPush();
if (!track->filemodhappy)
break;
vframe += userc->frameCount;
}
}
track->nextvframe += vframe;
track->totalvframes += vframe;
return vframe;
}
int afReadFrames (AFfilehandle file, int trackid, void *samples,
int nvframeswanted)
{
SharedPtr<Module> firstmod;
SharedPtr<Chunk> userc;
AFframecount nvframesleft, nvframes2read;
int bytes_per_vframe;
AFframecount vframe;
if (!_af_filehandle_ok(file))
return -1;
if (!file->checkCanRead())
return -1;
Track *track = file->getTrack(trackid);
if (!track)
return -1;
if (track->ms->isDirty() && track->ms->setup(file, track) == AF_FAIL)
return -1;
if (!track->ms->fileModuleHandlesSeeking() &&
file->m_seekok &&
file->m_fh->seek(track->fpos_next_frame, File::SeekFromBeginning) !=
track->fpos_next_frame)
{
_af_error(AF_BAD_LSEEK, "unable to position read pointer at next frame");
return -1;
}
if (track->totalvframes == -1)
nvframes2read = nvframeswanted;
else
{
nvframesleft = track->totalvframes - track->nextvframe;
nvframes2read = (nvframeswanted > nvframesleft) ?
nvframesleft : nvframeswanted;
}
bytes_per_vframe = _af_format_frame_size(&track->v, true);
firstmod = track->ms->modules().back();
userc = track->ms->chunks().back();
track->filemodhappy = true;
vframe = 0;
if (!track->ms->mustUseAtomicNVFrames())
{
assert(track->frames2ignore == 0);
userc->buffer = samples;
userc->frameCount = nvframes2read;
firstmod->runPull();
if (track->filemodhappy)
vframe += userc->frameCount;
}
else
{
bool eof = false;
if (track->frames2ignore != 0)
{
userc->frameCount = track->frames2ignore;
userc->allocate(track->frames2ignore * bytes_per_vframe);
if (!userc->buffer)
return 0;
firstmod->runPull();
if (static_cast<ssize_t>(userc->frameCount) < track->frames2ignore)
eof = true;
track->frames2ignore = 0;
userc->deallocate();
}
while (track->filemodhappy && !eof && vframe < nvframes2read)
{
AFframecount nvframes2pull;
userc->buffer = (char *) samples + bytes_per_vframe * vframe;
if (vframe <= nvframes2read - _AF_ATOMIC_NVFRAMES)
nvframes2pull = _AF_ATOMIC_NVFRAMES;
else
nvframes2pull = nvframes2read - vframe;
userc->frameCount = nvframes2pull;
firstmod->runPull();
if (track->filemodhappy)
{
vframe += userc->frameCount;
if (static_cast<ssize_t>(userc->frameCount) < nvframes2pull)
eof = true;
}
}
}
track->nextvframe += vframe;
return vframe;
}
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <assert.h>
void _af_print_pvlist (AUpvlist list)
{
assert(list);
printf("list.valid: %d\n", list->valid);
printf("list.count: %zu\n", list->count);
for (unsigned i=0; i<list->count; i++)
{
printf("item %u valid %d, should be %d\n",
i, list->items[i].valid, _AU_VALID_PVITEM);
switch (list->items[i].type)
{
case AU_PVTYPE_LONG:
printf("item #%u, parameter %d, long: %ld\n",
i, list->items[i].parameter,
list->items[i].value.l);
break;
case AU_PVTYPE_DOUBLE:
printf("item #%u, parameter %d, double: %f\n",
i, list->items[i].parameter,
list->items[i].value.d);
break;
case AU_PVTYPE_PTR:
printf("item #%u, parameter %d, pointer: %p\n",
i, list->items[i].parameter,
list->items[i].value.v);
break;
default:
printf("item #%u, invalid type %d\n", i,
list->items[i].type);
assert(false);
break;
}
}
}
void _af_print_audioformat (AudioFormat *fmt)
{
printf("{ %7.2f Hz %d ch ", fmt->sampleRate, fmt->channelCount);
switch (fmt->sampleFormat)
{
case AF_SAMPFMT_TWOSCOMP:
printf("%db 2 ", fmt->sampleWidth);
break;
case AF_SAMPFMT_UNSIGNED:
printf("%db u ", fmt->sampleWidth);
break;
case AF_SAMPFMT_FLOAT:
printf("flt ");
break;
case AF_SAMPFMT_DOUBLE:
printf("dbl ");
break;
default:
printf("%dsampfmt? ", fmt->sampleFormat);
}
printf("(%.30g+-%.30g [%.30g,%.30g]) ",
fmt->pcm.intercept, fmt->pcm.slope,
fmt->pcm.minClip, fmt->pcm.maxClip);
switch (fmt->byteOrder)
{
case AF_BYTEORDER_BIGENDIAN:
printf("big ");
break;
case AF_BYTEORDER_LITTLEENDIAN:
printf("little ");
break;
default:
printf("%dbyteorder? ", fmt->byteOrder);
break;
}
{
const CompressionUnit *unit = _af_compression_unit_from_id(fmt->compressionType);
if (!unit)
printf("%dcompression?", fmt->compressionType);
else if (fmt->compressionType == AF_COMPRESSION_NONE)
printf("pcm");
else
printf("%s", unit->label);
}
printf(" }");
}
void _af_print_tracks (AFfilehandle filehandle)
{
for (int i=0; i<filehandle->m_trackCount; i++)
{
Track *track = &filehandle->m_tracks[i];
printf("track %d\n", i);
printf(" id %d\n", track->id);
printf(" sample format\n");
_af_print_audioformat(&track->f);
printf(" virtual format\n");
_af_print_audioformat(&track->v);
printf(" total file frames: %jd\n",
(intmax_t) track->totalfframes);
printf(" total virtual frames: %jd\n",
(intmax_t) track->totalvframes);
printf(" next file frame: %jd\n",
(intmax_t) track->nextfframe);
printf(" next virtual frame: %jd\n",
(intmax_t) track->nextvframe);
printf(" frames to ignore: %jd\n",
(intmax_t) track->frames2ignore);
printf(" data_size: %jd\n",
(intmax_t) track->data_size);
printf(" fpos_first_frame: %jd\n",
(intmax_t) track->fpos_first_frame);
printf(" fpos_next_frame: %jd\n",
(intmax_t) track->fpos_next_frame);
printf(" fpos_after_data: %jd\n",
(intmax_t) track->fpos_after_data);
printf(" channel matrix:");
_af_print_channel_matrix(track->channelMatrix,
track->f.channelCount, track->v.channelCount);
printf("\n");
printf(" marker count: %d\n", track->markerCount);
}
}
void _af_print_filehandle (AFfilehandle filehandle)
{
printf("file handle: 0x%p\n", filehandle);
if (filehandle->m_valid == _AF_VALID_FILEHANDLE)
printf("valid\n");
else
printf("invalid!\n");
printf(" access: ");
if (filehandle->m_access == _AF_READ_ACCESS)
putchar('r');
else
putchar('w');
printf(" fileFormat: %d\n", filehandle->m_fileFormat);
printf(" instrument count: %d\n", filehandle->m_instrumentCount);
printf(" instruments: 0x%p\n", filehandle->m_instruments);
printf(" miscellaneous count: %d\n", filehandle->m_miscellaneousCount);
printf(" miscellaneous: 0x%p\n", filehandle->m_miscellaneous);
printf(" trackCount: %d\n", filehandle->m_trackCount);
printf(" tracks: 0x%p\n", filehandle->m_tracks);
_af_print_tracks(filehandle);
}
void _af_print_channel_matrix (double *matrix, int fchans, int vchans)
{
int v, f;
if (!matrix)
{
printf("NULL");
return;
}
printf("{");
for (v=0; v < vchans; v++)
{
if (v) printf(" ");
printf("{");
for (f=0; f < fchans; f++)
{
if (f) printf(" ");
printf("%5.2f", *(matrix + v*fchans + f));
}
printf("}");
}
printf("}");
}
void _af_print_frame (AFframecount frameno, double *frame, int nchannels,
char *formatstring, int numberwidth,
double slope, double intercept, double minclip, double maxclip)
{
char linebuf[81];
int wavewidth = 78 - numberwidth*nchannels - 6;
int c;
memset(linebuf, ' ', 80);
linebuf[0] = '|';
linebuf[wavewidth-1] = '|';
linebuf[wavewidth] = 0;
printf("%05jd ", (intmax_t) frameno);
for (c=0; c < nchannels; c++)
{
double pcm = frame[c];
printf(formatstring, pcm);
}
for (c=0; c < nchannels; c++)
{
double pcm = frame[c], volts;
if (maxclip > minclip)
{
if (pcm < minclip) pcm = minclip;
if (pcm > maxclip) pcm = maxclip;
}
volts = (pcm - intercept) / slope;
linebuf[(int)((volts/2 + 0.5)*(wavewidth-3)) + 1] = '0' + c;
}
printf("%s\n", linebuf);
}
#include <stdio.h>
#include <stdarg.h>
#include <assert.h>
static void defaultErrorFunction (long error, const char *str);
static AFerrfunc errorFunction = defaultErrorFunction;
AFerrfunc afSetErrorHandler (AFerrfunc efunc)
{
AFerrfunc old;
old = errorFunction;
errorFunction = efunc;
return old;
}
static void defaultErrorFunction (long error, const char *str)
{
fprintf(stderr, "Audio File Library: ");
fprintf(stderr, "%s", str);
fprintf(stderr, " [error %ld]\n", error);
}
void _af_error (int errorCode, const char *fmt, ...)
{
char buf[1024];
va_list ap;
va_start(ap, fmt);
vsnprintf(buf, 1024, fmt, ap);
va_end(ap);
if (errorFunction != NULL)
errorFunction(errorCode, buf);
}
#include <math.h>
#ifndef HUGE_VAL
#define HUGE_VAL HUGE
#endif
#define FloatToUnsigned(f) ((unsigned long) (((long) (f - 2147483648.0)) + 2147483647L) + 1)
void _af_convert_to_ieee_extended (double num, unsigned char *bytes)
{
int sign;
int expon;
double fMant, fsMant;
unsigned long hiMant, loMant;
if (num < 0) {
sign = 0x8000;
num *= -1;
} else {
sign = 0;
}
if (num == 0) {
expon = 0; hiMant = 0; loMant = 0;
}
else {
fMant = frexp(num, &expon);
if ((expon > 16384) || !(fMant < 1)) {
expon = sign|0x7FFF; hiMant = 0; loMant = 0;
}
else {
expon += 16382;
if (expon < 0) {
fMant = ldexp(fMant, expon);
expon = 0;
}
expon |= sign;
fMant = ldexp(fMant, 32);
fsMant = floor(fMant);
hiMant = FloatToUnsigned(fsMant);
fMant = ldexp(fMant - fsMant, 32);
fsMant = floor(fMant);
loMant = FloatToUnsigned(fsMant);
}
}
bytes[0] = expon >> 8;
bytes[1] = expon;
bytes[2] = hiMant >> 24;
bytes[3] = hiMant >> 16;
bytes[4] = hiMant >> 8;
bytes[5] = hiMant;
bytes[6] = loMant >> 24;
bytes[7] = loMant >> 16;
bytes[8] = loMant >> 8;
bytes[9] = loMant;
}
#define UnsignedToFloat(u) (((double) ((long) (u - 2147483647L - 1))) + 2147483648.0)
double _af_convert_from_ieee_extended (const unsigned char *bytes)
{
double f;
int expon;
unsigned long hiMant, loMant;
expon = ((bytes[0] & 0x7F) << 8) | (bytes[1] & 0xFF);
hiMant = ((unsigned long)(bytes[2] & 0xFF) << 24)
| ((unsigned long) (bytes[3] & 0xFF) << 16)
| ((unsigned long) (bytes[4] & 0xFF) << 8)
| ((unsigned long) (bytes[5] & 0xFF));
loMant = ((unsigned long) (bytes[6] & 0xFF) << 24)
| ((unsigned long) (bytes[7] & 0xFF) << 16)
| ((unsigned long) (bytes[8] & 0xFF) << 8)
| ((unsigned long) (bytes[9] & 0xFF));
if (expon == 0 && hiMant == 0 && loMant == 0) {
f = 0;
}
else {
if (expon == 0x7FFF) {
f = HUGE_VAL;
}
else {
expon -= 16383;
f = ldexp(UnsignedToFloat(hiMant), expon-=31);
f += ldexp(UnsignedToFloat(loMant), expon-=32);
}
}
if (bytes[0] & 0x80)
return -f;
else
return f;
}
#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
AFfileoffset afGetDataOffset (AFfilehandle file, int trackid)
{
if (!_af_filehandle_ok(file))
return -1;
Track *track = file->getTrack(trackid);
if (!track)
return -1;
return track->fpos_first_frame;
}
AFfileoffset afGetTrackBytes (AFfilehandle file, int trackid)
{
if (!_af_filehandle_ok(file))
return -1;
Track *track = file->getTrack(trackid);
if (!track)
return -1;
return track->data_size;
}
float afGetFrameSize (AFfilehandle file, int trackid, int stretch3to4)
{
if (!_af_filehandle_ok(file))
return -1;
Track *track = file->getTrack(trackid);
if (!track)
return -1;
return _af_format_frame_size(&track->f, stretch3to4);
}
float afGetVirtualFrameSize (AFfilehandle file, int trackid, int stretch3to4)
{
if (!_af_filehandle_ok(file))
return -1;
Track *track = file->getTrack(trackid);
if (!track)
return -1;
return _af_format_frame_size(&track->v, stretch3to4);
}
AFframecount afSeekFrame (AFfilehandle file, int trackid, AFframecount frame)
{
if (!_af_filehandle_ok(file))
return -1;
if (!file->checkCanRead())
return -1;
Track *track = file->getTrack(trackid);
if (!track)
return -1;
if (track->ms->isDirty() && track->ms->setup(file, track) == AF_FAIL)
return -1;
if (frame < 0)
return track->nextvframe;
if (frame == track->nextvframe)
return track->nextvframe;
if (track->totalvframes != -1)
if (frame > track->totalvframes)
frame = track->totalvframes - 1;
track->nextvframe = frame;
if (track->ms->setup(file, track) == AF_FAIL)
return -1;
return track->nextvframe;
}
AFfileoffset afTellFrame (AFfilehandle file, int trackid)
{
return afSeekFrame(file, trackid, -1);
}
int afSetVirtualByteOrder (AFfilehandle file, int trackid, int byteorder)
{
if (!_af_filehandle_ok(file))
return AF_FAIL;
Track *track = file->getTrack(trackid);
if (!track)
return AF_FAIL;
if (byteorder != AF_BYTEORDER_BIGENDIAN &&
byteorder != AF_BYTEORDER_LITTLEENDIAN)
{
_af_error(AF_BAD_BYTEORDER, "invalid byte order %d", byteorder);
return AF_FAIL;
}
track->v.byteOrder = byteorder;
track->ms->setDirty();
return AF_SUCCEED;
}
int afGetByteOrder (AFfilehandle file, int trackid)
{
if (!_af_filehandle_ok(file))
return -1;
Track *track = file->getTrack(trackid);
if (!track)
return -1;
return track->f.byteOrder;
}
int afGetVirtualByteOrder (AFfilehandle file, int trackid)
{
if (!_af_filehandle_ok(file))
return -1;
Track *track = file->getTrack(trackid);
if (!track)
return -1;
return track->v.byteOrder;
}
AFframecount afGetFrameCount (AFfilehandle file, int trackid)
{
if (!_af_filehandle_ok(file))
return -1;
Track *track = file->getTrack(trackid);
if (!track)
return -1;
if (track->ms->isDirty() && track->ms->setup(file, track) == AF_FAIL)
return -1;
return track->totalvframes;
}
double afGetRate (AFfilehandle file, int trackid)
{
if (!_af_filehandle_ok(file))
return -1;
Track *track = file->getTrack(trackid);
if (!track)
return -1;
return track->f.sampleRate;
}
int afGetChannels (AFfilehandle file, int trackid)
{
if (!_af_filehandle_ok(file))
return -1;
Track *track = file->getTrack(trackid);
if (!track)
return -1;
return track->f.channelCount;
}
void afGetSampleFormat (AFfilehandle file, int trackid, int *sampleFormat, int *sampleWidth)
{
if (!_af_filehandle_ok(file))
return;
Track *track = file->getTrack(trackid);
if (!track)
return;
if (sampleFormat)
*sampleFormat = track->f.sampleFormat;
if (sampleWidth)
*sampleWidth = track->f.sampleWidth;
}
void afGetVirtualSampleFormat (AFfilehandle file, int trackid, int *sampleFormat, int *sampleWidth)
{
if (!_af_filehandle_ok(file))
return;
Track *track = file->getTrack(trackid);
if (!track)
return;
if (sampleFormat)
*sampleFormat = track->v.sampleFormat;
if (sampleWidth)
*sampleWidth = track->v.sampleWidth;
}
int afSetVirtualSampleFormat (AFfilehandle file, int trackid,
int sampleFormat, int sampleWidth)
{
if (!_af_filehandle_ok(file))
return -1;
Track *track = file->getTrack(trackid);
if (!track)
return -1;
if (_af_set_sample_format(&track->v, sampleFormat, sampleWidth) == AF_FAIL)
return -1;
track->ms->setDirty();
return 0;
}
int afGetFileFormat (AFfilehandle file, int *version)
{
if (!_af_filehandle_ok(file))
return -1;
if (version != NULL)
*version = file->getVersion();
return file->m_fileFormat;
}
int afSetVirtualChannels (AFfilehandle file, int trackid, int channelCount)
{
if (!_af_filehandle_ok(file))
return -1;
Track *track = file->getTrack(trackid);
if (!track)
return -1;
track->v.channelCount = channelCount;
track->ms->setDirty();
if (track->channelMatrix)
free(track->channelMatrix);
track->channelMatrix = NULL;
return 0;
}
double afGetVirtualRate (AFfilehandle file, int trackid)
{
if (!_af_filehandle_ok(file))
return -1;
Track *track = file->getTrack(trackid);
if (!track)
return -1;
return track->v.sampleRate;
}
int afSetVirtualRate (AFfilehandle file, int trackid, double rate)
{
if (!_af_filehandle_ok(file))
return -1;
Track *track = file->getTrack(trackid);
if (!track)
return -1;
if (rate < 0)
{
_af_error(AF_BAD_RATE, "invalid sampling rate %.30g", rate);
return -1;
}
track->v.sampleRate = rate;
track->ms->setDirty();
return 0;
}
void afSetChannelMatrix (AFfilehandle file, int trackid, double* matrix)
{
if (!_af_filehandle_ok(file))
return;
Track *track = file->getTrack(trackid);
if (!track)
return;
if (track->channelMatrix != NULL)
free(track->channelMatrix);
track->channelMatrix = NULL;
if (matrix != NULL)
{
int i, size;
size = track->v.channelCount * track->f.channelCount;
track->channelMatrix = (double *) malloc(size * sizeof (double));
for (i = 0; i < size; i++)
track->channelMatrix[i] = matrix[i];
}
}
int afGetVirtualChannels (AFfilehandle file, int trackid)
{
if (!_af_filehandle_ok(file))
return -1;
Track *track = file->getTrack(trackid);
if (!track)
return -1;
return track->v.channelCount;
}
#define SUPERCEDED
#define SIGN_BIT (0x80)
#define QUANT_MASK (0xf)
#define NSEGS (8)
#define SEG_SHIFT (4)
#define SEG_MASK (0x70)
#ifdef SUPERCEDED
static const short seg_end[8] = {0xFF, 0x1FF, 0x3FF, 0x7FF,
0xFFF, 0x1FFF, 0x3FFF, 0x7FFF};
static int search(int val, const short *table, int size)
{
int i;
for (i = 0; i < size; i++) {
if (val <= *table++)
return (i);
}
return (size);
}
unsigned char
_af_linear2alaw(int pcm_val)
{
int mask;
int seg;
unsigned char aval;
if (pcm_val >= 0) {
mask = 0xD5;
} else {
mask = 0x55;
pcm_val = -pcm_val - 8;
}
seg = search(pcm_val, seg_end, 8);
if (seg >= 8)
return (0x7F ^ mask);
else {
aval = seg << SEG_SHIFT;
if (seg < 2)
aval |= (pcm_val >> 4) & QUANT_MASK;
else
aval |= (pcm_val >> (seg + 3)) & QUANT_MASK;
return (aval ^ mask);
}
}
int
_af_alaw2linear(unsigned char a_val)
{
int t;
int seg;
a_val ^= 0x55;
t = (a_val & QUANT_MASK) << 4;
seg = ((unsigned)a_val & SEG_MASK) >> SEG_SHIFT;
switch (seg) {
case 0:
t += 8;
break;
case 1:
t += 0x108;
break;
default:
t += 0x108;
t <<= seg - 1;
}
return ((a_val & SIGN_BIT) ? t : -t);
}
#define BIAS (0x84)
unsigned char _af_linear2ulaw (int pcm_val)
{
int mask;
int seg;
unsigned char uval;
if (pcm_val < 0) {
pcm_val = BIAS - pcm_val;
mask = 0x7F;
} else {
pcm_val += BIAS;
mask = 0xFF;
}
seg = search(pcm_val, seg_end, 8);
if (seg >= 8)
return (0x7F ^ mask);
else {
uval = (seg << 4) | ((pcm_val >> (seg + 3)) & 0xF);
return (uval ^ mask);
}
}
int _af_ulaw2linear (unsigned char u_val)
{
int t;
u_val = ~u_val;
t = ((u_val & QUANT_MASK) << 3) + BIAS;
t <<= ((unsigned)u_val & SEG_MASK) >> SEG_SHIFT;
return ((u_val & SIGN_BIT) ? (BIAS - t) : (t - BIAS));
}
#endif
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <audiofile.h>
static status _afOpenFile (int access, File *f, const char *filename,
AFfilehandle *file, AFfilesetup filesetup);
int _af_identify (File *f, int *implemented)
{
if (!f->canSeek())
{
_af_error(AF_BAD_LSEEK, "Cannot seek in file");
return AF_FILE_UNKNOWN;
}
AFfileoffset curpos = f->tell();
for (int i=0; i<_AF_NUM_UNITS; i++)
{
if (_af_units[i].recognize &&
_af_units[i].recognize(f))
{
if (implemented != NULL)
*implemented = _af_units[i].implemented;
f->seek(curpos, File::SeekFromBeginning);
return _af_units[i].fileFormat;
}
}
f->seek(curpos, File::SeekFromBeginning);
if (implemented != NULL)
*implemented = false;
return AF_FILE_UNKNOWN;
}
int afIdentifyFD (int fd)
{
fd = dup(fd);
File *f = File::create(fd, File::ReadAccess);
int result = _af_identify(f, NULL);
delete f;
return result;
}
int afIdentifyNamedFD (int fd, const char *filename, int *implemented)
{
fd = dup(fd);
File *f = File::create(fd, File::ReadAccess);
if (!f)
{
_af_error(AF_BAD_OPEN, "could not open file '%s'", filename);
return AF_FILE_UNKNOWN;
}
int result = _af_identify(f, implemented);
delete f;
return result;
}
AFfilehandle afOpenFD (int fd, const char *mode, AFfilesetup setup)
{
if (!mode)
{
_af_error(AF_BAD_ACCMODE, "null access mode");
return AF_NULL_FILEHANDLE;
}
int access;
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;
}
File *f = File::create(fd, access == _AF_READ_ACCESS ?
File::ReadAccess : File::WriteAccess);
AFfilehandle filehandle = NULL;
if (_afOpenFile(access, f, NULL, &filehandle, setup) != AF_SUCCEED)
{
delete f;
}
return filehandle;
}
AFfilehandle afOpenNamedFD (int fd, const char *mode, AFfilesetup setup,
const char *filename)
{
if (!mode)
{
_af_error(AF_BAD_ACCMODE, "null access mode");
return AF_NULL_FILEHANDLE;
}
int access;
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;
}
File *f = File::create(fd, access == _AF_READ_ACCESS ?
File::ReadAccess : File::WriteAccess);
AFfilehandle filehandle;
if (_afOpenFile(access, f, filename, &filehandle, setup) != AF_SUCCEED)
{
delete f;
}
return filehandle;
}
AFfilehandle afOpenFile (const char *filename, const char *mode, AFfilesetup setup)
{
if (!mode)
{
_af_error(AF_BAD_ACCMODE, "null access mode");
return AF_NULL_FILEHANDLE;
}
int access;
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;
}
File *f = File::open(filename,
access == _AF_READ_ACCESS ? File::ReadAccess : File::WriteAccess);
if (!f)
{
_af_error(AF_BAD_OPEN, "could not open file '%s'", filename);
return AF_NULL_FILEHANDLE;
}
AFfilehandle filehandle;
if (_afOpenFile(access, f, filename, &filehandle, setup) != AF_SUCCEED)
{
delete f;
}
return filehandle;
}
AFfilehandle afOpenVirtualFile (AFvirtualfile *vf, const char *mode,
AFfilesetup setup)
{
if (!vf)
{
_af_error(AF_BAD_OPEN, "null virtual file");
return AF_NULL_FILEHANDLE;
}
if (!mode)
{
_af_error(AF_BAD_ACCMODE, "null access mode");
return AF_NULL_FILEHANDLE;
}
int access;
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;
}
File *f = File::create(vf,
access == _AF_READ_ACCESS ? File::ReadAccess : File::WriteAccess);
if (!f)
{
_af_error(AF_BAD_OPEN, "could not open virtual file");
return AF_NULL_FILEHANDLE;
}
AFfilehandle filehandle;
if (_afOpenFile(access, f, NULL, &filehandle, setup) != AF_SUCCEED)
{
delete f;
}
return filehandle;
}
static status _afOpenFile (int access, File *f, const char *filename,
AFfilehandle *file, AFfilesetup filesetup)
{
int fileFormat = AF_FILE_UNKNOWN;
int implemented = true;
int userSampleFormat = 0;
double userSampleRate = 0.0;
PCMInfo userPCM = {0};
bool userFormatSet = false;
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(f, &implemented);
}
}
else if (filesetup == AF_NULL_FILESETUP)
fileFormat = _af_identify(f, &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;
}
const char *formatName = _af_units[fileFormat].name;
if (!implemented)
{
_af_error(AF_BAD_NOT_IMPLEMENTED,
"%s format not currently supported", formatName);
}
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 = true;
if ((completesetup = _af_units[fileFormat].completesetup(filesetup)) == NULL)
return AF_FAIL;
}
filehandle = _AFfilehandle::create(fileFormat);
if (!filehandle)
{
if (completesetup)
afFreeFileSetup(completesetup);
return AF_FAIL;
}
filehandle->m_fh = f;
filehandle->m_access = access;
filehandle->m_seekok = f->canSeek();
if (filename != NULL)
filehandle->m_fileName = _af_strdup(filename);
else
filehandle->m_fileName = NULL;
filehandle->m_fileFormat = fileFormat;
status result = access == _AF_READ_ACCESS ?
filehandle->readInit(completesetup) :
filehandle->writeInit(completesetup);
if (result != AF_SUCCEED)
{
delete filehandle;
filehandle = AF_NULL_FILEHANDLE;
if (completesetup)
afFreeFileSetup(completesetup);
return AF_FAIL;
}
if (completesetup)
afFreeFileSetup(completesetup);
for (int t=0; t<filehandle->m_trackCount; t++)
{
Track *track = &filehandle->m_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
track->ms = new ModuleState();
if (track->ms->init(filehandle, track) == AF_FAIL)
{
delete filehandle;
return AF_FAIL;
}
}
*file = filehandle;
return AF_SUCCEED;
}
int afSyncFile (AFfilehandle handle)
{
if (!_af_filehandle_ok(handle))
return -1;
if (handle->m_access == _AF_WRITE_ACCESS)
{
for (int trackno = 0; trackno < handle->m_trackCount; trackno++)
{
Track *track = &handle->m_tracks[trackno];
if (track->ms->isDirty() && track->ms->setup(handle, track) == AF_FAIL)
return -1;
if (track->ms->sync(handle, track) != AF_SUCCEED)
return -1;
}
if (handle->update() != AF_SUCCEED)
return AF_FAIL;
}
else if (handle->m_access == _AF_READ_ACCESS)
{
}
else
{
_af_error(AF_BAD_ACCMODE, "unrecognized access mode %d",
handle->m_access);
return AF_FAIL;
}
return AF_SUCCEED;
}
int afCloseFile (AFfilehandle file)
{
int err;
if (!_af_filehandle_ok(file))
return -1;
afSyncFile(file);
err = file->m_fh->close();
if (err < 0)
_af_error(AF_BAD_CLOSE, "close returned %d", err);
delete file->m_fh;
delete file;
return 0;
}
extern const PCMInfo _af_default_signed_integer_pcm_mappings[] =
{
{0, 0, 0, 0},
{SLOPE_INT8, 0, MIN_INT8, MAX_INT8},
{SLOPE_INT16, 0, MIN_INT16, MAX_INT16},
{SLOPE_INT24, 0, MIN_INT24, MAX_INT24},
{SLOPE_INT32, 0, MIN_INT32, MAX_INT32}
};
extern const PCMInfo _af_default_unsigned_integer_pcm_mappings[] =
{
{0, 0, 0, 0},
{SLOPE_INT8, INTERCEPT_U_INT8, 0, MAX_U_INT8},
{SLOPE_INT16, INTERCEPT_U_INT16, 0, MAX_U_INT16},
{SLOPE_INT24, INTERCEPT_U_INT24, 0, MAX_U_INT24},
{SLOPE_INT32, INTERCEPT_U_INT32, 0, MAX_U_INT32}
};
extern const PCMInfo _af_default_float_pcm_mapping =
{1, 0, 0, 0};
extern const PCMInfo _af_default_double_pcm_mapping =
{1, 0, 0, 0};
void afInitPCMMapping (AFfilesetup setup, int trackid,
double slope, double intercept, double minClip, double maxClip)
{
if (!_af_filesetup_ok(setup))
return;
TrackSetup *track = setup->getTrack(trackid);
if (!track)
return;
track->f.pcm.slope = slope;
track->f.pcm.intercept = intercept;
track->f.pcm.minClip = minClip;
track->f.pcm.maxClip = maxClip;
}
int afSetVirtualPCMMapping (AFfilehandle file, int trackid,
double slope, double intercept, double minClip, double maxClip)
{
if (!_af_filehandle_ok(file))
return -1;
Track *track = file->getTrack(trackid);
if (!track)
return -1;
track->v.pcm.slope = slope;
track->v.pcm.intercept = intercept;
track->v.pcm.minClip = minClip;
track->v.pcm.maxClip = maxClip;
track->ms->setDirty();
return 0;
}
int afSetTrackPCMMapping (AFfilehandle file, int trackid,
double slope, double intercept, double minClip, double maxClip)
{
if (!_af_filehandle_ok(file))
return -1;
Track *track = file->getTrack(trackid);
if (!track)
return -1;
track->f.pcm.slope = slope;
track->f.pcm.intercept = intercept;
track->f.pcm.minClip = minClip;
track->f.pcm.maxClip = maxClip;
track->ms->setDirty();
return 0;
}
void afGetPCMMapping (AFfilehandle file, int trackid,
double *slope, double *intercept, double *minClip, double *maxClip)
{
if (!_af_filehandle_ok(file))
return;
Track *track = file->getTrack(trackid);
if (!track)
return;
if (slope)
*slope = track->f.pcm.slope;
if (intercept)
*intercept = track->f.pcm.intercept;
if (minClip)
*minClip = track->f.pcm.minClip;
if (maxClip)
*maxClip = track->f.pcm.maxClip;
}
void afGetVirtualPCMMapping (AFfilehandle file, int trackid,
double *slope, double *intercept, double *minClip, double *maxClip)
{
if (!_af_filehandle_ok(file))
return;
Track *track = file->getTrack(trackid);
if (!track)
return;
if (slope)
*slope = track->v.pcm.slope;
if (intercept)
*intercept = track->v.pcm.intercept;
if (minClip)
*minClip = track->v.pcm.minClip;
if (maxClip)
*maxClip = track->v.pcm.maxClip;
}
#include <assert.h>
#include <stdlib.h>
AUpvlist _afQueryFileFormat (int arg1, int arg2, int arg3, int arg4);
AUpvlist _afQueryInstrument (int arg1, int arg2, int arg3, int arg4);
AUpvlist _afQueryInstrumentParameter (int arg1, int arg2, int arg3, int arg4);
AUpvlist _afQueryLoop (int arg1, int arg2, int arg3, int arg4);
AUpvlist _afQueryMarker (int arg1, int arg2, int arg3, int arg4);
AUpvlist _afQueryMiscellaneous (int arg1, int arg2, int arg3, int arg4);
AUpvlist _afQueryCompression (int arg1, int arg2, int arg3, int arg4);
AUpvlist _afQueryCompressionParameter (int arg1, int arg2, int arg3, int arg4);
AUpvlist afQuery (int querytype, int arg1, int arg2, int arg3, int arg4)
{
switch (querytype)
{
case AF_QUERYTYPE_INST:
return _afQueryInstrument(arg1, arg2, arg3, arg4);
case AF_QUERYTYPE_INSTPARAM:
return _afQueryInstrumentParameter(arg1, arg2, arg3, arg4);
case AF_QUERYTYPE_LOOP:
return _afQueryLoop(arg1, arg2, arg3, arg4);
case AF_QUERYTYPE_FILEFMT:
return _afQueryFileFormat(arg1, arg2, arg3, arg4);
case AF_QUERYTYPE_COMPRESSION:
return _afQueryCompression(arg1, arg2, arg3, arg4);
case AF_QUERYTYPE_COMPRESSIONPARAM:
return AU_NULL_PVLIST;
case AF_QUERYTYPE_MISC:
return AU_NULL_PVLIST;
case AF_QUERYTYPE_MARK:
return _afQueryMarker(arg1, arg2, arg3, arg4);
}
_af_error(AF_BAD_QUERYTYPE, "bad query type");
return AU_NULL_PVLIST;
}
AUpvlist _afQueryFileFormat (int arg1, int arg2, int arg3, int arg4)
{
switch (arg1)
{
case AF_QUERY_ID_COUNT:
{
int count = 0, idx;
for (idx = 0; idx < _AF_NUM_UNITS; idx++)
if (_af_units[idx].implemented)
count++;
return _af_pv_long(count);
}
break;
case AF_QUERY_IDS:
{
int count = 0, idx;
int *buffer;
buffer = (int *) _af_calloc(_AF_NUM_UNITS, sizeof (int));
if (buffer == NULL)
return AU_NULL_PVLIST;
for (idx = 0; idx < _AF_NUM_UNITS; idx++)
if (_af_units[idx].implemented)
buffer[count++] = idx;
if (count == 0)
{
free(buffer);
return AU_NULL_PVLIST;
}
return _af_pv_pointer(buffer);
}
break;
case AF_QUERY_LABEL:
if (arg2 < 0 || arg2 >= _AF_NUM_UNITS)
return AU_NULL_PVLIST;
return _af_pv_pointer(const_cast<char *>(_af_units[arg2].label));
case AF_QUERY_NAME:
if (arg2 < 0 || arg2 >= _AF_NUM_UNITS)
return AU_NULL_PVLIST;
return _af_pv_pointer(const_cast<char *>(_af_units[arg2].name));
case AF_QUERY_DESC:
if (arg2 < 0 || arg2 >= _AF_NUM_UNITS)
return AU_NULL_PVLIST;
return _af_pv_pointer(const_cast<char *>(_af_units[arg2].description));
case AF_QUERY_IMPLEMENTED:
if (arg2 < 0 || arg2 >= _AF_NUM_UNITS)
return _af_pv_long(0);
return _af_pv_long(_af_units[arg2].implemented);
case AF_QUERY_SAMPLE_FORMATS:
if (arg3 < 0 || arg3 >= _AF_NUM_UNITS)
return AU_NULL_PVLIST;
switch (arg2)
{
case AF_QUERY_DEFAULT:
return _af_pv_long(_af_units[arg3].defaultSampleFormat);
default:
break;
}
break;
case AF_QUERY_SAMPLE_SIZES:
if (arg3 < 0 || arg3 >= _AF_NUM_UNITS)
return AU_NULL_PVLIST;
switch (arg2)
{
case AF_QUERY_DEFAULT:
return _af_pv_long(_af_units[arg3].defaultSampleWidth);
default:
break;
}
break;
case AF_QUERY_COMPRESSION_TYPES:
{
int idx, count;
int *buffer;
if (arg3 < 0 || arg3 >= _AF_NUM_UNITS)
{
_af_error(AF_BAD_QUERY,
"unrecognized file format %d", arg3);
return AU_NULL_PVLIST;
}
switch (arg2)
{
case AF_QUERY_VALUE_COUNT:
count = _af_units[arg3].compressionTypeCount;
return _af_pv_long(count);
case AF_QUERY_VALUES:
count = _af_units[arg3].compressionTypeCount;
if (count == 0)
return AU_NULL_PVLIST;
buffer = (int *) _af_calloc(count, sizeof (int));
if (buffer == NULL)
return AU_NULL_PVLIST;
for (idx = 0; idx < count; idx++)
{
buffer[idx] = _af_units[arg3].compressionTypes[idx];
}
return _af_pv_pointer(buffer);
}
}
break;
}
_af_error(AF_BAD_QUERY, "bad query selector");
return AU_NULL_PVLIST;
}
long afQueryLong (int querytype, int arg1, int arg2, int arg3, int arg4)
{
AUpvlist list;
int type;
long value;
list = afQuery(querytype, arg1, arg2, arg3, arg4);
if (list == AU_NULL_PVLIST)
return -1;
AUpvgetvaltype(list, 0, &type);
if (type != AU_PVTYPE_LONG)
return -1;
AUpvgetval(list, 0, &value);
AUpvfree(list);
return value;
}
double afQueryDouble (int querytype, int arg1, int arg2, int arg3, int arg4)
{
AUpvlist list;
int type;
double value;
list = afQuery(querytype, arg1, arg2, arg3, arg4);
if (list == AU_NULL_PVLIST)
return -1;
AUpvgetvaltype(list, 0, &type);
if (type != AU_PVTYPE_DOUBLE)
return -1;
AUpvgetval(list, 0, &value);
AUpvfree(list);
return value;
}
void *afQueryPointer (int querytype, int arg1, int arg2, int arg3, int arg4)
{
AUpvlist list;
int type;
void *value;
list = afQuery(querytype, arg1, arg2, arg3, arg4);
if (list == AU_NULL_PVLIST)
return NULL;
AUpvgetvaltype(list, 0, &type);
if (type != AU_PVTYPE_PTR)
return NULL;
AUpvgetval(list, 0, &value);
AUpvfree(list);
return value;
}
AUpvlist _afQueryInstrumentParameter (int arg1, int arg2, int arg3, int arg4)
{
switch (arg1)
{
case AF_QUERY_SUPPORTED:
if (arg2 < 0 || arg2 >= _AF_NUM_UNITS)
return AU_NULL_PVLIST;
return _af_pv_long(_af_units[arg2].instrumentParameterCount != 0);
case AF_QUERY_ID_COUNT:
if (arg2 < 0 || arg2 >= _AF_NUM_UNITS)
return AU_NULL_PVLIST;
return _af_pv_long(_af_units[arg2].instrumentParameterCount);
case AF_QUERY_IDS:
{
int count;
int *buffer;
if (arg2 < 0 || arg2 >= _AF_NUM_UNITS)
return AU_NULL_PVLIST;
count = _af_units[arg2].instrumentParameterCount;
if (count == 0)
return AU_NULL_PVLIST;
buffer = (int *) _af_calloc(count, sizeof (int));
if (buffer == NULL)
return AU_NULL_PVLIST;
for (int i=0; i<count; i++)
buffer[i] = _af_units[arg2].instrumentParameters[i].id;
return _af_pv_pointer(buffer);
}
break;
case AF_QUERY_TYPE:
{
int idx;
if (arg2 < 0 || arg2 >= _AF_NUM_UNITS)
return AU_NULL_PVLIST;
idx = _af_instparam_index_from_id(arg2, arg3);
if (idx<0)
return AU_NULL_PVLIST;
return _af_pv_long(_af_units[arg2].instrumentParameters[idx].type);
}
case AF_QUERY_NAME:
{
int idx;
if (arg2 < 0 || arg2 >= _AF_NUM_UNITS)
return AU_NULL_PVLIST;
idx = _af_instparam_index_from_id(arg2, arg3);
if (idx < 0)
return AU_NULL_PVLIST;
return _af_pv_pointer(const_cast<char *>(_af_units[arg2].instrumentParameters[idx].name));
}
case AF_QUERY_DEFAULT:
{
int idx;
if (arg2 < 0 || arg2 >= _AF_NUM_UNITS)
return AU_NULL_PVLIST;
idx = _af_instparam_index_from_id(arg2, arg3);
if (idx >= 0)
{
AUpvlist ret = AUpvnew(1);
AUpvsetparam(ret, 0, _af_units[arg2].instrumentParameters[idx].id);
AUpvsetvaltype(ret, 0, _af_units[arg2].instrumentParameters[idx].type);
AUpvsetval(ret, 0, const_cast<AFPVu *>(&_af_units[arg2].instrumentParameters[idx].defaultValue));
return ret;
}
return AU_NULL_PVLIST;
}
}
_af_error(AF_BAD_QUERY, "bad query selector");
return AU_NULL_PVLIST;
}
AUpvlist _afQueryLoop (int arg1, int arg2, int arg3, int arg4)
{
if (arg2 < 0 || arg2 >= _AF_NUM_UNITS)
return AU_NULL_PVLIST;
switch (arg1)
{
case AF_QUERY_SUPPORTED:
return _af_pv_long(_af_units[arg2].loopPerInstrumentCount != 0);
case AF_QUERY_MAX_NUMBER:
return _af_pv_long(_af_units[arg2].loopPerInstrumentCount);
}
_af_error(AF_BAD_QUERY, "bad query selector");
return AU_NULL_PVLIST;
}
AUpvlist _afQueryInstrument (int arg1, int arg2, int arg3, int arg4)
{
switch (arg1)
{
case AF_QUERY_SUPPORTED:
if (arg2 < 0 || arg2 >= _AF_NUM_UNITS)
return AU_NULL_PVLIST;
return _af_pv_long(_af_units[arg2].instrumentCount != 0);
case AF_QUERY_MAX_NUMBER:
if (arg2 < 0 || arg2 >= _AF_NUM_UNITS)
return AU_NULL_PVLIST;
return _af_pv_long(_af_units[arg2].instrumentCount);
}
_af_error(AF_BAD_QUERY, "bad query selector");
return AU_NULL_PVLIST;
}
AUpvlist _afQueryMiscellaneous (int arg1, int arg2, int arg3, int arg4)
{
_af_error(AF_BAD_NOT_IMPLEMENTED, "not implemented yet");
return AU_NULL_PVLIST;
}
AUpvlist _afQueryMarker (int arg1, int arg2, int arg3, int arg4)
{
switch (arg1)
{
case AF_QUERY_SUPPORTED:
return _af_pv_long(_af_units[arg2].markerCount != 0);
case AF_QUERY_MAX_NUMBER:
return _af_pv_long(_af_units[arg2].markerCount);
}
_af_error(AF_BAD_QUERY, "bad query selector");
return AU_NULL_PVLIST;
}
AUpvlist _afQueryCompression (int arg1, int arg2, int arg3, int arg4)
{
const CompressionUnit *unit = NULL;
switch (arg1)
{
case AF_QUERY_ID_COUNT:
{
int count = 0;
for (int i = 0; i < _AF_NUM_COMPRESSION; i++)
if (_af_compression[i].implemented)
count++;
return _af_pv_long(count);
}
case AF_QUERY_IDS:
{
int *buf = (int *) _af_calloc(_AF_NUM_COMPRESSION, sizeof (int));
if (!buf)
return AU_NULL_PVLIST;
int count = 0;
for (int i = 0; i < _AF_NUM_COMPRESSION; i++)
{
if (_af_compression[i].implemented)
buf[count++] = _af_compression[i].compressionID;
}
return _af_pv_pointer(buf);
}
case AF_QUERY_IMPLEMENTED:
unit = _af_compression_unit_from_id(arg2);
if (!unit)
return _af_pv_long(0);
return _af_pv_long(unit->implemented);
case AF_QUERY_NATIVE_SAMPFMT:
unit = _af_compression_unit_from_id(arg2);
if (!unit)
return AU_NULL_PVLIST;
return _af_pv_long(unit->nativeSampleFormat);
case AF_QUERY_NATIVE_SAMPWIDTH:
unit = _af_compression_unit_from_id(arg2);
if (!unit)
return AU_NULL_PVLIST;
return _af_pv_long(unit->nativeSampleWidth);
case AF_QUERY_LABEL:
unit = _af_compression_unit_from_id(arg2);
if (!unit)
return AU_NULL_PVLIST;
return _af_pv_pointer(const_cast<char *>(unit->label));
case AF_QUERY_NAME:
unit = _af_compression_unit_from_id(arg2);
if (!unit)
return AU_NULL_PVLIST;
return _af_pv_pointer(const_cast<char *>(unit->shortname));
case AF_QUERY_DESC:
unit = _af_compression_unit_from_id(arg2);
if (!unit)
return AU_NULL_PVLIST;
return _af_pv_pointer(const_cast<char *>(unit->name));
}
_af_error(AF_BAD_QUERY, "unrecognized query selector %d\n", arg1);
return AU_NULL_PVLIST;
}
const Unit _af_units[_AF_NUM_UNITS] =
{
{
AF_FILE_RAWDATA,
"Raw Data", "Raw Sound Data", "raw",
true,
&RawFile::completeSetup,
&RawFile::recognize,
AF_SAMPFMT_TWOSCOMP, 16,
_AF_RAW_NUM_COMPTYPES,
_af_raw_compression_types,
0,
0,
0,
0, NULL,
},
{
AF_FILE_AIFFC,
"AIFF-C", "AIFF-C File Format", "aifc",
true,
AIFFFile::completeSetup,
AIFFFile::recognizeAIFFC,
AF_SAMPFMT_TWOSCOMP, 16,
_AF_AIFFC_NUM_COMPTYPES,
_af_aiffc_compression_types,
65535,
1,
2,
_AF_AIFF_NUM_INSTPARAMS,
_af_aiff_inst_params
},
{
AF_FILE_AIFF,
"AIFF", "Audio Interchange File Format", "aiff",
true,
AIFFFile::completeSetup,
AIFFFile::recognizeAIFF,
AF_SAMPFMT_TWOSCOMP, 16,
0,
NULL,
65535,
1,
2,
_AF_AIFF_NUM_INSTPARAMS,
_af_aiff_inst_params
},
{
AF_FILE_WAVE,
"MS RIFF WAVE", "Microsoft RIFF WAVE Format", "wave",
true,
WAVEFile::completeSetup,
WAVEFile::recognize,
AF_SAMPFMT_TWOSCOMP, 16,
_AF_WAVE_NUM_COMPTYPES,
_af_wave_compression_types,
AF_NUM_UNLIMITED,
1,
AF_NUM_UNLIMITED,
_AF_WAVE_NUM_INSTPARAMS,
_af_wave_inst_params
},
};
const CompressionUnit _af_compression[_AF_NUM_COMPRESSION] =
{
{
AF_COMPRESSION_NONE,
true,
"none",
"none",
"not compressed",
1.0,
AF_SAMPFMT_TWOSCOMP, 16,
false,
false,
_af_pcm_format_ok,
_AFpcminitcompress, _AFpcminitdecompress
},
{
AF_COMPRESSION_G711_ULAW,
true,
"ulaw",
"CCITT G.711 u-law",
"CCITT G.711 u-law",
2.0,
AF_SAMPFMT_TWOSCOMP, 16,
false,
false,
_af_g711_format_ok,
_AFg711initcompress, _AFg711initdecompress
},
{
AF_COMPRESSION_G711_ALAW,
true,
"alaw",
"CCITT G.711 A-law",
"CCITT G.711 A-law",
2.0,
AF_SAMPFMT_TWOSCOMP, 16,
false,
false,
_af_g711_format_ok,
_AFg711initcompress, _AFg711initdecompress
},
{
AF_COMPRESSION_MS_ADPCM,
true,
"msadpcm",
"MS ADPCM",
"Microsoft ADPCM",
4.0,
AF_SAMPFMT_TWOSCOMP, 16,
true,
false,
_af_ms_adpcm_format_ok,
_af_ms_adpcm_init_compress, _af_ms_adpcm_init_decompress
},
};
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
bool _af_filesetup_ok (AFfilesetup setup)
{
if (setup == AF_NULL_FILESETUP)
{
_af_error(AF_BAD_FILESETUP, "null file setup");
return false;
}
if (setup->valid != _AF_VALID_FILESETUP)
{
_af_error(AF_BAD_FILESETUP, "invalid file setup");
return false;
}
return true;
}
bool _af_filehandle_ok (AFfilehandle file)
{
if (file == AF_NULL_FILEHANDLE)
{
_af_error(AF_BAD_FILEHANDLE, "null file handle");
return false;
}
if (file->m_valid != _AF_VALID_FILEHANDLE)
{
_af_error(AF_BAD_FILEHANDLE, "invalid file handle");
return false;
}
return true;
}
void *_af_malloc (size_t size)
{
void *p;
if (size <= 0)
{
_af_error(AF_BAD_MALLOC, "bad memory allocation size request %zd", size);
return NULL;
}
p = malloc(size);
#ifdef AF_DEBUG
if (p)
memset(p, 0xff, size);
#endif
if (p == NULL)
{
_af_error(AF_BAD_MALLOC, "allocation of %zd bytes failed", size);
return NULL;
}
return p;
}
char *_af_strdup (const char *s)
{
char *p = (char *) malloc(strlen(s) + 1);
if (p)
strcpy(p, s);
return p;
}
void *_af_realloc (void *p, size_t size)
{
if (size <= 0)
{
_af_error(AF_BAD_MALLOC, "bad memory allocation size request %zd", size);
return NULL;
}
p = realloc(p, size);
if (p == NULL)
{
_af_error(AF_BAD_MALLOC, "allocation of %zd bytes failed", size);
return NULL;
}
return p;
}
void *_af_calloc (size_t nmemb, size_t size)
{
void *p;
if (nmemb <= 0 || size <= 0)
{
_af_error(AF_BAD_MALLOC, "bad memory allocation size request "
"%zd elements of %zd bytes each", nmemb, size);
return NULL;
}
p = calloc(nmemb, size);
if (p == NULL)
{
_af_error(AF_BAD_MALLOC, "allocation of %zd bytes failed",
nmemb*size);
return NULL;
}
return p;
}
AUpvlist _af_pv_long (long val)
{
AUpvlist ret = AUpvnew(1);
AUpvsetparam(ret, 0, 0);
AUpvsetvaltype(ret, 0, AU_PVTYPE_LONG);
AUpvsetval(ret, 0, &val);
return ret;
}
AUpvlist _af_pv_double (double val)
{
AUpvlist ret = AUpvnew(1);
AUpvsetparam(ret, 0, 0);
AUpvsetvaltype(ret, 0, AU_PVTYPE_DOUBLE);
AUpvsetval(ret, 0, &val);
return ret;
}
AUpvlist _af_pv_pointer (void *val)
{
AUpvlist ret = AUpvnew(1);
AUpvsetparam(ret, 0, 0);
AUpvsetvaltype(ret, 0, AU_PVTYPE_PTR);
AUpvsetval(ret, 0, &val);
return ret;
}
bool _af_pv_getlong (AUpvlist pvlist, int param, long *l)
{
for (int i=0; i<AUpvgetmaxitems(pvlist); i++)
{
int p, t;
AUpvgetparam(pvlist, i, &p);
if (p != param)
continue;
AUpvgetvaltype(pvlist, i, &t);
if (t != AU_PVTYPE_LONG)
return false;
AUpvgetval(pvlist, i, l);
return true;
}
return false;
}
bool _af_pv_getdouble (AUpvlist pvlist, int param, double *d)
{
for (int i=0; i<AUpvgetmaxitems(pvlist); i++)
{
int p, t;
AUpvgetparam(pvlist, i, &p);
if (p != param)
continue;
AUpvgetvaltype(pvlist, i, &t);
if (t != AU_PVTYPE_DOUBLE)
return false;
AUpvgetval(pvlist, i, d);
return true;
}
return false;
}
bool _af_pv_getptr (AUpvlist pvlist, int param, void **v)
{
for (int i=0; i<AUpvgetmaxitems(pvlist); i++)
{
int p, t;
AUpvgetparam(pvlist, i, &p);
if (p != param)
continue;
AUpvgetvaltype(pvlist, i, &t);
if (t != AU_PVTYPE_PTR)
return false;
AUpvgetval(pvlist, i, v);
return true;
}
return false;
}
int _af_format_sample_size_uncompressed (const AudioFormat *format, bool stretch3to4)
{
int size = 0;
switch (format->sampleFormat)
{
case AF_SAMPFMT_FLOAT:
size = sizeof (float);
break;
case AF_SAMPFMT_DOUBLE:
size = sizeof (double);
break;
default:
size = (int) (format->sampleWidth + 7) / 8;
if (format->compressionType == AF_COMPRESSION_NONE &&
size == 3 && stretch3to4)
size = 4;
break;
}
return size;
}
float _af_format_sample_size (const AudioFormat *fmt, bool stretch3to4)
{
const CompressionUnit *unit = _af_compression_unit_from_id(fmt->compressionType);
float squishFactor = unit->squishFactor;
return _af_format_sample_size_uncompressed(fmt, stretch3to4) /
squishFactor;
}
int _af_format_frame_size_uncompressed (const AudioFormat *fmt, bool stretch3to4)
{
return _af_format_sample_size_uncompressed(fmt, stretch3to4) *
fmt->channelCount;
}
float _af_format_frame_size (const AudioFormat *fmt, bool stretch3to4)
{
const CompressionUnit *unit = _af_compression_unit_from_id(fmt->compressionType);
float squishFactor = unit->squishFactor;
return _af_format_frame_size_uncompressed(fmt, stretch3to4) /
squishFactor;
}
status _af_set_sample_format (AudioFormat *f, int sampleFormat, int sampleWidth)
{
switch (sampleFormat)
{
case AF_SAMPFMT_UNSIGNED:
case AF_SAMPFMT_TWOSCOMP:
if (sampleWidth < 1 || sampleWidth > 32)
{
_af_error(AF_BAD_SAMPFMT,
"illegal sample width %d for integer data",
sampleWidth);
return AF_FAIL;
}
else
{
int bytes;
f->sampleFormat = sampleFormat;
f->sampleWidth = sampleWidth;
bytes = _af_format_sample_size_uncompressed(f, false);
if (sampleFormat == AF_SAMPFMT_TWOSCOMP)
f->pcm = _af_default_signed_integer_pcm_mappings[bytes];
else
f->pcm = _af_default_unsigned_integer_pcm_mappings[bytes];
}
break;
case AF_SAMPFMT_FLOAT:
f->sampleFormat = sampleFormat;
f->sampleWidth = 32;
f->pcm = _af_default_float_pcm_mapping;
break;
case AF_SAMPFMT_DOUBLE:
f->sampleFormat = sampleFormat;
f->sampleWidth = 64;
f->pcm = _af_default_double_pcm_mapping;
break;
default:
_af_error(AF_BAD_SAMPFMT, "unknown sample format %d",
sampleFormat);
return AF_FAIL;
}
return AF_SUCCEED;
}
bool _af_unique_ids (const int *ids, int nids, const char *idname, int iderr)
{
for (int i = 0; i < nids; i++)
{
for (int j = 0; j < i; j++)
{
if (ids[i] == ids[j])
{
_af_error(iderr, "nonunique %s id %d", idname, ids[i]);
return false;
}
}
}
return true;
}