sm64pc/tools/audiofile-0.3.6/libaudiofile/FLACFile.cpp

290 lines
7.2 KiB
C++

/*
Audio File Library
Copyright (C) 2013 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
*/
#include "config.h"
#include "FLACFile.h"
#include "File.h"
#include "Setup.h"
#include "Track.h"
#include "byteorder.h"
#include "util.h"
#include <string.h>
const int _af_flac_compression_types[_AF_FLAC_NUM_COMPTYPES] =
{
AF_COMPRESSION_FLAC
};
const _AFfilesetup flacDefaultFileSetup =
{
_AF_VALID_FILESETUP,
AF_FILE_FLAC,
true,
true,
true,
1, // trackCount
NULL, // tracks
0, // instrumentCount
NULL, // instruments
0, // miscellaneousCount
NULL // miscellaneous
};
bool FLACFile::recognize(File *file)
{
file->seek(0, File::SeekFromBeginning);
uint8_t buffer[4];
if (file->read(buffer, 4) != 4 || memcmp(buffer, "fLaC", 4) != 0)
return false;
return true;
}
FLACFile::FLACFile()
{
}
FLACFile::~FLACFile()
{
}
#if ENABLE(FLAC)
AFfilesetup FLACFile::completeSetup(AFfilesetup setup)
{
if (setup->trackSet && setup->trackCount != 1)
{
_af_error(AF_BAD_NUMTRACKS, "FLAC file must have 1 track");
return AF_NULL_FILESETUP;
}
TrackSetup *track = setup->getTrack();
if (track->sampleFormatSet &&
track->f.sampleFormat != AF_SAMPFMT_TWOSCOMP)
{
_af_error(AF_BAD_SAMPFMT,
"FLAC files support only signed integer audio data");
return AF_NULL_FILESETUP;
}
if (track->sampleWidthSet &&
track->f.sampleWidth != 16 && track->f.sampleWidth != 24)
{
_af_error(AF_BAD_WIDTH,
"FLAC files support only 16- or 24-bit audio data");
return AF_NULL_FILESETUP;
}
_af_set_sample_format(&track->f, AF_SAMPFMT_TWOSCOMP, track->f.sampleWidth);
track->f.byteOrder = _AF_BYTEORDER_NATIVE;
if (track->compressionSet &&
track->f.compressionType != AF_COMPRESSION_FLAC)
{
_af_error(AF_BAD_COMPTYPE, "Only FLAC compression supported in FLAC files");
return AF_NULL_FILESETUP;
}
track->f.compressionType = AF_COMPRESSION_FLAC;
if (track->markersSet && track->markerCount)
{
_af_error(AF_BAD_NOT_IMPLEMENTED, "FLAC does not yet support markers");
return AF_NULL_FILESETUP;
}
if (track->aesDataSet)
{
_af_error(AF_BAD_FILESETUP, "FLAC does not support AES data");
return AF_NULL_FILESETUP;
}
return _af_filesetup_copy(setup, &flacDefaultFileSetup, true);
}
status FLACFile::readInit(AFfilesetup)
{
m_fh->seek(0, File::SeekFromBeginning);
FLAC__StreamDecoder *decoder = FLAC__stream_decoder_new();
if (FLAC__stream_decoder_init_stream(decoder,
readCallback,
seekCallback,
tellCallback,
lengthCallback,
eofCallback,
writeCallback,
metadataCallback,
errorCallback,
this) != FLAC__STREAM_DECODER_INIT_STATUS_OK)
{
_af_error(AF_BAD_HEADER, "could not read FLAC file");
return AF_FAIL;
}
if (!FLAC__stream_decoder_process_until_end_of_metadata(decoder))
return AF_FAIL;
FLAC__uint64 position;
if (!FLAC__stream_decoder_get_decode_position(decoder, &position))
return AF_FAIL;
Track *track = getTrack();
if (track)
{
track->fpos_first_frame = static_cast<off_t>(position);
track->data_size = m_fh->length() - track->fpos_first_frame;
}
FLAC__stream_decoder_delete(decoder);
if (!track)
return AF_FAIL;
return AF_SUCCEED;
}
status FLACFile::writeInit(AFfilesetup setup)
{
if (initFromSetup(setup) == AF_FAIL)
return AF_FAIL;
return AF_SUCCEED;
}
status FLACFile::update()
{
return AF_SUCCEED;
}
void FLACFile::parseStreamInfo(const FLAC__StreamMetadata_StreamInfo &streamInfo)
{
Track *track = allocateTrack();
track->f.channelCount = streamInfo.channels;
track->f.sampleRate = streamInfo.sample_rate;
track->f.byteOrder = _AF_BYTEORDER_NATIVE;
track->f.framesPerPacket = 0;
track->f.bytesPerPacket = 0;
track->f.compressionType = AF_COMPRESSION_FLAC;
track->f.compressionParams = NULL;
_af_set_sample_format(&track->f, AF_SAMPFMT_TWOSCOMP, streamInfo.bits_per_sample);
track->totalfframes = streamInfo.total_samples;
}
FLAC__StreamDecoderReadStatus FLACFile::readCallback(const FLAC__StreamDecoder *, FLAC__byte buffer[], size_t *bytes, void *clientData)
{
FLACFile *flac = static_cast<FLACFile *>(clientData);
ssize_t result = flac->m_fh->read(buffer, *bytes);
if (result > 0)
{
*bytes = result;
return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
}
*bytes = 0;
return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
}
FLAC__StreamDecoderSeekStatus FLACFile::seekCallback(const FLAC__StreamDecoder *, FLAC__uint64 absoluteByteOffset, void *clientData)
{
FLACFile *flac = static_cast<FLACFile *>(clientData);
if (flac->m_fh->seek(static_cast<off_t>(absoluteByteOffset), File::SeekFromBeginning) < 0)
return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
}
FLAC__StreamDecoderTellStatus FLACFile::tellCallback(const FLAC__StreamDecoder *, FLAC__uint64 *absoluteByteOffset, void *clientData)
{
FLACFile *flac = static_cast<FLACFile *>(clientData);
off_t result = flac->m_fh->tell();
if (result < 0)
return FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
*absoluteByteOffset = static_cast<FLAC__uint64>(result);
return FLAC__STREAM_DECODER_TELL_STATUS_OK;
}
FLAC__StreamDecoderLengthStatus FLACFile::lengthCallback(const FLAC__StreamDecoder *, FLAC__uint64 *length, void *clientData)
{
FLACFile *flac = static_cast<FLACFile *>(clientData);
off_t result = flac->m_fh->length();
if (result < 0)
return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR;
*length = result;
return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
}
FLAC__bool FLACFile::eofCallback(const FLAC__StreamDecoder *, void *clientData)
{
FLACFile *flac = static_cast<FLACFile *>(clientData);
return flac->m_fh->tell() == flac->m_fh->length();
}
FLAC__StreamDecoderWriteStatus FLACFile::writeCallback(const FLAC__StreamDecoder *, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *clientData)
{
return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
}
void FLACFile::metadataCallback(const FLAC__StreamDecoder *, const FLAC__StreamMetadata *metadata, void *clientData)
{
FLACFile *flac = static_cast<FLACFile *>(clientData);
if (metadata->type == FLAC__METADATA_TYPE_STREAMINFO)
flac->parseStreamInfo(metadata->data.stream_info);
}
void FLACFile::errorCallback(const FLAC__StreamDecoder *, FLAC__StreamDecoderErrorStatus status, void *clientData)
{
_af_error(AF_BAD_FILEFMT, "error %d parsing FLAC file", status);
}
#else
AFfilesetup FLACFile::completeSetup(AFfilesetup)
{
_af_error(AF_BAD_FILEFMT, "FLAC is disabled");
return AF_NULL_FILESETUP;
}
status FLACFile::readInit(AFfilesetup)
{
_af_error(AF_BAD_FILEFMT, "FLAC is disabled");
return AF_FAIL;
}
status FLACFile::writeInit(AFfilesetup)
{
return AF_FAIL;
}
status FLACFile::update()
{
return AF_FAIL;
}
#endif