mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-22 12:11:25 +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 )
|
||||
|
||||
# Search for libmpg123
|
||||
|
||||
find_package( MPG123 )
|
||||
|
||||
# Search for FluidSynth
|
||||
|
||||
find_package( FluidSynth )
|
||||
|
@ -553,7 +557,10 @@ if( SNDFILE_FOUND )
|
|||
set( ZDOOM_LIBS ${ZDOOM_LIBS} "${SNDFILE_LIBRARIES}" )
|
||||
include_directories( "${SNDFILE_INCLUDE_DIRS}" )
|
||||
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( FLUIDSYNTH_FOUND )
|
||||
set( ZDOOM_LIBS ${ZDOOM_LIBS} "${FLUIDSYNTH_LIBRARIES}" )
|
||||
|
@ -671,6 +678,9 @@ endif( SSE_MATTERS )
|
|||
if( SNDFILE_FOUND )
|
||||
add_definitions( -DHAVE_SNDFILE )
|
||||
endif( SNDFILE_FOUND )
|
||||
if( MPG123_FOUND )
|
||||
add_definitions( -DHAVE_MPG123 )
|
||||
endif( MPG123_FOUND )
|
||||
if( DYN_FLUIDSYNTH )
|
||||
add_definitions( -DHAVE_FLUIDSYNTH -DDYN_FLUIDSYNTH )
|
||||
elseif( FLUIDSYNTH_FOUND )
|
||||
|
@ -1034,6 +1044,7 @@ add_executable( zdoom WIN32
|
|||
resourcefiles/file_directory.cpp
|
||||
resourcefiles/resourcefile.cpp
|
||||
sfmt/SFMT.cpp
|
||||
sound/audio_mpg123_decoder.cpp
|
||||
sound/audio_sndfile_decoder.cpp
|
||||
sound/fmodsound.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,13 +524,65 @@ SoundHandle SoundRenderer::LoadSoundVoc(BYTE *sfxdata, int length)
|
|||
SoundDecoder *SoundRenderer::CreateDecoder(const BYTE *sfxdata, int length)
|
||||
{
|
||||
SoundDecoder *decoder = NULL;
|
||||
#ifdef HAVE_MPG123
|
||||
int mpg_start = -1;
|
||||
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)
|
||||
{
|
||||
// ID3v2
|
||||
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
|
||||
return decoder;
|
||||
}
|
||||
|
|
|
@ -139,6 +139,38 @@ private:
|
|||
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
|
||||
#include "sndfile.h"
|
||||
struct SndFileDecoder : public SoundDecoder
|
||||
|
|
Loading…
Reference in a new issue