Added FLAC read support.

--HG--
branch : dev
This commit is contained in:
Martín Lucas Golini
2018-04-22 22:42:01 -03:00
parent 56129ca9b5
commit 0b17abb1d8
10 changed files with 5912 additions and 54 deletions

View File

@@ -14,3 +14,4 @@
#define EE_BACKEND_SDL_ACTIVE
#define EE_MBEDTLS
#define DR_MP3_IMPLEMENTATION
#define DR_FLAC_IMPLEMENTATION

View File

@@ -394,6 +394,8 @@
../../src/eepp/audio/soundfilefactory.cpp
../../src/eepp/audio/soundfileogg.cpp
../../src/eepp/audio/soundfileogg.hpp
../../src/eepp/audio/soundfilereaderflac.cpp
../../src/eepp/audio/soundfilereaderflac.hpp
../../src/eepp/audio/soundfilereadermp3.cpp
../../src/eepp/audio/soundfilereadermp3.hpp
../../src/eepp/audio/soundfilereaderogg.cpp

View File

@@ -51,11 +51,11 @@ static int frame_length(Mp3Info::Header *header) {
Mp3Info::Mp3Info( IOStream& stream ) :
mStream( stream ),
mValidInfo( false )
mValidMp3( false )
{
memset(&mInfo,0,sizeof(Info));
fetchInfo();
mValidMp3 = fetchInfo();
}
Mp3Info::Info Mp3Info::getInfo() {
@@ -70,50 +70,60 @@ int Mp3Info::getBitrate() {
return header_bitrate( &mInfo.header );
}
int Mp3Info::fetchInfo() {
int had_error = 0;
int frame_type[15]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
float seconds=0,total_rate=0;
int frames=0,frame_types=0,frames_so_far=0;
int vbr_median=-1;
bool Mp3Info::isValidMp3() const {
return mValidMp3;
}
bool Mp3Info::fetchInfo() {
bool isValid = true;
int frameType[15]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
float seconds=0,totalRate=0;
int frames=0,frameTypes=0,framesSoFar=0;
int vbrMedian=-1;
int bitrate;
int counter=0;
Header header;
mStream.seek(0);
mInfo.datasize = mStream.getSize();
if( getFirstHeader( 0L ) ) {
if ( getFirstHeader( 0L ) ) {
while( ( bitrate = getNextHeader() ) ) {
frame_type[15-bitrate]++;
frameType[15-bitrate]++;
frames++;
}
memcpy( &header, &(mInfo.header), sizeof(Header) );
for(counter=0;counter<15;counter++) {
if(frame_type[counter]) {
frame_types++;
if(frameType[counter]) {
frameTypes++;
header.bitrate=counter;
frames_so_far += frame_type[counter];
seconds += (float)(frame_length(&header)*frame_type[counter])/
framesSoFar += frameType[counter];
seconds += (float)(frame_length(&header)*frameType[counter])/
(float)(header_bitrate(&header)*125);
total_rate += (float)((header_bitrate(&header))*frame_type[counter]);
if((vbr_median == -1) && (frames_so_far >= frames/2))
vbr_median=counter;
totalRate += (float)((header_bitrate(&header))*frameType[counter]);
if((vbrMedian == -1) && (framesSoFar >= frames/2))
vbrMedian=counter;
}
}
mInfo.seconds=(int)(seconds+0.5);
mInfo.header.bitrate=vbr_median;
mInfo.vbr_average=total_rate/(float)frames;
mInfo.header.bitrate=vbrMedian;
mInfo.vbr_average=totalRate/(float)frames;
mInfo.frames=frames;
if(frame_types > 1) {
if(frameTypes > 1) {
mInfo.vbr=1;
}
} else {
isValid = false;
}
return had_error;
mStream.seek(0);
return isValid;
}
int Mp3Info::getFirstHeader( long startpos ) {
@@ -121,7 +131,7 @@ int Mp3Info::getFirstHeader( long startpos ) {
unsigned char val;
int c;
Header h, h2;
long valid_start=0;
long validStart=0;
mStream.seek( startpos );
@@ -138,6 +148,11 @@ int Mp3Info::getFirstHeader( long startpos ) {
break;
}
// If read 1MB and not 255 found, asume error
if ( mStream.tell() >= EE_1MB ) {
return 0;
}
mStream.read( (char*)&val, 1 );
c = val;
}
@@ -145,7 +160,7 @@ int Mp3Info::getFirstHeader( long startpos ) {
if ( c == 255 ) {
if ( mStream.tell() > 0 && mStream.tell() != mStream.getSize() ) mStream.seek( mStream.tell() - 1 );
valid_start = mStream.tell();
validStart = mStream.tell();
if( ( l = getHeader( &h ) ) ) {
mStream.seek( mStream.tell() + l - FRAME_HEADER_SIZE );
@@ -157,7 +172,7 @@ int Mp3Info::getFirstHeader( long startpos ) {
}
if( k == MIN_CONSEC_GOOD_FRAMES ) {
mStream.seek( valid_start );
mStream.seek( validStart );
memcpy( &(mInfo.header), &h2, sizeof(Header) );
mInfo.header_isvalid=1;
return 1;
@@ -215,7 +230,7 @@ int Mp3Info::getHeader(Header *header) {
}
int Mp3Info::getNextHeader() {
int l=0,skip_bytes=0;
int l=0,skipBytes=0;
unsigned char val;
int c;
Header h;
@@ -233,7 +248,7 @@ int Mp3Info::getNextHeader() {
break;
}
skip_bytes++;
skipBytes++;
mStream.read( (char*)&val, 1 ); c = val;
}
@@ -241,16 +256,16 @@ int Mp3Info::getNextHeader() {
if ( mStream.tell() > 0 && mStream.tell() != mStream.getSize() ) mStream.seek( mStream.tell() - 1 );
if( ( l = getHeader(&h) ) ) {
if(skip_bytes) mInfo.badframes++;
if(skipBytes) mInfo.badframes++;
mStream.seek( mStream.tell() + l - FRAME_HEADER_SIZE );
return 15 - h.bitrate;
} else {
skip_bytes += FRAME_HEADER_SIZE;
skipBytes += FRAME_HEADER_SIZE;
}
} else {
if(skip_bytes) mInfo.badframes++;
if(skipBytes) mInfo.badframes++;
return 0;
}
}

View File

@@ -50,12 +50,14 @@ class Mp3Info {
int getFrequency();
int getBitrate();
bool isValidMp3() const;
protected:
IOStream& mStream;
Info mInfo;
bool mValidInfo;
bool mValidMp3;
int fetchInfo();
bool fetchInfo();
int getFirstHeader(long startpos);
int getHeader(Header * header);
int getNextHeader();

View File

@@ -4,6 +4,7 @@
#include <eepp/audio/soundfilereaderogg.hpp>
#include <eepp/audio/soundfilewriterogg.hpp>
#include <eepp/audio/soundfilereadermp3.hpp>
#include <eepp/audio/soundfilereaderflac.hpp>
#include <eepp/system/iostreamfile.hpp>
#include <eepp/system/iostreammemory.hpp>
#include <eepp/system/mutex.hpp>
@@ -23,6 +24,7 @@ namespace
if (!registered) {
EE::Audio::SoundFileFactory::registerReader<EE::Audio::Private::SoundFileReaderWav>();
EE::Audio::SoundFileFactory::registerReader<EE::Audio::Private::SoundFileReaderOgg>();
EE::Audio::SoundFileFactory::registerReader<EE::Audio::Private::SoundFileReaderFlac>();
EE::Audio::SoundFileFactory::registerReader<EE::Audio::Private::SoundFileReaderMp3>();
EE::Audio::SoundFileFactory::registerWriter<EE::Audio::Private::SoundFileWriterWav>();
EE::Audio::SoundFileFactory::registerWriter<EE::Audio::Private::SoundFileWriterOgg>();

View File

@@ -0,0 +1,100 @@
#include <eepp/audio/soundfilereaderflac.hpp>
#include <eepp/system/iostreammemory.hpp>
#include <eepp/core/core.hpp>
#include <algorithm>
#include <cctype>
#define DR_FLAC_IMPLEMENTATION
#include <dr_libs/dr_flac.h>
static size_t drflac_func_read(void* data, void* ptr, size_t size) {
IOStream* stream = static_cast<IOStream*>(data);
return static_cast<std::size_t>(stream->read((char*)ptr, size));
}
static drflac_bool32 drflac_func_seek(void* data, int offset, drflac_seek_origin whence) {
IOStream* stream = static_cast<IOStream*>(data);
switch (whence) {
case drflac_seek_origin_start:
break;
case drflac_seek_origin_current:
offset += stream->tell();
break;
}
stream->seek(offset);
return 1;
}
namespace EE { namespace Audio { namespace Private {
bool SoundFileReaderFlac::check(IOStream& stream) {
drflac * flac = drflac_open( drflac_func_read, drflac_func_seek, &stream );
if ( flac ) {
drflac_close( flac );
return true;
}
return false;
}
SoundFileReaderFlac::SoundFileReaderFlac() :
mChannelCount(0),
mFlac(NULL)
{}
SoundFileReaderFlac::~SoundFileReaderFlac() {
close();
}
bool SoundFileReaderFlac::open(IOStream& stream, Info& info) {
stream.seek(0);
if ( ( mFlac = drflac_open( drflac_func_read, drflac_func_seek, &stream ) ) ) {
info.channelCount = mChannelCount = mFlac->channels;
info.sampleRate = mFlac->sampleRate;
info.sampleCount = mFlac->totalSampleCount;
return true;
}
eeSAFE_FREE( mFlac );
return false;
}
void SoundFileReaderFlac::seek(Uint64 sampleOffset) {
if ( mFlac ) {
drflac_seek_to_sample( mFlac, sampleOffset );
}
}
Uint64 SoundFileReaderFlac::read(Int16* samples, Uint64 maxCount) {
eeASSERT(mFlac);
Uint64 count = 0;
while (count < maxCount) {
int samplesToRead = static_cast<int>(maxCount - count);
long samplesRead = drflac_read_s16( mFlac, samplesToRead, samples );
if (samplesRead > 0) {
count += samplesRead;
samples += samplesRead;
} else {
// error or end of file
break;
}
}
return count;
}
void SoundFileReaderFlac::close() {
if ( mFlac ) {
drflac_close( mFlac );
eeSAFE_FREE( mFlac );
mChannelCount = 0;
}
}
}}}

View File

@@ -0,0 +1,75 @@
#ifndef EE_AUDIO_SOUNDFILEREADERFLAC_HPP
#define EE_AUDIO_SOUNDFILEREADERFLAC_HPP
#include <eepp/audio/soundfilereader.hpp>
#include <dr_libs/dr_flac.h>
namespace EE { namespace Audio { namespace Private {
/// \brief Implementation of sound file reader that handles FLAC/Vorbis files
class SoundFileReaderFlac : public SoundFileReader {
public:
////////////////////////////////////////////////////////////
/// \brief Check if this reader can handle a file given by an input stream
///
/// \param stream Source stream to check
///
/// \return True if the file is supported by this reader
///
////////////////////////////////////////////////////////////
static bool check(IOStream& stream);
public:
SoundFileReaderFlac();
~SoundFileReaderFlac();
////////////////////////////////////////////////////////////
/// \brief Open a sound file for reading
///
/// \param stream Source stream to read from
/// \param info Structure to fill with the properties of the loaded sound
///
/// \return True if the file was successfully opened
///
////////////////////////////////////////////////////////////
virtual bool open(IOStream& stream, Info& info);
////////////////////////////////////////////////////////////
/// \brief Change the current read position to the given sample offset
///
/// The sample offset takes the channels into account.
/// If you have a time offset instead, you can easily find
/// the corresponding sample offset with the following formula:
/// `timeInSeconds * sampleRate * channelCount`
/// If the given offset exceeds to total number of samples,
/// this function must jump to the end of the file.
///
/// \param sampleOffset Index of the sample to jump to, relative to the beginning
///
////////////////////////////////////////////////////////////
virtual void seek(Uint64 sampleOffset);
////////////////////////////////////////////////////////////
/// \brief Read audio samples from the open file
///
/// \param samples Pointer to the sample array to fill
/// \param maxCount Maximum number of samples to read
///
/// \return Number of samples actually read (may be less than \a maxCount)
///
////////////////////////////////////////////////////////////
virtual Uint64 read(Int16* samples, Uint64 maxCount);
private:
void close();
unsigned int mChannelCount; // number of channels of the open sound file
drflac * mFlac;
};
}}}
#endif

View File

@@ -1,13 +1,11 @@
#include <eepp/audio/soundfilereadermp3.hpp>
#define DR_MP3_IMPLEMENTATION
#include <dr_libs/dr_mp3.h>
#include <eepp/audio/soundfilereadermp3.hpp>
#include <eepp/system/iostreammemory.hpp>
#include <eepp/core/core.hpp>
#include <algorithm>
#include <cctype>
#include <eepp/audio/mp3info.hpp>
#include <eepp/system/clock.hpp>
static size_t drmp3_func_read(void* data, void* ptr, size_t size) {
IOStream* stream = static_cast<IOStream*>(data);
@@ -30,15 +28,9 @@ static drmp3_bool32 drmp3_func_seek(void* data, int offset, drmp3_seek_origin wh
namespace EE { namespace Audio { namespace Private {
bool SoundFileReaderMp3::check(IOStream& stream) {
drmp3 mp3;
if ( drmp3_init( &mp3, drmp3_func_read, drmp3_func_seek, &stream, NULL ) ) {
drmp3_uninit( &mp3 );
return true;
}
return false;
Mp3Info info( stream );
stream.seek(0);
return info.isValidMp3();
}
SoundFileReaderMp3::SoundFileReaderMp3() :
@@ -51,17 +43,15 @@ SoundFileReaderMp3::~SoundFileReaderMp3() {
}
bool SoundFileReaderMp3::open(IOStream& stream, Info& info) {
mMp3 = eeMalloc(sizeof(drmp3));
drmp3 * mp3 = (drmp3*)mMp3;
mMp3 = (drmp3*)eeMalloc(sizeof(drmp3));
Mp3Info::Info mp3info = Mp3Info( stream ).getInfo();
stream.seek(0);
if ( drmp3_init( mp3, drmp3_func_read, drmp3_func_seek, &stream, NULL ) ) {
info.channelCount = mChannelCount = mp3->channels;
info.sampleRate = mp3->sampleRate;
if ( drmp3_init( mMp3, drmp3_func_read, drmp3_func_seek, &stream, NULL ) ) {
info.channelCount = mChannelCount = mMp3->channels;
info.sampleRate = mMp3->sampleRate;
info.sampleCount = mp3info.frames * DRMP3_MAX_SAMPLES_PER_FRAME;
return true;
}
@@ -73,21 +63,20 @@ bool SoundFileReaderMp3::open(IOStream& stream, Info& info) {
void SoundFileReaderMp3::seek(Uint64 sampleOffset) {
if ( mMp3 ) {
drmp3_seek_to_frame( (drmp3*)mMp3, sampleOffset );
drmp3_seek_to_frame( mMp3, sampleOffset );
}
}
Uint64 SoundFileReaderMp3::read(Int16* samples, Uint64 maxCount) {
eeASSERT(mMp3);
drmp3 * mp3 = (drmp3*)mMp3;
Uint64 count = 0;
while (count < maxCount) {
int samplesToRead = static_cast<int>(maxCount - count);
int frames = samplesToRead / mChannelCount;
float rSamples[samplesToRead];
long framesRead = drmp3_read_f32( mp3, frames, rSamples );
long framesRead = drmp3_read_f32( mMp3, frames, rSamples );
if (framesRead > 0) {
long samplesRead = framesRead * mChannelCount;
@@ -111,7 +100,7 @@ Uint64 SoundFileReaderMp3::read(Int16* samples, Uint64 maxCount) {
void SoundFileReaderMp3::close() {
if ( mMp3 ) {
drmp3_uninit( (drmp3*)mMp3 );
drmp3_uninit( mMp3 );
eeSAFE_FREE( mMp3 );
mChannelCount = 0;
}

View File

@@ -2,6 +2,7 @@
#define EE_AUDIO_SOUNDFILEREADERMP3_HPP
#include <eepp/audio/soundfilereader.hpp>
#include <dr_libs/dr_mp3.h>
namespace EE { namespace Audio { namespace Private {
@@ -65,7 +66,7 @@ class SoundFileReaderMp3 : public SoundFileReader {
void close();
unsigned int mChannelCount; // number of channels of the open sound file
void * mMp3;
drmp3 * mMp3;
};
}}}

5671
src/thirdparty/dr_libs/dr_flac.h vendored Normal file

File diff suppressed because it is too large Load Diff