mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-08-11 17:17:42 +03:00
Added FLAC read support.
--HG-- branch : dev
This commit is contained in:
@@ -14,3 +14,4 @@
|
||||
#define EE_BACKEND_SDL_ACTIVE
|
||||
#define EE_MBEDTLS
|
||||
#define DR_MP3_IMPLEMENTATION
|
||||
#define DR_FLAC_IMPLEMENTATION
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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>();
|
||||
|
||||
100
src/eepp/audio/soundfilereaderflac.cpp
Normal file
100
src/eepp/audio/soundfilereaderflac.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
|
||||
}}}
|
||||
75
src/eepp/audio/soundfilereaderflac.hpp
Normal file
75
src/eepp/audio/soundfilereaderflac.hpp
Normal 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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
5671
src/thirdparty/dr_libs/dr_flac.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user