sm64pc/tools/audiofile-0.3.6/libaudiofile/AVR.cpp
2020-05-07 20:21:22 +02:00

346 lines
7.6 KiB
C++

/*
Audio File Library
Copyright (C) 2004, Michael Pruett <michael@68k.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301 USA
*/
/*
AVR.cpp
This file contains routines for reading and writing AVR (Audio
Visual Research) sound files.
*/
#include "config.h"
#include "AVR.h"
#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "File.h"
#include "Setup.h"
#include "Track.h"
#include "afinternal.h"
#include "audiofile.h"
#include "byteorder.h"
#include "util.h"
static const _AFfilesetup avrDefaultFileSetup =
{
_AF_VALID_FILESETUP, /* valid */
AF_FILE_AVR, /* fileFormat */
true, /* trackSet */
true, /* instrumentSet */
true, /* miscellaneousSet */
1, /* trackCount */
NULL, /* tracks */
0, /* instrumentCount */
NULL, /* instruments */
0, /* miscellaneousCount */
NULL /* miscellaneous */
};
AVRFile::AVRFile()
{
setFormatByteOrder(AF_BYTEORDER_BIGENDIAN);
}
bool AVRFile::recognize(File *fh)
{
uint32_t magic;
fh->seek(0, File::SeekFromBeginning);
if (fh->read(&magic, 4) != 4 || memcmp(&magic, "2BIT", 4) != 0)
return false;
return true;
}
status AVRFile::readInit(AFfilesetup setup)
{
uint32_t magic;
char name[8];
uint16_t mono, resolution, sign, loop, midi;
uint32_t rate, size, loopStart, loopEnd;
char reserved[26];
char user[64];
m_fh->seek(0, File::SeekFromBeginning);
if (m_fh->read(&magic, 4) != 4)
{
_af_error(AF_BAD_READ, "could not read AVR file header");
return AF_FAIL;
}
if (memcmp(&magic, "2BIT", 4) != 0)
{
_af_error(AF_BAD_FILEFMT, "file is not AVR format");
return AF_FAIL;
}
/* Read name. */
m_fh->read(name, 8);
readU16(&mono);
readU16(&resolution);
readU16(&sign);
readU16(&loop);
readU16(&midi);
readU32(&rate);
readU32(&size);
readU32(&loopStart);
readU32(&loopEnd);
m_fh->read(reserved, 26);
m_fh->read(user, 64);
Track *track = allocateTrack();
if (!track)
return AF_FAIL;
/* Use only low-order three bytes of sample rate. */
track->f.sampleRate = rate & 0xffffff;
if (sign == 0)
track->f.sampleFormat = AF_SAMPFMT_UNSIGNED;
else if (sign == 0xffff)
track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP;
else
{
_af_error(AF_BAD_SAMPFMT, "bad sample format in AVR file");
return AF_FAIL;
}
if (resolution != 8 && resolution != 16)
{
_af_error(AF_BAD_WIDTH, "bad sample width %d in AVR file",
resolution);
return AF_FAIL;
}
track->f.sampleWidth = resolution;
track->f.byteOrder = AF_BYTEORDER_BIGENDIAN;
if (mono == 0)
track->f.channelCount = 1;
else if (mono == 0xffff)
track->f.channelCount = 2;
else
{
_af_error(AF_BAD_CHANNELS,
"invalid number of channels in AVR file");
return AF_FAIL;
}
track->f.compressionType = AF_COMPRESSION_NONE;
track->f.framesPerPacket = 1;
track->f.computeBytesPerPacketPCM();
_af_set_sample_format(&track->f, track->f.sampleFormat, track->f.sampleWidth);
track->fpos_first_frame = m_fh->tell();
track->totalfframes = size;
track->data_size = track->totalfframes * track->f.bytesPerFrame(false);
track->nextfframe = 0;
track->fpos_next_frame = track->fpos_first_frame;
/* The file has been parsed successfully. */
return AF_SUCCEED;
}
AFfilesetup AVRFile::completeSetup(AFfilesetup setup)
{
if (setup->trackSet && setup->trackCount != 1)
{
_af_error(AF_BAD_NUMTRACKS, "AVR files must have exactly 1 track");
return AF_NULL_FILESETUP;
}
TrackSetup *track = setup->getTrack();
if (!track)
return AF_NULL_FILESETUP;
/* AVR allows only unsigned and two's complement integer data. */
if (track->f.sampleFormat != AF_SAMPFMT_UNSIGNED &&
track->f.sampleFormat != AF_SAMPFMT_TWOSCOMP)
{
_af_error(AF_BAD_FILEFMT, "AVR format does supports only unsigned and two's complement integer data");
return AF_NULL_FILESETUP;
}
/* For now we support only 8- and 16-bit samples. */
if (track->f.sampleWidth != 8 && track->f.sampleWidth != 16)
{
_af_error(AF_BAD_WIDTH, "invalid sample width %d for AVR file (only 8- and 16-bit sample widths are allowed)", track->f.sampleWidth);
return AF_NULL_FILESETUP;
}
/* AVR does not support compression. */
if (track->f.compressionType != AF_COMPRESSION_NONE)
{
_af_error(AF_BAD_NOT_IMPLEMENTED, "compression not supported for AVR files");
return AF_NULL_FILESETUP;
}
/* AVR audio data is big-endian. */
if (track->f.byteOrder != AF_BYTEORDER_BIGENDIAN)
{
if (track->byteOrderSet)
{
_af_error(AF_BAD_BYTEORDER,
"AVR format supports only big-endian data");
return AF_NULL_FILESETUP;
}
else
track->f.byteOrder = AF_BYTEORDER_BIGENDIAN;
}
if (track->aesDataSet)
{
_af_error(AF_BAD_FILESETUP, "AVR files do not support AES data");
return AF_NULL_FILESETUP;
}
if (track->markersSet && track->markerCount != 0)
{
_af_error(AF_BAD_FILESETUP, "AVR format does not support markers");
return AF_NULL_FILESETUP;
}
if (setup->instrumentSet && setup->instrumentCount != 0)
{
_af_error(AF_BAD_FILESETUP, "AVR format does not support instruments");
return AF_NULL_FILESETUP;
}
if (setup->miscellaneousSet && setup->miscellaneousCount != 0)
{
_af_error(AF_BAD_FILESETUP, "AVR format does not support miscellaneous data");
return AF_NULL_FILESETUP;
}
return _af_filesetup_copy(setup, &avrDefaultFileSetup, false);
}
status AVRFile::update()
{
uint32_t size, loopStart, loopEnd;
Track *track = getTrack();
/* Seek to the position of the size field. */
m_fh->seek(26, File::SeekFromBeginning);
size = track->totalfframes;
/* For the case of no loops, loopStart = 0 and loopEnd = size. */
loopStart = 0;
loopEnd = size;
writeU32(&size);
writeU32(&loopStart);
writeU32(&loopEnd);
return AF_SUCCEED;
}
static char *af_basename (char *filename)
{
char *base;
base = strrchr(filename, '/');
if (base == NULL)
return filename;
else
return base + 1;
}
status AVRFile::writeInit(AFfilesetup setup)
{
if (initFromSetup(setup) == AF_FAIL)
return AF_FAIL;
if (m_fh->seek(0, File::SeekFromBeginning) != 0)
{
_af_error(AF_BAD_LSEEK, "bad seek");
return AF_FAIL;
}
Track *track = getTrack();
char name[8];
uint16_t mono, resolution, sign, loop, midi;
uint32_t rate, size, loopStart, loopEnd;
char reserved[26];
char user[64];
m_fh->write("2BIT", 4);
memset(name, 0, 8);
if (m_fileName != NULL)
strncpy(name, af_basename(m_fileName), 8);
m_fh->write(name, 8);
if (track->f.channelCount == 1)
mono = 0x0;
else
mono = 0xffff;
writeU16(&mono);
resolution = track->f.sampleWidth;
writeU16(&resolution);
if (track->f.sampleFormat == AF_SAMPFMT_UNSIGNED)
sign = 0x0;
else
sign = 0xffff;
writeU16(&sign);
/* We do not currently support loops. */
loop = 0;
writeU16(&loop);
midi = 0xffff;
writeU16(&midi);
rate = track->f.sampleRate;
/* Set the high-order byte of rate to 0xff. */
rate |= 0xff000000;
size = track->totalfframes;
loopStart = 0;
loopEnd = size;
writeU32(&rate);
writeU32(&size);
writeU32(&loopStart);
writeU32(&loopEnd);
memset(reserved, 0, 26);
m_fh->write(reserved, 26);
memset(user, 0, 64);
m_fh->write(user, 64);
if (track->fpos_first_frame == 0)
track->fpos_first_frame = m_fh->tell();
return AF_SUCCEED;
}