mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-26 14:01:45 +00:00
Add an mp3 decoder using libmpg123
Does not currently handle direct file sources
This commit is contained in:
parent
14618cbf30
commit
77b1febd0e
5 changed files with 296 additions and 6 deletions
28
FindMPG123.cmake
Normal file
28
FindMPG123.cmake
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
# - Find mpg123
|
||||||
|
# Find the native mpg123 includes and library
|
||||||
|
#
|
||||||
|
# MPG123_INCLUDE_DIR - where to find mpg123.h
|
||||||
|
# MPG123_LIBRARIES - List of libraries when using mpg123.
|
||||||
|
# MPG123_FOUND - True if mpg123 found.
|
||||||
|
|
||||||
|
IF(MPG123_INCLUDE_DIR AND MPG123_LIBRARIES)
|
||||||
|
# Already in cache, be silent
|
||||||
|
SET(MPG123_FIND_QUIETLY TRUE)
|
||||||
|
ENDIF(MPG123_INCLUDE_DIR AND MPG123_LIBRARIES)
|
||||||
|
|
||||||
|
FIND_PATH(MPG123_INCLUDE_DIR mpg123.h
|
||||||
|
PATHS "${MPG123_DIR}"
|
||||||
|
PATH_SUFFIXES include
|
||||||
|
)
|
||||||
|
|
||||||
|
FIND_LIBRARY(MPG123_LIBRARIES NAMES mpg123 mpg123-0
|
||||||
|
PATHS "${MPG123_DIR}"
|
||||||
|
PATH_SUFFIXES lib
|
||||||
|
)
|
||||||
|
|
||||||
|
MARK_AS_ADVANCED(MPG123_LIBRARIES MPG123_INCLUDE_DIR)
|
||||||
|
|
||||||
|
# handle the QUIETLY and REQUIRED arguments and set MPG123_FOUND to TRUE if
|
||||||
|
# all listed variables are TRUE
|
||||||
|
INCLUDE(FindPackageHandleStandardArgs)
|
||||||
|
FIND_PACKAGE_HANDLE_STANDARD_ARGS(MPG123 DEFAULT_MSG MPG123_LIBRARIES MPG123_INCLUDE_DIR)
|
|
@ -299,6 +299,10 @@ endif( NO_OPENAL )
|
||||||
|
|
||||||
find_package( SndFile )
|
find_package( SndFile )
|
||||||
|
|
||||||
|
# Search for libmpg123
|
||||||
|
|
||||||
|
find_package( MPG123 )
|
||||||
|
|
||||||
# Search for FluidSynth
|
# Search for FluidSynth
|
||||||
|
|
||||||
find_package( FluidSynth )
|
find_package( FluidSynth )
|
||||||
|
@ -553,7 +557,10 @@ if( SNDFILE_FOUND )
|
||||||
set( ZDOOM_LIBS ${ZDOOM_LIBS} "${SNDFILE_LIBRARIES}" )
|
set( ZDOOM_LIBS ${ZDOOM_LIBS} "${SNDFILE_LIBRARIES}" )
|
||||||
include_directories( "${SNDFILE_INCLUDE_DIRS}" )
|
include_directories( "${SNDFILE_INCLUDE_DIRS}" )
|
||||||
endif( SNDFILE_FOUND )
|
endif( SNDFILE_FOUND )
|
||||||
|
if( MPG123_FOUND )
|
||||||
|
set( ZDOOM_LIBS ${ZDOOM_LIBS} "${MPG123_LIBRARIES}" )
|
||||||
|
include_directories( "${MPG123_INCLUDE_DIR}" )
|
||||||
|
endif( MPG123_FOUND )
|
||||||
if( NOT DYN_FLUIDSYNTH)
|
if( NOT DYN_FLUIDSYNTH)
|
||||||
if( FLUIDSYNTH_FOUND )
|
if( FLUIDSYNTH_FOUND )
|
||||||
set( ZDOOM_LIBS ${ZDOOM_LIBS} "${FLUIDSYNTH_LIBRARIES}" )
|
set( ZDOOM_LIBS ${ZDOOM_LIBS} "${FLUIDSYNTH_LIBRARIES}" )
|
||||||
|
@ -671,6 +678,9 @@ endif( SSE_MATTERS )
|
||||||
if( SNDFILE_FOUND )
|
if( SNDFILE_FOUND )
|
||||||
add_definitions( -DHAVE_SNDFILE )
|
add_definitions( -DHAVE_SNDFILE )
|
||||||
endif( SNDFILE_FOUND )
|
endif( SNDFILE_FOUND )
|
||||||
|
if( MPG123_FOUND )
|
||||||
|
add_definitions( -DHAVE_MPG123 )
|
||||||
|
endif( MPG123_FOUND )
|
||||||
if( DYN_FLUIDSYNTH )
|
if( DYN_FLUIDSYNTH )
|
||||||
add_definitions( -DHAVE_FLUIDSYNTH -DDYN_FLUIDSYNTH )
|
add_definitions( -DHAVE_FLUIDSYNTH -DDYN_FLUIDSYNTH )
|
||||||
elseif( FLUIDSYNTH_FOUND )
|
elseif( FLUIDSYNTH_FOUND )
|
||||||
|
@ -1034,6 +1044,7 @@ add_executable( zdoom WIN32
|
||||||
resourcefiles/file_directory.cpp
|
resourcefiles/file_directory.cpp
|
||||||
resourcefiles/resourcefile.cpp
|
resourcefiles/resourcefile.cpp
|
||||||
sfmt/SFMT.cpp
|
sfmt/SFMT.cpp
|
||||||
|
sound/audio_mpg123_decoder.cpp
|
||||||
sound/audio_sndfile_decoder.cpp
|
sound/audio_sndfile_decoder.cpp
|
||||||
sound/fmodsound.cpp
|
sound/fmodsound.cpp
|
||||||
sound/i_music.cpp
|
sound/i_music.cpp
|
||||||
|
|
167
src/sound/audio_mpg123_decoder.cpp
Normal file
167
src/sound/audio_mpg123_decoder.cpp
Normal file
|
@ -0,0 +1,167 @@
|
||||||
|
#include "i_soundinternal.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_MPG123
|
||||||
|
static bool inited = false;
|
||||||
|
|
||||||
|
|
||||||
|
off_t MPG123Decoder::mem_lseek(void *handle, off_t offset, int whence)
|
||||||
|
{
|
||||||
|
MPG123Decoder *self = reinterpret_cast<MPG123Decoder*>(handle);
|
||||||
|
|
||||||
|
switch(whence)
|
||||||
|
{
|
||||||
|
case SEEK_SET:
|
||||||
|
if(offset < 0 || offset > (off_t)self->MemLength)
|
||||||
|
return -1;
|
||||||
|
self->MemPos = offset;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SEEK_CUR:
|
||||||
|
if((offset > 0 && (off_t)(self->MemLength-self->MemPos) < offset) ||
|
||||||
|
(offset < 0 && (off_t)self->MemPos < -offset))
|
||||||
|
return -1;
|
||||||
|
self->MemPos += offset;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SEEK_END:
|
||||||
|
if(offset > 0 || -offset > (off_t)self->MemLength)
|
||||||
|
return -1;
|
||||||
|
self->MemPos = self->MemLength + offset;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return self->MemPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t MPG123Decoder::mem_read(void *handle, void *buffer, size_t bytes)
|
||||||
|
{
|
||||||
|
MPG123Decoder *self = reinterpret_cast<MPG123Decoder*>(handle);
|
||||||
|
|
||||||
|
if(bytes > self->MemLength-self->MemPos)
|
||||||
|
bytes = self->MemLength-self->MemPos;
|
||||||
|
|
||||||
|
memcpy(buffer, self->MemData+self->MemPos, bytes);
|
||||||
|
self->MemPos += bytes;
|
||||||
|
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
MPG123Decoder::~MPG123Decoder()
|
||||||
|
{
|
||||||
|
if(MPG123)
|
||||||
|
{
|
||||||
|
mpg123_close(MPG123);
|
||||||
|
mpg123_delete(MPG123);
|
||||||
|
MPG123 = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MPG123Decoder::open(const char *data, size_t length)
|
||||||
|
{
|
||||||
|
if(!inited)
|
||||||
|
{
|
||||||
|
if(mpg123_init() != MPG123_OK)
|
||||||
|
return false;
|
||||||
|
inited = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
MemData = data;
|
||||||
|
MemPos = 0;
|
||||||
|
MemLength = length;
|
||||||
|
|
||||||
|
MPG123 = mpg123_new(NULL, NULL);
|
||||||
|
if(mpg123_replace_reader_handle(MPG123, mem_read, mem_lseek, NULL) == MPG123_OK &&
|
||||||
|
mpg123_open_handle(MPG123, this) == MPG123_OK)
|
||||||
|
{
|
||||||
|
int enc, channels;
|
||||||
|
long srate;
|
||||||
|
|
||||||
|
if(mpg123_getformat(MPG123, &srate, &channels, &enc) == MPG123_OK)
|
||||||
|
{
|
||||||
|
if((channels == 1 || channels == 2) && srate > 0 &&
|
||||||
|
mpg123_format_none(MPG123) == MPG123_OK &&
|
||||||
|
mpg123_format(MPG123, srate, channels, MPG123_ENC_SIGNED_16) == MPG123_OK)
|
||||||
|
{
|
||||||
|
// All OK
|
||||||
|
Done = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mpg123_close(MPG123);
|
||||||
|
}
|
||||||
|
mpg123_delete(MPG123);
|
||||||
|
MPG123 = 0;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MPG123Decoder::getInfo(int *samplerate, ChannelConfig *chans, SampleType *type)
|
||||||
|
{
|
||||||
|
int enc = 0, channels = 0;
|
||||||
|
long srate = 0;
|
||||||
|
|
||||||
|
mpg123_getformat(MPG123, &srate, &channels, &enc);
|
||||||
|
|
||||||
|
*samplerate = srate;
|
||||||
|
|
||||||
|
if(channels == 2)
|
||||||
|
*chans = ChannelConfig_Stereo;
|
||||||
|
else
|
||||||
|
*chans = ChannelConfig_Mono;
|
||||||
|
|
||||||
|
*type = SampleType_Int16;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t MPG123Decoder::read(char *buffer, size_t bytes)
|
||||||
|
{
|
||||||
|
size_t amt = 0;
|
||||||
|
while(!Done && bytes > 0)
|
||||||
|
{
|
||||||
|
size_t got = 0;
|
||||||
|
int ret = mpg123_read(MPG123, (unsigned char*)buffer, bytes, &got);
|
||||||
|
|
||||||
|
bytes -= got;
|
||||||
|
buffer += got;
|
||||||
|
amt += got;
|
||||||
|
|
||||||
|
if(ret == MPG123_NEW_FORMAT || ret == MPG123_DONE || got == 0)
|
||||||
|
{
|
||||||
|
Done = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return amt;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MPG123Decoder::open(const char *fname, size_t offset, size_t length)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MPG123Decoder::seek(size_t ms_offset)
|
||||||
|
{
|
||||||
|
int enc, channels;
|
||||||
|
long srate;
|
||||||
|
|
||||||
|
if(mpg123_getformat(MPG123, &srate, &channels, &enc) == MPG123_OK)
|
||||||
|
{
|
||||||
|
size_t smp_offset = (size_t)((double)ms_offset / 1000. * srate);
|
||||||
|
if(mpg123_seek(MPG123, smp_offset, SEEK_SET) >= 0)
|
||||||
|
{
|
||||||
|
Done = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t MPG123Decoder::getSampleOffset()
|
||||||
|
{
|
||||||
|
return mpg123_tell(MPG123);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -524,12 +524,64 @@ SoundHandle SoundRenderer::LoadSoundVoc(BYTE *sfxdata, int length)
|
||||||
SoundDecoder *SoundRenderer::CreateDecoder(const BYTE *sfxdata, int length)
|
SoundDecoder *SoundRenderer::CreateDecoder(const BYTE *sfxdata, int length)
|
||||||
{
|
{
|
||||||
SoundDecoder *decoder = NULL;
|
SoundDecoder *decoder = NULL;
|
||||||
#ifdef HAVE_SNDFILE
|
#ifdef HAVE_MPG123
|
||||||
decoder = new SndFileDecoder;
|
int mpg_start = -1;
|
||||||
if(!decoder->open((const char*)sfxdata, length))
|
int mpg_len = -1;
|
||||||
|
|
||||||
|
// Check for an ID3 tag to identify an mp3 (and skip the tag)
|
||||||
|
if(length > 10 && memcmp(sfxdata, "ID3", 3) == 0 &&
|
||||||
|
sfxdata[3] <= 4 && sfxdata[4] != 0xff &&
|
||||||
|
(sfxdata[5]&0x0f) == 0 && (sfxdata[6]&0x80) == 0 &&
|
||||||
|
(sfxdata[7]&0x80) == 0 && (sfxdata[8]&0x80) == 0 &&
|
||||||
|
(sfxdata[9]&0x80) == 0)
|
||||||
{
|
{
|
||||||
delete decoder;
|
// ID3v2
|
||||||
decoder = NULL;
|
mpg_start = (sfxdata[6]<<21) | (sfxdata[7]<<14) |
|
||||||
|
(sfxdata[8]<< 7) | (sfxdata[9] );
|
||||||
|
mpg_start += ((sfxdata[5]&0x10) ? 20 : 10);
|
||||||
|
mpg_len = length - mpg_start;
|
||||||
|
}
|
||||||
|
else if(length > 128 && memcmp(sfxdata+length-128, "TAG", 3) == 0)
|
||||||
|
{
|
||||||
|
// ID3v1
|
||||||
|
mpg_start = 0;
|
||||||
|
mpg_len = length - 128;
|
||||||
|
}
|
||||||
|
else if(length > 3)
|
||||||
|
{
|
||||||
|
// No ID3 tag. Check for a frame header
|
||||||
|
if((sfxdata[0] == 0xff && sfxdata[1]>>1 == 0x7d) || // MPEG-1
|
||||||
|
(sfxdata[0] == 0xff && sfxdata[1]>>1 == 0x79)) // MPEG-2
|
||||||
|
{
|
||||||
|
int brate_idx = (sfxdata[2]>>4) & 0x0f;
|
||||||
|
int srate_idx = (sfxdata[2]>>2) & 0x03;
|
||||||
|
if(brate_idx != 0 && brate_idx != 15 && srate_idx != 3)
|
||||||
|
{
|
||||||
|
mpg_start = 0;
|
||||||
|
mpg_len = length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mpg_start >= 0 && mpg_len > 0 && mpg_start < length && mpg_len <= length-mpg_start)
|
||||||
|
{
|
||||||
|
decoder = new MPG123Decoder;
|
||||||
|
if(!decoder->open((const char*)sfxdata+mpg_start, mpg_len))
|
||||||
|
{
|
||||||
|
delete decoder;
|
||||||
|
decoder = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_SNDFILE
|
||||||
|
if(!decoder)
|
||||||
|
{
|
||||||
|
decoder = new SndFileDecoder;
|
||||||
|
if(!decoder->open((const char*)sfxdata, length))
|
||||||
|
{
|
||||||
|
delete decoder;
|
||||||
|
decoder = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return decoder;
|
return decoder;
|
||||||
|
|
|
@ -139,6 +139,38 @@ private:
|
||||||
SoundDecoder& operator=(const SoundDecoder &rhs);
|
SoundDecoder& operator=(const SoundDecoder &rhs);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef HAVE_MPG123
|
||||||
|
#include "mpg123.h"
|
||||||
|
struct MPG123Decoder : public SoundDecoder
|
||||||
|
{
|
||||||
|
virtual void getInfo(int *samplerate, ChannelConfig *chans, SampleType *type);
|
||||||
|
|
||||||
|
virtual size_t read(char *buffer, size_t bytes);
|
||||||
|
virtual bool seek(size_t ms_offset);
|
||||||
|
virtual size_t getSampleOffset();
|
||||||
|
|
||||||
|
MPG123Decoder() : MPG123(0) { }
|
||||||
|
virtual ~MPG123Decoder();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual bool open(const char *data, size_t length);
|
||||||
|
virtual bool open(const char *fname, size_t offset, size_t length);
|
||||||
|
|
||||||
|
private:
|
||||||
|
mpg123_handle *MPG123;
|
||||||
|
bool Done;
|
||||||
|
|
||||||
|
const char *MemData;
|
||||||
|
size_t MemLength;
|
||||||
|
size_t MemPos;
|
||||||
|
static off_t mem_lseek(void *handle, off_t offset, int whence);
|
||||||
|
static ssize_t mem_read(void *handle, void *buffer, size_t bytes);
|
||||||
|
|
||||||
|
// Make non-copyable
|
||||||
|
MPG123Decoder(const MPG123Decoder &rhs);
|
||||||
|
MPG123Decoder& operator=(const MPG123Decoder &rhs);
|
||||||
|
};
|
||||||
|
#endif
|
||||||
#ifdef HAVE_SNDFILE
|
#ifdef HAVE_SNDFILE
|
||||||
#include "sndfile.h"
|
#include "sndfile.h"
|
||||||
struct SndFileDecoder : public SoundDecoder
|
struct SndFileDecoder : public SoundDecoder
|
||||||
|
|
Loading…
Reference in a new issue