- moved the sound decoding code to the zmusic project.
Since this gets used by both the sound backend and the music code it needs to be in a place accessible to both.
This commit is contained in:
parent
b883d27a1f
commit
cdf2a17c5a
35 changed files with 544 additions and 426 deletions
|
|
@ -23,10 +23,6 @@ if( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE )
|
|||
endif()
|
||||
endif()
|
||||
|
||||
option( DYN_OPENAL "Dynamically load OpenAL" ON )
|
||||
option( DYN_SNDFILE "Dynamically load libsndfile" ON )
|
||||
option( DYN_MPG123 "Dynamically load libmpg123" ON )
|
||||
|
||||
if( APPLE )
|
||||
option( OSX_COCOA_BACKEND "Use native Cocoa backend instead of SDL" ON )
|
||||
endif()
|
||||
|
|
@ -623,24 +619,6 @@ add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/sc_man_scanner.h
|
|||
|
||||
include_directories( ${CMAKE_CURRENT_BINARY_DIR} )
|
||||
|
||||
if( DYN_SNDFILE)
|
||||
add_definitions( -DHAVE_SNDFILE -DDYN_SNDFILE )
|
||||
elseif( SNDFILE_FOUND )
|
||||
add_definitions( -DHAVE_SNDFILE )
|
||||
endif()
|
||||
|
||||
if( DYN_MPG123)
|
||||
add_definitions( -DHAVE_MPG123 -DDYN_MPG123 )
|
||||
elseif( MPG123_FOUND )
|
||||
add_definitions( -DHAVE_MPG123 )
|
||||
endif()
|
||||
|
||||
if( DYN_FLUIDSYNTH )
|
||||
add_definitions( -DHAVE_FLUIDSYNTH -DDYN_FLUIDSYNTH )
|
||||
elseif( FLUIDSYNTH_FOUND )
|
||||
add_definitions( -DHAVE_FLUIDSYNTH )
|
||||
endif()
|
||||
|
||||
option( SEND_ANON_STATS "Enable sending of anonymous hardware statistics" ON )
|
||||
|
||||
if( NOT SEND_ANON_STATS )
|
||||
|
|
@ -832,10 +810,8 @@ set( FASTMATH_SOURCES
|
|||
rendering/swrenderer/r_all.cpp
|
||||
rendering/swrenderer/r_swscene.cpp
|
||||
rendering/polyrenderer/poly_all.cpp
|
||||
sound/backend/mpg123_decoder.cpp
|
||||
sound/music/music_midi_base.cpp
|
||||
sound/backend/oalsound.cpp
|
||||
sound/backend/sndfile_decoder.cpp
|
||||
gamedata/textures/hires/hqnx/init.cpp
|
||||
gamedata/textures/hires/hqnx/hq2x.cpp
|
||||
gamedata/textures/hires/hqnx/hq3x.cpp
|
||||
|
|
|
|||
|
|
@ -39,8 +39,10 @@
|
|||
|
||||
#include "oalsound.h"
|
||||
|
||||
#include "mpg123_decoder.h"
|
||||
#include "sndfile_decoder.h"
|
||||
#include "i_module.h"
|
||||
#include "cmdlib.h"
|
||||
#include "zmusic/mpg123_decoder.h"
|
||||
#include "zmusic/sndfile_decoder.h"
|
||||
|
||||
#include "c_dispatch.h"
|
||||
#include "i_music.h"
|
||||
|
|
@ -247,6 +249,7 @@ public:
|
|||
|
||||
void I_InitSound ()
|
||||
{
|
||||
FModule_SetProgDir(progdir);
|
||||
/* Get command line options: */
|
||||
nosound = !!Args->CheckParm ("-nosound");
|
||||
nosfx = !!Args->CheckParm ("-nosfx");
|
||||
|
|
@ -351,16 +354,20 @@ FString SoundRenderer::GatherStats ()
|
|||
|
||||
short *SoundRenderer::DecodeSample(int outlen, const void *coded, int sizebytes, ECodecType ctype)
|
||||
{
|
||||
FileReader reader;
|
||||
short *samples = (short*)calloc(1, outlen);
|
||||
ChannelConfig chans;
|
||||
SampleType type;
|
||||
int srate;
|
||||
|
||||
reader.OpenMemory(coded, sizebytes);
|
||||
// The decoder will take ownership of the reader if it succeeds so this may not be a local variable.
|
||||
MusicIO::MemoryReader *reader = new MusicIO::MemoryReader((const uint8_t*)coded, sizebytes);
|
||||
|
||||
SoundDecoder *decoder = CreateDecoder(reader);
|
||||
if(!decoder) return samples;
|
||||
SoundDecoder *decoder = SoundDecoder::CreateDecoder(reader);
|
||||
if (!decoder)
|
||||
{
|
||||
reader->close();
|
||||
return samples;
|
||||
}
|
||||
|
||||
decoder->getInfo(&srate, &chans, &type);
|
||||
if(chans != ChannelConfig_Mono || type != SampleType_Int16)
|
||||
|
|
@ -545,46 +552,3 @@ std::pair<SoundHandle, bool> SoundRenderer::LoadSoundBuffered(FSoundLoadBuffer *
|
|||
return std::make_pair(retval, true);
|
||||
}
|
||||
|
||||
SoundDecoder *SoundRenderer::CreateDecoder(FileReader &reader)
|
||||
{
|
||||
SoundDecoder *decoder = NULL;
|
||||
auto pos = reader.Tell();
|
||||
|
||||
#ifdef HAVE_SNDFILE
|
||||
decoder = new SndFileDecoder;
|
||||
if (decoder->open(reader))
|
||||
return decoder;
|
||||
reader.Seek(pos, FileReader::SeekSet);
|
||||
|
||||
delete decoder;
|
||||
decoder = NULL;
|
||||
#endif
|
||||
#ifdef HAVE_MPG123
|
||||
decoder = new MPG123Decoder;
|
||||
if (decoder->open(reader))
|
||||
return decoder;
|
||||
reader.Seek(pos, FileReader::SeekSet);
|
||||
|
||||
delete decoder;
|
||||
decoder = NULL;
|
||||
#endif
|
||||
return decoder;
|
||||
}
|
||||
|
||||
|
||||
// Default readAll implementation, for decoders that can't do anything better
|
||||
TArray<uint8_t> SoundDecoder::readAll()
|
||||
{
|
||||
TArray<uint8_t> output;
|
||||
unsigned total = 0;
|
||||
unsigned got;
|
||||
|
||||
output.Resize(total+32768);
|
||||
while((got=(unsigned)read((char*)&output[total], output.Size()-total)) > 0)
|
||||
{
|
||||
total += got;
|
||||
output.Resize(total*2);
|
||||
}
|
||||
output.Resize(total);
|
||||
return output;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ class MIDIDevice;
|
|||
|
||||
struct FSoundLoadBuffer
|
||||
{
|
||||
TArray<uint8_t> mBuffer;
|
||||
std::vector<uint8_t> mBuffer;
|
||||
uint32_t loop_start;
|
||||
uint32_t loop_end;
|
||||
ChannelConfig chans;
|
||||
|
|
@ -169,8 +169,6 @@ public:
|
|||
virtual short *DecodeSample(int outlen, const void *coded, int sizebytes, ECodecType type);
|
||||
|
||||
virtual void DrawWaveDebug(int mode);
|
||||
|
||||
static SoundDecoder *CreateDecoder(FileReader &reader);
|
||||
};
|
||||
|
||||
extern SoundRenderer *GSnd;
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#include "doomtype.h"
|
||||
#include "vectors.h"
|
||||
#include "tarray.h"
|
||||
#include "../../libraries/music_common/fileio.h"
|
||||
|
||||
class FileReader;
|
||||
|
||||
|
|
@ -113,45 +114,12 @@ struct FISoundChannel
|
|||
};
|
||||
|
||||
|
||||
void FindLoopTags(FileReader &fr, uint32_t *start, bool *startass, uint32_t *end, bool *endass);
|
||||
void FindLoopTags(MusicIO::FileInterface *fr, uint32_t *start, bool *startass, uint32_t *end, bool *endass);
|
||||
|
||||
|
||||
enum SampleType
|
||||
{
|
||||
SampleType_UInt8,
|
||||
SampleType_Int16
|
||||
};
|
||||
enum ChannelConfig
|
||||
{
|
||||
ChannelConfig_Mono,
|
||||
ChannelConfig_Stereo
|
||||
};
|
||||
|
||||
const char *GetSampleTypeName(enum SampleType type);
|
||||
const char *GetChannelConfigName(enum ChannelConfig chan);
|
||||
|
||||
struct SoundDecoder
|
||||
{
|
||||
virtual void getInfo(int *samplerate, ChannelConfig *chans, SampleType *type) = 0;
|
||||
|
||||
virtual size_t read(char *buffer, size_t bytes) = 0;
|
||||
virtual TArray<uint8_t> readAll();
|
||||
virtual bool seek(size_t ms_offset, bool ms, bool mayrestart) = 0;
|
||||
virtual size_t getSampleOffset() = 0;
|
||||
virtual size_t getSampleLength() { return 0; }
|
||||
|
||||
SoundDecoder() { }
|
||||
virtual ~SoundDecoder() { }
|
||||
|
||||
protected:
|
||||
virtual bool open(FileReader &reader) = 0;
|
||||
friend class SoundRenderer;
|
||||
|
||||
// Make non-copyable
|
||||
SoundDecoder(const SoundDecoder &rhs) = delete;
|
||||
SoundDecoder& operator=(const SoundDecoder &rhs) = delete;
|
||||
};
|
||||
|
||||
class MusInfo;
|
||||
struct MusPlayingInfo
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,234 +0,0 @@
|
|||
/*
|
||||
** mpg123_decoder.cpp
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2008-2010 Chris Robinson
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
#include "mpg123_decoder.h"
|
||||
#include "i_module.h"
|
||||
#include "cmdlib.h"
|
||||
|
||||
#ifdef HAVE_MPG123
|
||||
|
||||
|
||||
FModule MPG123Module{"MPG123"};
|
||||
|
||||
#include "mpgload.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#define MPG123LIB "libmpg123-0.dll"
|
||||
#elif defined(__APPLE__)
|
||||
#define MPG123LIB "libmpg123.0.dylib"
|
||||
#else
|
||||
#define MPG123LIB "libmpg123.so.0"
|
||||
#endif
|
||||
|
||||
bool IsMPG123Present()
|
||||
{
|
||||
#if !defined DYN_MPG123
|
||||
return true;
|
||||
#else
|
||||
static bool cached_result = false;
|
||||
static bool done = false;
|
||||
|
||||
if (!done)
|
||||
{
|
||||
done = true;
|
||||
cached_result = MPG123Module.Load({NicePath("$PROGDIR/" MPG123LIB), MPG123LIB});
|
||||
}
|
||||
return cached_result;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static bool inited = false;
|
||||
|
||||
|
||||
off_t MPG123Decoder::file_lseek(void *handle, off_t offset, int whence)
|
||||
{
|
||||
auto &reader = reinterpret_cast<MPG123Decoder*>(handle)->Reader;
|
||||
|
||||
if(whence == SEEK_CUR)
|
||||
{
|
||||
if(offset < 0 && reader.Tell()+offset < 0)
|
||||
return -1;
|
||||
}
|
||||
else if(whence == SEEK_END)
|
||||
{
|
||||
if(offset < 0 && reader.GetLength()+offset < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(reader.Seek(offset, (FileReader::ESeek)whence) != 0)
|
||||
return -1;
|
||||
return (off_t)reader.Tell();
|
||||
}
|
||||
|
||||
ssize_t MPG123Decoder::file_read(void *handle, void *buffer, size_t bytes)
|
||||
{
|
||||
auto &reader = reinterpret_cast<MPG123Decoder*>(handle)->Reader;
|
||||
return (ssize_t)reader.Read(buffer, (long)bytes);
|
||||
}
|
||||
|
||||
|
||||
MPG123Decoder::~MPG123Decoder()
|
||||
{
|
||||
if(MPG123)
|
||||
{
|
||||
mpg123_close(MPG123);
|
||||
mpg123_delete(MPG123);
|
||||
MPG123 = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool MPG123Decoder::open(FileReader &reader)
|
||||
{
|
||||
if(!inited)
|
||||
{
|
||||
if (!IsMPG123Present()) return false;
|
||||
if(mpg123_init() != MPG123_OK) return false;
|
||||
inited = true;
|
||||
}
|
||||
|
||||
Reader = std::move(reader);
|
||||
|
||||
{
|
||||
MPG123 = mpg123_new(NULL, NULL);
|
||||
if(mpg123_replace_reader_handle(MPG123, file_read, file_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;
|
||||
}
|
||||
|
||||
reader = std::move(Reader); // need to give it back.
|
||||
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::seek(size_t ms_offset, bool ms, bool mayrestart)
|
||||
{
|
||||
int enc, channels;
|
||||
long srate;
|
||||
|
||||
if (!mayrestart || ms_offset > 0)
|
||||
{
|
||||
if (mpg123_getformat(MPG123, &srate, &channels, &enc) == MPG123_OK)
|
||||
{
|
||||
size_t smp_offset = ms ? (size_t)((double)ms_offset / 1000. * srate) : ms_offset;
|
||||
if (mpg123_seek(MPG123, (off_t)smp_offset, SEEK_SET) >= 0)
|
||||
{
|
||||
Done = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Restart the song instead of rewinding. A rewind seems to cause distortion when done repeatedly.
|
||||
// offset is intentionally ignored here.
|
||||
if (MPG123)
|
||||
{
|
||||
mpg123_close(MPG123);
|
||||
mpg123_delete(MPG123);
|
||||
MPG123 = 0;
|
||||
}
|
||||
Reader.Seek(0, FileReader::SeekSet);
|
||||
// Do not call open with our own reader variable, that would be catastrophic.
|
||||
auto reader = std::move(Reader);
|
||||
return open(reader);
|
||||
}
|
||||
}
|
||||
size_t MPG123Decoder::getSampleOffset()
|
||||
{
|
||||
return mpg123_tell(MPG123);
|
||||
}
|
||||
|
||||
size_t MPG123Decoder::getSampleLength()
|
||||
{
|
||||
off_t len = mpg123_length(MPG123);
|
||||
return (len > 0) ? len : 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
#ifndef MPG123_DECODER_H
|
||||
#define MPG123_DECODER_H
|
||||
|
||||
#include "i_soundinternal.h"
|
||||
#include "files.h"
|
||||
|
||||
#ifdef HAVE_MPG123
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <stddef.h>
|
||||
typedef ptrdiff_t ssize_t;
|
||||
#endif
|
||||
|
||||
#ifndef DYN_MPG123
|
||||
#include "mpg123.h"
|
||||
#else
|
||||
#include "thirdparty/mpg123.h"
|
||||
#endif
|
||||
|
||||
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, bool ms, bool mayrestart);
|
||||
virtual size_t getSampleOffset();
|
||||
virtual size_t getSampleLength();
|
||||
|
||||
MPG123Decoder() : MPG123(0) { }
|
||||
virtual ~MPG123Decoder();
|
||||
|
||||
protected:
|
||||
virtual bool open(FileReader &reader);
|
||||
|
||||
private:
|
||||
mpg123_handle *MPG123;
|
||||
bool Done;
|
||||
|
||||
FileReader Reader;
|
||||
static off_t file_lseek(void *handle, off_t offset, int whence);
|
||||
static ssize_t file_read(void *handle, void *buffer, size_t bytes);
|
||||
|
||||
// Make non-copyable
|
||||
MPG123Decoder(const MPG123Decoder &rhs);
|
||||
MPG123Decoder& operator=(const MPG123Decoder &rhs);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* MPG123_DECODER_H */
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
#ifndef MPGDEF_H
|
||||
#define MPGDEF_H
|
||||
|
||||
#if defined HAVE_MPG123 && defined DYN_MPG123
|
||||
|
||||
#define DEFINE_ENTRY(type, name) static TReqProc<MPG123Module, type> p_##name{#name};
|
||||
DEFINE_ENTRY(int (*)(mpg123_handle *mh), mpg123_close)
|
||||
DEFINE_ENTRY(void (*)(mpg123_handle *mh), mpg123_delete)
|
||||
DEFINE_ENTRY(int (*)(void), mpg123_init)
|
||||
DEFINE_ENTRY(mpg123_handle* (*)(const char* decoder, int *error), mpg123_new)
|
||||
DEFINE_ENTRY(int (*)(mpg123_handle *mh, ssize_t (*r_read) (void *, void *, size_t), off_t (*r_lseek)(void *, off_t, int), void (*cleanup)(void*)), mpg123_replace_reader_handle)
|
||||
DEFINE_ENTRY(int (*)(mpg123_handle *mh, void *iohandle), mpg123_open_handle)
|
||||
DEFINE_ENTRY(int (*)(mpg123_handle *mh, long *rate, int *channels, int *encoding), mpg123_getformat)
|
||||
DEFINE_ENTRY(int (*)(mpg123_handle *mh), mpg123_format_none)
|
||||
DEFINE_ENTRY(int (*)(mpg123_handle *mh, unsigned char *outmemory, size_t outmemsize, size_t *done), mpg123_read)
|
||||
DEFINE_ENTRY(off_t (*)(mpg123_handle *mh, off_t sampleoff, int whence), mpg123_seek)
|
||||
DEFINE_ENTRY(int (*)(mpg123_handle *mh, long rate, int channels, int encodings), mpg123_format)
|
||||
DEFINE_ENTRY(off_t (*)(mpg123_handle *mh), mpg123_tell)
|
||||
DEFINE_ENTRY(off_t (*)(mpg123_handle *mh), mpg123_length)
|
||||
|
||||
#undef DEFINE_ENTRY
|
||||
|
||||
#ifndef IN_IDE_PARSER
|
||||
#define mpg123_close p_mpg123_close
|
||||
#define mpg123_delete p_mpg123_delete
|
||||
#define mpg123_init p_mpg123_init
|
||||
#define mpg123_new p_mpg123_new
|
||||
#define mpg123_replace_reader_handle p_mpg123_replace_reader_handle
|
||||
#define mpg123_open_handle p_mpg123_open_handle
|
||||
#define mpg123_getformat p_mpg123_getformat
|
||||
#define mpg123_format_none p_mpg123_format_none
|
||||
#define mpg123_read p_mpg123_read
|
||||
#define mpg123_seek p_mpg123_seek
|
||||
#define mpg123_tell p_mpg123_tell
|
||||
#define mpg123_format p_mpg123_format
|
||||
#define mpg123_length p_mpg123_length
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
@ -44,6 +44,8 @@
|
|||
#include "i_music.h"
|
||||
#include "cmdlib.h"
|
||||
#include "menu/menu.h"
|
||||
#include "zmusic/sounddecoder.h"
|
||||
#include "filereadermusicinterface.h"
|
||||
|
||||
FModule OpenALModule{"OpenAL"};
|
||||
|
||||
|
|
@ -229,7 +231,6 @@ class OpenALSoundStream : public SoundStream
|
|||
ALfloat Volume;
|
||||
|
||||
|
||||
FileReader Reader;
|
||||
SoundDecoder *Decoder;
|
||||
static bool DecoderCallback(SoundStream *_sstream, void *ptr, int length, void *user)
|
||||
{
|
||||
|
|
@ -612,9 +613,13 @@ public:
|
|||
}
|
||||
|
||||
if(Decoder) delete Decoder;
|
||||
Reader = std::move(reader);
|
||||
Decoder = Renderer->CreateDecoder(Reader);
|
||||
if(!Decoder) return false;
|
||||
auto mreader = new FileReaderMusicInterface(reader);
|
||||
Decoder = SoundDecoder::CreateDecoder(mreader);
|
||||
if (!Decoder)
|
||||
{
|
||||
mreader->close();
|
||||
return false;
|
||||
}
|
||||
|
||||
Callback = DecoderCallback;
|
||||
UserData = NULL;
|
||||
|
|
@ -1285,7 +1290,6 @@ std::pair<SoundHandle,bool> OpenALSoundRenderer::LoadSoundRaw(uint8_t *sfxdata,
|
|||
std::pair<SoundHandle,bool> OpenALSoundRenderer::LoadSound(uint8_t *sfxdata, int length, bool monoize, FSoundLoadBuffer *pBuffer)
|
||||
{
|
||||
SoundHandle retval = { NULL };
|
||||
FileReader reader;
|
||||
ALenum format = AL_NONE;
|
||||
ChannelConfig chans;
|
||||
SampleType type;
|
||||
|
|
@ -1296,13 +1300,16 @@ std::pair<SoundHandle,bool> OpenALSoundRenderer::LoadSound(uint8_t *sfxdata, int
|
|||
/* Only downmix to mono if we can't spatialize multi-channel sounds. */
|
||||
monoize = monoize && !AL.SOFT_source_spatialize;
|
||||
|
||||
reader.OpenMemory(sfxdata, length);
|
||||
|
||||
FindLoopTags(reader, &loop_start, &startass, &loop_end, &endass);
|
||||
|
||||
reader.Seek(0, FileReader::SeekSet);
|
||||
std::unique_ptr<SoundDecoder> decoder(CreateDecoder(reader));
|
||||
if (!decoder) return std::make_pair(retval, true);
|
||||
auto mreader = new MusicIO::MemoryReader(sfxdata, length);
|
||||
FindLoopTags(mreader, &loop_start, &startass, &loop_end, &endass);
|
||||
mreader->seek(0, SEEK_SET);
|
||||
std::unique_ptr<SoundDecoder> decoder(SoundDecoder::CreateDecoder(mreader));
|
||||
if (!decoder)
|
||||
{
|
||||
delete mreader;
|
||||
return std::make_pair(retval, true);
|
||||
}
|
||||
// the decode will take ownership of the reader here.
|
||||
|
||||
decoder->getInfo(&srate, &chans, &type);
|
||||
int samplesize = 1;
|
||||
|
|
@ -1324,12 +1331,12 @@ std::pair<SoundHandle,bool> OpenALSoundRenderer::LoadSound(uint8_t *sfxdata, int
|
|||
return std::make_pair(retval, true);
|
||||
}
|
||||
|
||||
TArray<uint8_t> data = decoder->readAll();
|
||||
auto data = decoder->readAll();
|
||||
|
||||
if(chans != ChannelConfig_Mono && monoize)
|
||||
{
|
||||
size_t chancount = GetChannelCount(chans);
|
||||
size_t frames = data.Size() / chancount /
|
||||
size_t frames = data.size() / chancount /
|
||||
(type == SampleType_Int16 ? 2 : 1);
|
||||
if(type == SampleType_Int16)
|
||||
{
|
||||
|
|
@ -1353,13 +1360,13 @@ std::pair<SoundHandle,bool> OpenALSoundRenderer::LoadSound(uint8_t *sfxdata, int
|
|||
sfxdata[i] = uint8_t((sum / chancount) + 128);
|
||||
}
|
||||
}
|
||||
data.Resize(unsigned(data.Size()/chancount));
|
||||
data.resize((data.size()/chancount));
|
||||
}
|
||||
|
||||
ALenum err;
|
||||
ALuint buffer = 0;
|
||||
alGenBuffers(1, &buffer);
|
||||
alBufferData(buffer, format, &data[0], data.Size(), srate);
|
||||
alBufferData(buffer, format, &data[0], (ALsizei)data.size(), srate);
|
||||
if((err=getALError()) != AL_NO_ERROR)
|
||||
{
|
||||
Printf("Failed to buffer data: %s\n", alGetString(err));
|
||||
|
|
@ -1370,7 +1377,7 @@ std::pair<SoundHandle,bool> OpenALSoundRenderer::LoadSound(uint8_t *sfxdata, int
|
|||
|
||||
if (!startass) loop_start = Scale(loop_start, srate, 1000);
|
||||
if (!endass && loop_end != ~0u) loop_end = Scale(loop_end, srate, 1000);
|
||||
const uint32_t samples = data.Size() / samplesize;
|
||||
const uint32_t samples = (uint32_t)data.size() / samplesize;
|
||||
if (loop_start > samples) loop_start = 0;
|
||||
if (loop_end > samples) loop_end = samples;
|
||||
|
||||
|
|
@ -1425,12 +1432,12 @@ std::pair<SoundHandle, bool> OpenALSoundRenderer::LoadSoundBuffered(FSoundLoadBu
|
|||
return std::make_pair(retval, true);
|
||||
}
|
||||
|
||||
TArray<uint8_t> &data = pBuffer->mBuffer;
|
||||
auto &data = pBuffer->mBuffer;
|
||||
|
||||
if (pBuffer->chans == ChannelConfig_Stereo && monoize)
|
||||
{
|
||||
size_t chancount = GetChannelCount(chans);
|
||||
size_t frames = data.Size() / chancount /
|
||||
size_t frames = data.size() / chancount /
|
||||
(type == SampleType_Int16 ? 2 : 1);
|
||||
if (type == SampleType_Int16)
|
||||
{
|
||||
|
|
@ -1454,13 +1461,13 @@ std::pair<SoundHandle, bool> OpenALSoundRenderer::LoadSoundBuffered(FSoundLoadBu
|
|||
sfxdata[i] = uint8_t((sum / chancount) + 128);
|
||||
}
|
||||
}
|
||||
data.Resize(unsigned(data.Size() / chancount));
|
||||
data.resize(data.size() / chancount);
|
||||
}
|
||||
|
||||
ALenum err;
|
||||
ALuint buffer = 0;
|
||||
alGenBuffers(1, &buffer);
|
||||
alBufferData(buffer, format, &data[0], data.Size(), srate);
|
||||
alBufferData(buffer, format, &data[0], (ALsizei)data.size(), srate);
|
||||
if ((err = getALError()) != AL_NO_ERROR)
|
||||
{
|
||||
Printf("Failed to buffer data: %s\n", alGetString(err));
|
||||
|
|
|
|||
|
|
@ -1,205 +0,0 @@
|
|||
/*
|
||||
** sndfile_decoder.cpp
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2008-2010 Chris Robinson
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
#include "sndfile_decoder.h"
|
||||
#include "templates.h"
|
||||
#include "i_module.h"
|
||||
#include "cmdlib.h"
|
||||
|
||||
#ifdef HAVE_SNDFILE
|
||||
|
||||
FModule SndFileModule{"SndFile"};
|
||||
|
||||
#include "sndload.h"
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
#define SNDFILELIB "libsndfile-1.dll"
|
||||
#elif defined(__APPLE__)
|
||||
#define SNDFILELIB "libsndfile.1.dylib"
|
||||
#else
|
||||
#define SNDFILELIB "libsndfile.so.1"
|
||||
#endif
|
||||
|
||||
bool IsSndFilePresent()
|
||||
{
|
||||
#if !defined DYN_SNDFILE
|
||||
return true;
|
||||
#else
|
||||
static bool cached_result = false;
|
||||
static bool done = false;
|
||||
|
||||
if (!done)
|
||||
{
|
||||
done = true;
|
||||
cached_result = SndFileModule.Load({NicePath("$PROGDIR/" SNDFILELIB), SNDFILELIB});
|
||||
}
|
||||
return cached_result;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
sf_count_t SndFileDecoder::file_get_filelen(void *user_data)
|
||||
{
|
||||
auto &reader = reinterpret_cast<SndFileDecoder*>(user_data)->Reader;
|
||||
return reader.GetLength();
|
||||
}
|
||||
|
||||
sf_count_t SndFileDecoder::file_seek(sf_count_t offset, int whence, void *user_data)
|
||||
{
|
||||
auto &reader = reinterpret_cast<SndFileDecoder*>(user_data)->Reader;
|
||||
|
||||
if(reader.Seek((long)offset, (FileReader::ESeek)whence) != 0)
|
||||
return -1;
|
||||
return reader.Tell();
|
||||
}
|
||||
|
||||
sf_count_t SndFileDecoder::file_read(void *ptr, sf_count_t count, void *user_data)
|
||||
{
|
||||
auto &reader = reinterpret_cast<SndFileDecoder*>(user_data)->Reader;
|
||||
return reader.Read(ptr, (long)count);
|
||||
}
|
||||
|
||||
sf_count_t SndFileDecoder::file_write(const void *ptr, sf_count_t count, void *user_data)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
sf_count_t SndFileDecoder::file_tell(void *user_data)
|
||||
{
|
||||
auto &reader = reinterpret_cast<SndFileDecoder*>(user_data)->Reader;
|
||||
return reader.Tell();
|
||||
}
|
||||
|
||||
|
||||
SndFileDecoder::~SndFileDecoder()
|
||||
{
|
||||
if(SndFile)
|
||||
sf_close(SndFile);
|
||||
SndFile = 0;
|
||||
}
|
||||
|
||||
bool SndFileDecoder::open(FileReader &reader)
|
||||
{
|
||||
if (!IsSndFilePresent()) return false;
|
||||
|
||||
SF_VIRTUAL_IO sfio = { file_get_filelen, file_seek, file_read, file_write, file_tell };
|
||||
|
||||
Reader = std::move(reader);
|
||||
SndInfo.format = 0;
|
||||
SndFile = sf_open_virtual(&sfio, SFM_READ, &SndInfo, this);
|
||||
if (SndFile)
|
||||
{
|
||||
if (SndInfo.channels == 1 || SndInfo.channels == 2)
|
||||
return true;
|
||||
|
||||
sf_close(SndFile);
|
||||
SndFile = 0;
|
||||
}
|
||||
reader = std::move(Reader); // need to give it back.
|
||||
return false;
|
||||
}
|
||||
|
||||
void SndFileDecoder::getInfo(int *samplerate, ChannelConfig *chans, SampleType *type)
|
||||
{
|
||||
*samplerate = SndInfo.samplerate;
|
||||
|
||||
if(SndInfo.channels == 2)
|
||||
*chans = ChannelConfig_Stereo;
|
||||
else
|
||||
*chans = ChannelConfig_Mono;
|
||||
|
||||
*type = SampleType_Int16;
|
||||
}
|
||||
|
||||
size_t SndFileDecoder::read(char *buffer, size_t bytes)
|
||||
{
|
||||
short *out = (short*)buffer;
|
||||
size_t frames = bytes / SndInfo.channels / 2;
|
||||
size_t total = 0;
|
||||
|
||||
// It seems libsndfile has a bug with converting float samples from Vorbis
|
||||
// to the 16-bit shorts we use, which causes some PCM samples to overflow
|
||||
// and wrap, creating static. So instead, read the samples as floats and
|
||||
// convert to short ourselves.
|
||||
// Use a loop to convert a handful of samples at a time, avoiding a heap
|
||||
// allocation for temporary storage. 64 at a time works, though maybe it
|
||||
// could be more.
|
||||
while(total < frames)
|
||||
{
|
||||
size_t todo = MIN<size_t>(frames-total, 64/SndInfo.channels);
|
||||
float tmp[64];
|
||||
|
||||
size_t got = (size_t)sf_readf_float(SndFile, tmp, todo);
|
||||
if(got < todo) frames = total + got;
|
||||
|
||||
for(size_t i = 0;i < got*SndInfo.channels;i++)
|
||||
*out++ = (short)xs_CRoundToInt(clamp(tmp[i] * 32767.f, -32768.f, 32767.f));
|
||||
total += got;
|
||||
}
|
||||
return total * SndInfo.channels * 2;
|
||||
}
|
||||
|
||||
TArray<uint8_t> SndFileDecoder::readAll()
|
||||
{
|
||||
if(SndInfo.frames <= 0)
|
||||
return SoundDecoder::readAll();
|
||||
|
||||
int framesize = 2 * SndInfo.channels;
|
||||
TArray<uint8_t> output;
|
||||
|
||||
output.Resize((unsigned)(SndInfo.frames * framesize));
|
||||
size_t got = read((char*)&output[0], output.Size());
|
||||
output.Resize((unsigned)got);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
bool SndFileDecoder::seek(size_t ms_offset, bool ms, bool /*mayrestart*/)
|
||||
{
|
||||
size_t smp_offset = ms? (size_t)((double)ms_offset / 1000. * SndInfo.samplerate) : ms_offset;
|
||||
if(sf_seek(SndFile, smp_offset, SEEK_SET) < 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t SndFileDecoder::getSampleOffset()
|
||||
{
|
||||
return (size_t)sf_seek(SndFile, 0, SEEK_CUR);
|
||||
}
|
||||
|
||||
size_t SndFileDecoder::getSampleLength()
|
||||
{
|
||||
return (size_t)((SndInfo.frames > 0) ? SndInfo.frames : 0);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -1,49 +0,0 @@
|
|||
#ifndef SNDFILE_DECODER_H
|
||||
#define SNDFILE_DECODER_H
|
||||
|
||||
#include "i_soundinternal.h"
|
||||
#include "files.h"
|
||||
|
||||
#ifdef HAVE_SNDFILE
|
||||
|
||||
#ifndef DYN_SNDFILE
|
||||
#include "sndfile.h"
|
||||
#else
|
||||
#include "thirdparty/sndfile.h"
|
||||
#endif
|
||||
|
||||
struct SndFileDecoder : public SoundDecoder
|
||||
{
|
||||
virtual void getInfo(int *samplerate, ChannelConfig *chans, SampleType *type);
|
||||
|
||||
virtual size_t read(char *buffer, size_t bytes);
|
||||
virtual TArray<uint8_t> readAll();
|
||||
virtual bool seek(size_t ms_offset, bool ms, bool mayrestart);
|
||||
virtual size_t getSampleOffset();
|
||||
virtual size_t getSampleLength();
|
||||
|
||||
SndFileDecoder() : SndFile(0) { }
|
||||
virtual ~SndFileDecoder();
|
||||
|
||||
protected:
|
||||
virtual bool open(FileReader &reader);
|
||||
|
||||
private:
|
||||
SNDFILE *SndFile;
|
||||
SF_INFO SndInfo;
|
||||
|
||||
FileReader Reader;
|
||||
static sf_count_t file_get_filelen(void *user_data);
|
||||
static sf_count_t file_seek(sf_count_t offset, int whence, void *user_data);
|
||||
static sf_count_t file_read(void *ptr, sf_count_t count, void *user_data);
|
||||
static sf_count_t file_write(const void *ptr, sf_count_t count, void *user_data);
|
||||
static sf_count_t file_tell(void *user_data);
|
||||
|
||||
// Make non-copyable
|
||||
SndFileDecoder(const SndFileDecoder &rhs);
|
||||
SndFileDecoder& operator=(const SndFileDecoder &rhs);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* SNDFILE_DECODER_H */
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
#ifndef SNDDEF_H
|
||||
#define SNDDEF_H
|
||||
|
||||
#if defined HAVE_SNDFILE && defined DYN_SNDFILE
|
||||
|
||||
#define DEFINE_ENTRY(type, name) static TReqProc<SndFileModule, type> p_##name{#name};
|
||||
DEFINE_ENTRY(int (*)(SNDFILE *sndfile), sf_close)
|
||||
DEFINE_ENTRY(SNDFILE* (*)(SF_VIRTUAL_IO *sfvirtual, int mode, SF_INFO *sfinfo, void *user_data), sf_open_virtual)
|
||||
DEFINE_ENTRY(sf_count_t (*)(SNDFILE *sndfile, float *ptr, sf_count_t frames), sf_readf_float)
|
||||
DEFINE_ENTRY(sf_count_t (*)(SNDFILE *sndfile, sf_count_t frames, int whence), sf_seek)
|
||||
#undef DEFINE_ENTRY
|
||||
|
||||
#ifndef IN_IDE_PARSER
|
||||
#define sf_close p_sf_close
|
||||
#define sf_open_virtual p_sf_open_virtual
|
||||
#define sf_readf_float p_sf_readf_float
|
||||
#define sf_seek p_sf_seek
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
|
|
@ -47,7 +47,7 @@
|
|||
#include "stats.h"
|
||||
#include "vm.h"
|
||||
#include "s_music.h"
|
||||
#include "i_soundfont.h"
|
||||
#include "filereadermusicinterface.h"
|
||||
#include "../libraries/zmusic/midisources/midisource.h"
|
||||
#include "../libraries/dumb/include/dumb.h"
|
||||
|
||||
|
|
@ -83,7 +83,7 @@ EXTERN_CVAR (Int, snd_mididevice)
|
|||
|
||||
static bool MusicDown = true;
|
||||
|
||||
static bool ungzip(uint8_t *data, int size, TArray<uint8_t> &newdata);
|
||||
static bool ungzip(uint8_t *data, int size, std::vector<uint8_t> &newdata);
|
||||
|
||||
MusInfo *currSong;
|
||||
int nomusic = 0;
|
||||
|
|
@ -205,8 +205,6 @@ MusInfo::~MusInfo ()
|
|||
|
||||
void MusInfo::Start(bool loop, float rel_vol, int subsong)
|
||||
{
|
||||
if (nomusic) return;
|
||||
|
||||
if (rel_vol > 0.f)
|
||||
{
|
||||
float factor = relative_volume / saved_relative_volume;
|
||||
|
|
@ -287,24 +285,21 @@ MusInfo *MusInfo::GetWaveDumper(const char *filename, int rate)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
static MIDISource *CreateMIDISource(FileReader &reader, EMIDIType miditype)
|
||||
static MIDISource *CreateMIDISource(const uint8_t *data, size_t length, EMIDIType miditype)
|
||||
{
|
||||
MIDISource *source = nullptr;
|
||||
auto data = reader.Read();
|
||||
if (data.Size() <= 0) return nullptr;
|
||||
switch (miditype)
|
||||
{
|
||||
case MIDI_MUS:
|
||||
return new MUSSong2(data.Data(), data.Size());
|
||||
return new MUSSong2(data, length);
|
||||
|
||||
case MIDI_MIDI:
|
||||
return new MIDISong2(data.Data(), data.Size());
|
||||
return new MIDISong2(data, length);
|
||||
|
||||
case MIDI_HMI:
|
||||
return new HMISong(data.Data(), data.Size());
|
||||
return new HMISong(data, length);
|
||||
|
||||
case MIDI_XMI:
|
||||
return new XMISong(data.Data(), data.Size());
|
||||
return new XMISong(data, length);
|
||||
|
||||
default:
|
||||
return nullptr;
|
||||
|
|
@ -378,153 +373,154 @@ static EMIDIType IdentifyMIDIType(uint32_t *id, int size)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
MusInfo *I_RegisterSong (FileReader &reader, MidiDeviceSetting *device)
|
||||
MusInfo *I_RegisterSong (MusicIO::FileInterface *reader, MidiDeviceSetting *device)
|
||||
{
|
||||
MusInfo *info = nullptr;
|
||||
StreamSource *streamsource = nullptr;
|
||||
const char *fmt;
|
||||
uint32_t id[32/4];
|
||||
|
||||
if (nomusic)
|
||||
if(reader->read(id, 32) != 32 || reader->seek(-32, FileReader::SeekCur) != 0)
|
||||
{
|
||||
reader->close();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if(reader.Read(id, 32) != 32 || reader.Seek(-32, FileReader::SeekCur) != 0)
|
||||
try
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Check for gzip compression. Some formats are expected to have players
|
||||
// that can handle it, so it simplifies things if we make all songs
|
||||
// gzippable.
|
||||
if ((id[0] & MAKE_ID(255, 255, 255, 0)) == GZIP_ID)
|
||||
{
|
||||
|
||||
if (!reader.OpenMemoryArray([&reader](TArray<uint8_t> &array)
|
||||
// Check for gzip compression. Some formats are expected to have players
|
||||
// that can handle it, so it simplifies things if we make all songs
|
||||
// gzippable.
|
||||
if ((id[0] & MAKE_ID(255, 255, 255, 0)) == GZIP_ID)
|
||||
{
|
||||
bool res = false;
|
||||
auto len = reader.GetLength();
|
||||
uint8_t *gzipped = new uint8_t[len];
|
||||
if (reader.Read(gzipped, len) == len)
|
||||
// swap out the reader with one that reads the decompressed content.
|
||||
auto zreader = new MusicIO::VectorReader([reader](std::vector<uint8_t>& array)
|
||||
{
|
||||
bool res = false;
|
||||
auto len = reader->filelength();
|
||||
uint8_t* gzipped = new uint8_t[len];
|
||||
if (reader->read(gzipped, len) == len)
|
||||
{
|
||||
res = ungzip(gzipped, (int)len, array);
|
||||
}
|
||||
delete[] gzipped;
|
||||
});
|
||||
reader->close();
|
||||
reader = zreader;
|
||||
|
||||
|
||||
if (reader->read(id, 32) != 32 || reader->seek(-32, FileReader::SeekCur) != 0)
|
||||
{
|
||||
res = ungzip(gzipped, (int)len, array);
|
||||
reader->close();
|
||||
return nullptr;
|
||||
}
|
||||
delete[] gzipped;
|
||||
return res;
|
||||
}))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (reader.Read(id, 32) != 32 || reader.Seek(-32, FileReader::SeekCur) != 0)
|
||||
EMIDIType miditype = IdentifyMIDIType(id, sizeof(id));
|
||||
if (miditype != MIDI_NOTMIDI)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
std::vector<uint8_t> data(reader->filelength());
|
||||
if (reader->read(data.data(), (long)data.size()) != (long)data.size())
|
||||
{
|
||||
reader->close();
|
||||
return nullptr;
|
||||
}
|
||||
auto source = CreateMIDISource(data.data(), data.size(), miditype);
|
||||
if (source == nullptr)
|
||||
{
|
||||
reader->close();
|
||||
return nullptr;
|
||||
}
|
||||
if (!source->isValid())
|
||||
{
|
||||
delete source;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
EMIDIType miditype = IdentifyMIDIType(id, sizeof(id));
|
||||
if (miditype != MIDI_NOTMIDI)
|
||||
{
|
||||
auto source = CreateMIDISource(reader, miditype);
|
||||
if (source == nullptr) return nullptr;
|
||||
if (!source->isValid())
|
||||
{
|
||||
delete source;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
EMidiDevice devtype = device == nullptr? MDEV_DEFAULT : (EMidiDevice)device->device;
|
||||
EMidiDevice devtype = device == nullptr ? MDEV_DEFAULT : (EMidiDevice)device->device;
|
||||
#ifndef _WIN32
|
||||
// non-Windows platforms don't support MDEV_MMAPI so map to MDEV_SNDSYS
|
||||
if (devtype == MDEV_MMAPI)
|
||||
devtype = MDEV_SNDSYS;
|
||||
// non-Windows platforms don't support MDEV_MMAPI so map to MDEV_SNDSYS
|
||||
if (devtype == MDEV_MMAPI)
|
||||
devtype = MDEV_SNDSYS;
|
||||
#endif
|
||||
|
||||
MIDIStreamer *streamer = CreateMIDIStreamer(devtype, device != nullptr? device->args.GetChars() : "");
|
||||
if (streamer == nullptr)
|
||||
{
|
||||
delete source;
|
||||
return nullptr;
|
||||
MIDIStreamer* streamer = CreateMIDIStreamer(devtype, device != nullptr ? device->args.GetChars() : "");
|
||||
if (streamer == nullptr)
|
||||
{
|
||||
delete source;
|
||||
reader->close();
|
||||
return nullptr;
|
||||
}
|
||||
streamer->SetMIDISource(source);
|
||||
info = streamer;
|
||||
}
|
||||
streamer->SetMIDISource(source);
|
||||
info = streamer;
|
||||
}
|
||||
|
||||
// Check for various raw OPL formats
|
||||
else if (
|
||||
(id[0] == MAKE_ID('R','A','W','A') && id[1] == MAKE_ID('D','A','T','A')) || // Rdos Raw OPL
|
||||
(id[0] == MAKE_ID('D','B','R','A') && id[1] == MAKE_ID('W','O','P','L')) || // DosBox Raw OPL
|
||||
(id[0] == MAKE_ID('A','D','L','I') && *((uint8_t *)id + 4) == 'B')) // Martin Fernandez's modified IMF
|
||||
{
|
||||
OPL_SetupConfig(&oplConfig, device->args.GetChars(), false);
|
||||
auto mreader = new FileReaderMusicInterface(reader);
|
||||
streamsource = OPL_OpenSong(mreader, &oplConfig);
|
||||
reader = mreader->GetReader(); // We need to get this back for the rest of this function.
|
||||
delete mreader;
|
||||
}
|
||||
else if ((id[0] == MAKE_ID('R', 'I', 'F', 'F') && id[2] == MAKE_ID('C', 'D', 'X', 'A')))
|
||||
{
|
||||
auto mreader = new FileReaderMusicInterface(reader);
|
||||
streamsource = XA_OpenSong(mreader); // this takes over the reader.
|
||||
}
|
||||
// Check for game music
|
||||
else if ((fmt = GME_CheckFormat(id[0])) != nullptr && fmt[0] != '\0')
|
||||
{
|
||||
auto mreader = new FileReaderMusicInterface(reader);
|
||||
streamsource = GME_OpenSong(mreader, fmt, gme_stereodepth, (int)GSnd->GetOutputRate());
|
||||
reader = mreader->GetReader(); // We need to get this back for the rest of this function.
|
||||
delete mreader;
|
||||
}
|
||||
// Check for module formats
|
||||
else
|
||||
{
|
||||
auto mreader = new FileReaderMusicInterface(reader);
|
||||
Dumb_SetupConfig(&dumbConfig);
|
||||
streamsource = MOD_OpenSong(mreader, &dumbConfig, (int)GSnd->GetOutputRate());
|
||||
reader = mreader->GetReader(); // We need to get this back for the rest of this function.
|
||||
delete mreader;
|
||||
}
|
||||
if (info == nullptr && streamsource == nullptr)
|
||||
{
|
||||
streamsource = SndFile_OpenSong(reader);
|
||||
}
|
||||
|
||||
if (streamsource)
|
||||
{
|
||||
info = OpenStreamSong(streamsource);
|
||||
if (!info)
|
||||
// Check for various raw OPL formats
|
||||
else if (
|
||||
(id[0] == MAKE_ID('R', 'A', 'W', 'A') && id[1] == MAKE_ID('D', 'A', 'T', 'A')) || // Rdos Raw OPL
|
||||
(id[0] == MAKE_ID('D', 'B', 'R', 'A') && id[1] == MAKE_ID('W', 'O', 'P', 'L')) || // DosBox Raw OPL
|
||||
(id[0] == MAKE_ID('A', 'D', 'L', 'I') && *((uint8_t*)id + 4) == 'B')) // Martin Fernandez's modified IMF
|
||||
{
|
||||
// If this fails we have no more valid data - but it couldn't be a CDDA file anyway.
|
||||
return nullptr;
|
||||
OPL_SetupConfig(&oplConfig, device->args.GetChars(), false);
|
||||
streamsource = OPL_OpenSong(reader, &oplConfig);
|
||||
}
|
||||
else if ((id[0] == MAKE_ID('R', 'I', 'F', 'F') && id[2] == MAKE_ID('C', 'D', 'X', 'A')))
|
||||
{
|
||||
streamsource = XA_OpenSong(reader); // this takes over the reader.
|
||||
reader = nullptr; // We do not own this anymore.
|
||||
}
|
||||
// Check for game music
|
||||
else if ((fmt = GME_CheckFormat(id[0])) != nullptr && fmt[0] != '\0')
|
||||
{
|
||||
streamsource = GME_OpenSong(reader, fmt, gme_stereodepth, (int)GSnd->GetOutputRate());
|
||||
}
|
||||
// Check for module formats
|
||||
else
|
||||
{
|
||||
Dumb_SetupConfig(&dumbConfig);
|
||||
streamsource = MOD_OpenSong(reader, &dumbConfig, (int)GSnd->GetOutputRate());
|
||||
}
|
||||
if (info == nullptr && streamsource == nullptr)
|
||||
{
|
||||
streamsource = SndFile_OpenSong(reader); // this only takes over the reader if it succeeds. We need to look out for this.
|
||||
if (streamsource != nullptr) reader = nullptr;
|
||||
}
|
||||
|
||||
if (streamsource)
|
||||
{
|
||||
info = OpenStreamSong(streamsource);
|
||||
}
|
||||
if (info == nullptr && reader != nullptr)
|
||||
{
|
||||
// Check for CDDA "format"
|
||||
if (id[0] == (('R') | (('I') << 8) | (('F') << 16) | (('F') << 24)))
|
||||
{
|
||||
uint32_t subid;
|
||||
|
||||
reader->seek(8, SEEK_CUR);
|
||||
if (reader->read(&subid, 4) == 4)
|
||||
{
|
||||
reader->seek(-12, SEEK_CUR);
|
||||
|
||||
if (subid == (('C') | (('D') << 8) | (('D') << 16) | (('A') << 24)))
|
||||
{
|
||||
// This is a CDDA file
|
||||
info = new CDDAFile(reader);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (info && !info->IsValid())
|
||||
{
|
||||
delete info;
|
||||
info = nullptr;
|
||||
}
|
||||
}
|
||||
if (info == nullptr)
|
||||
{
|
||||
// Check for CDDA "format"
|
||||
if (id[0] == (('R')|(('I')<<8)|(('F')<<16)|(('F')<<24)))
|
||||
{
|
||||
uint32_t subid;
|
||||
|
||||
reader.Seek(8, FileReader::SeekCur);
|
||||
if (reader.Read (&subid, 4) != 4)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
reader.Seek(-12, FileReader::SeekCur);
|
||||
|
||||
if (subid == (('C')|(('D')<<8)|(('D')<<16)|(('A')<<24)))
|
||||
{
|
||||
// This is a CDDA file
|
||||
info = new CDDAFile (reader);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (info && !info->IsValid ())
|
||||
catch (...)
|
||||
{
|
||||
delete info;
|
||||
info = nullptr;
|
||||
// Make sure the reader is closed if this function abnormally terminates
|
||||
if (reader) reader->close();
|
||||
throw;
|
||||
}
|
||||
|
||||
return info;
|
||||
|
|
@ -558,7 +554,7 @@ MusInfo *I_RegisterCDSong (int track, int id)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
static bool ungzip(uint8_t *data, int complen, TArray<uint8_t> &newdata)
|
||||
static bool ungzip(uint8_t *data, int complen, std::vector<uint8_t> &newdata)
|
||||
{
|
||||
const uint8_t *max = data + complen - 8;
|
||||
const uint8_t *compstart = data + 10;
|
||||
|
|
@ -597,7 +593,7 @@ static bool ungzip(uint8_t *data, int complen, TArray<uint8_t> &newdata)
|
|||
|
||||
// Decompress
|
||||
isize = LittleLong(*(uint32_t *)(data + complen - 4));
|
||||
newdata.Resize(isize);
|
||||
newdata.resize(isize);
|
||||
|
||||
stream.next_in = (Bytef *)compstart;
|
||||
stream.avail_in = (uInt)(max - compstart);
|
||||
|
|
@ -705,6 +701,7 @@ static MIDISource *GetMIDISource(const char *fn)
|
|||
}
|
||||
|
||||
auto wlump = Wads.OpenLumpReader(lump);
|
||||
|
||||
uint32_t id[32 / 4];
|
||||
|
||||
if (wlump.Read(id, 32) != 32 || wlump.Seek(-32, FileReader::SeekCur) != 0)
|
||||
|
|
@ -712,9 +709,15 @@ static MIDISource *GetMIDISource(const char *fn)
|
|||
Printf("Unable to read lump %s\n", src.GetChars());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto type = IdentifyMIDIType(id, 32);
|
||||
auto source = CreateMIDISource(wlump, type);
|
||||
if (type == MIDI_NOTMIDI)
|
||||
{
|
||||
Printf("%s is not MIDI-based.\n", src.GetChars());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto data = wlump.Read();
|
||||
auto source = CreateMIDISource(data.Data(), data.Size(), type);
|
||||
|
||||
if (source == nullptr)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ void I_SetMusicVolume (double volume);
|
|||
// Registers a song handle to song data.
|
||||
class MusInfo;
|
||||
struct MidiDeviceSetting;
|
||||
MusInfo *I_RegisterSong (FileReader &reader, MidiDeviceSetting *device);
|
||||
MusInfo *I_RegisterSong (MusicIO::FileInterface *reader, MidiDeviceSetting *device);
|
||||
MusInfo *I_RegisterCDSong (int track, int cdid = 0);
|
||||
|
||||
// The base music class. Everything is derived from this --------------------
|
||||
|
|
|
|||
|
|
@ -134,7 +134,7 @@ protected:
|
|||
class CDDAFile : public CDSong
|
||||
{
|
||||
public:
|
||||
CDDAFile (FileReader &reader);
|
||||
CDDAFile (MusicIO::FileInterface *reader);
|
||||
};
|
||||
|
||||
// Data interface
|
||||
|
|
@ -154,7 +154,7 @@ class StreamSource;
|
|||
|
||||
StreamSource *MOD_OpenSong(MusicIO::FileInterface* reader, DumbConfig* config, int samplerate);
|
||||
StreamSource* GME_OpenSong(MusicIO::FileInterface* reader, const char* fmt, float stereo_depth, int sample_rate);
|
||||
StreamSource *SndFile_OpenSong(FileReader &fr);
|
||||
StreamSource *SndFile_OpenSong(MusicIO::FileInterface* fr);
|
||||
StreamSource* XA_OpenSong(MusicIO::FileInterface* reader);
|
||||
StreamSource* OPL_OpenSong(MusicIO::FileInterface* reader, OPLConfig *config);
|
||||
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@
|
|||
#include "cmdlib.h"
|
||||
#include "i_system.h"
|
||||
#include "gameconfigfile.h"
|
||||
#include "filereadermusicinterface.h"
|
||||
#include "resourcefiles/resourcefile.h"
|
||||
#include "../libraries/timidityplus/timiditypp/common.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
#include "doomtype.h"
|
||||
#include "w_wad.h"
|
||||
#include "files.h"
|
||||
#include "../libraries/music_common/fileio.h"
|
||||
#include "filereadermusicinterface.h"
|
||||
|
||||
enum
|
||||
{
|
||||
|
|
@ -21,45 +21,6 @@ struct FSoundFontInfo
|
|||
int type;
|
||||
};
|
||||
|
||||
struct FileReaderMusicInterface : public MusicIO::FileInterface
|
||||
{
|
||||
FileReader fr;
|
||||
|
||||
FileReaderMusicInterface(FileReader& fr_in)
|
||||
{
|
||||
fr = std::move(fr_in);
|
||||
}
|
||||
char* gets(char* buff, int n) override
|
||||
{
|
||||
if (!fr.isOpen()) return nullptr;
|
||||
return fr.Gets(buff, n);
|
||||
}
|
||||
long read(void* buff, int32_t size, int32_t nitems) override
|
||||
{
|
||||
if (!fr.isOpen()) return 0;
|
||||
return (long)fr.Read(buff, size * nitems) / size;
|
||||
}
|
||||
long seek(long offset, int whence) override
|
||||
{
|
||||
if (!fr.isOpen()) return 0;
|
||||
return (long)fr.Seek(offset, (FileReader::ESeek)whence);
|
||||
}
|
||||
long tell() override
|
||||
{
|
||||
if (!fr.isOpen()) return 0;
|
||||
return (long)fr.Tell();
|
||||
}
|
||||
void close()
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
FileReader &&GetReader()
|
||||
{
|
||||
return std::move(fr);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
|
|
|
|||
|
|
@ -111,33 +111,33 @@ bool CDSong::IsPlaying ()
|
|||
return m_Status != STATE_Stopped;
|
||||
}
|
||||
|
||||
CDDAFile::CDDAFile (FileReader &reader)
|
||||
CDDAFile::CDDAFile (MusicIO::FileInterface* reader)
|
||||
: CDSong ()
|
||||
{
|
||||
uint32_t chunk;
|
||||
uint16_t track;
|
||||
uint32_t discid;
|
||||
auto endpos = reader.Tell() + reader.GetLength() - 8;
|
||||
auto endpos = reader->tell() + reader->filelength() - 8;
|
||||
|
||||
// I_RegisterSong already identified this as a CDDA file, so we
|
||||
// just need to check the contents we're interested in.
|
||||
reader.Seek(12, FileReader::SeekCur);
|
||||
reader->seek(12, SEEK_CUR);
|
||||
|
||||
while (reader.Tell() < endpos)
|
||||
while (reader->tell() < endpos)
|
||||
{
|
||||
reader.Read(&chunk, 4);
|
||||
reader->read(&chunk, 4);
|
||||
if (chunk != (('f')|(('m')<<8)|(('t')<<16)|((' ')<<24)))
|
||||
{
|
||||
reader.Read(&chunk, 4);
|
||||
reader.Seek(chunk, FileReader::SeekCur);
|
||||
reader->read(&chunk, 4);
|
||||
reader->seek(LittleLong(chunk), SEEK_CUR);
|
||||
}
|
||||
else
|
||||
{
|
||||
reader.Seek(6, FileReader::SeekCur);
|
||||
reader.Read(&track, 2);
|
||||
reader.Read(&discid, 4);
|
||||
reader->seek(6, SEEK_CUR);
|
||||
reader->read(&track, 2);
|
||||
reader->read(&discid, 4);
|
||||
|
||||
if (CD_InitID (discid) && CD_CheckTrack (track))
|
||||
if (CD_InitID (LittleLong(discid)) && CD_CheckTrack (LittleShort(track)))
|
||||
{
|
||||
m_Inited = true;
|
||||
m_Track = track;
|
||||
|
|
|
|||
|
|
@ -785,9 +785,7 @@ StreamSource* MOD_OpenSong(MusicIO::FileInterface *reader, DumbConfig* config, i
|
|||
bool is_dos = true;
|
||||
|
||||
auto fpos = reader->tell();
|
||||
reader->seek(0, SEEK_END);
|
||||
int size = (int)reader->tell();
|
||||
reader->seek(fpos, SEEK_SET);
|
||||
int size = (int)reader->filelength();
|
||||
|
||||
filestate.ptr = start;
|
||||
filestate.offset = 0;
|
||||
|
|
|
|||
|
|
@ -124,9 +124,8 @@ StreamSource *GME_OpenSong(MusicIO::FileInterface *reader, const char *fmt, floa
|
|||
}
|
||||
|
||||
auto fpos = reader->tell();
|
||||
reader->seek(0, SEEK_END);
|
||||
auto len = reader->tell();
|
||||
reader->seek(fpos, SEEK_SET);
|
||||
auto len = reader->filelength();
|
||||
|
||||
song = new uint8_t[len];
|
||||
if (reader->read(song, len) != len)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@
|
|||
#include "templates.h"
|
||||
#include "m_fixed.h"
|
||||
#include "streamsource.h"
|
||||
#include "zmusic/sounddecoder.h"
|
||||
|
||||
// MACROS ------------------------------------------------------------------
|
||||
|
||||
|
|
@ -48,7 +49,7 @@
|
|||
class SndFileSong : public StreamSource
|
||||
{
|
||||
public:
|
||||
SndFileSong(FileReader &reader, SoundDecoder *decoder, uint32_t loop_start, uint32_t loop_end, bool startass, bool endass);
|
||||
SndFileSong(SoundDecoder *decoder, uint32_t loop_start, uint32_t loop_end, bool startass, bool endass);
|
||||
~SndFileSong();
|
||||
std::string GetStats() override;
|
||||
SoundStreamInfo GetFormat() override;
|
||||
|
|
@ -56,7 +57,6 @@ public:
|
|||
|
||||
protected:
|
||||
std::mutex CritSec;
|
||||
FileReader Reader;
|
||||
SoundDecoder *Decoder;
|
||||
int Channels;
|
||||
int SampleRate;
|
||||
|
|
@ -103,23 +103,23 @@ CUSTOM_CVAR(Int, snd_streambuffersize, 64, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
static void ParseVorbisComments(FileReader &fr, uint32_t *start, bool *startass, uint32_t *end, bool *endass)
|
||||
static void ParseVorbisComments(MusicIO::FileInterface *fr, uint32_t *start, bool *startass, uint32_t *end, bool *endass)
|
||||
{
|
||||
uint8_t vc_data[4];
|
||||
|
||||
// The VC block starts with a 32LE integer for the vendor string length,
|
||||
// followed by the vendor string
|
||||
if(fr.Read(vc_data, 4) != 4)
|
||||
if(fr->read(vc_data, 4) != 4)
|
||||
return;
|
||||
uint32_t vndr_len = vc_data[0] | (vc_data[1]<<8) | (vc_data[2]<<16) | (vc_data[3]<<24);
|
||||
|
||||
// Skip vendor string
|
||||
if(fr.Seek(vndr_len, FileReader::SeekCur) == -1)
|
||||
if(fr->seek(vndr_len, SEEK_CUR) == -1)
|
||||
return;
|
||||
|
||||
// Following the vendor string is a 32LE integer for the number of
|
||||
// comments, followed by each comment.
|
||||
if(fr.Read(vc_data, 4) != 4)
|
||||
if(fr->read(vc_data, 4) != 4)
|
||||
return;
|
||||
size_t count = vc_data[0] | (vc_data[1]<<8) | (vc_data[2]<<16) | (vc_data[3]<<24);
|
||||
|
||||
|
|
@ -127,20 +127,20 @@ static void ParseVorbisComments(FileReader &fr, uint32_t *start, bool *startass,
|
|||
{
|
||||
// Each comment is a 32LE integer for the comment length, followed by
|
||||
// the comment text (not null terminated!)
|
||||
if(fr.Read(vc_data, 4) != 4)
|
||||
if(fr->read(vc_data, 4) != 4)
|
||||
return;
|
||||
uint32_t length = vc_data[0] | (vc_data[1]<<8) | (vc_data[2]<<16) | (vc_data[3]<<24);
|
||||
|
||||
if(length >= 128)
|
||||
{
|
||||
// If the comment is "big", skip it
|
||||
if(fr.Seek(length, FileReader::SeekCur) == -1)
|
||||
if(fr->seek(length, SEEK_CUR) == -1)
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
|
||||
char strdat[128];
|
||||
if(fr.Read(strdat, length) != (long)length)
|
||||
if(fr->read(strdat, length) != (long)length)
|
||||
return;
|
||||
strdat[length] = 0;
|
||||
|
||||
|
|
@ -151,13 +151,13 @@ static void ParseVorbisComments(FileReader &fr, uint32_t *start, bool *startass,
|
|||
}
|
||||
}
|
||||
|
||||
static void FindFlacComments(FileReader &fr, uint32_t *loop_start, bool *startass, uint32_t *loop_end, bool *endass)
|
||||
static void FindFlacComments(MusicIO::FileInterface *fr, uint32_t *loop_start, bool *startass, uint32_t *loop_end, bool *endass)
|
||||
{
|
||||
// Already verified the fLaC marker, so we're 4 bytes into the file
|
||||
bool lastblock = false;
|
||||
uint8_t header[4];
|
||||
|
||||
while(!lastblock && fr.Read(header, 4) == 4)
|
||||
while(!lastblock && fr->read(header, 4) == 4)
|
||||
{
|
||||
// The first byte of the block header contains the type and a flag
|
||||
// indicating the last metadata block
|
||||
|
|
@ -173,18 +173,18 @@ static void FindFlacComments(FileReader &fr, uint32_t *loop_start, bool *startas
|
|||
return;
|
||||
}
|
||||
|
||||
if(fr.Seek(blocksize, FileReader::SeekCur) == -1)
|
||||
if(fr->seek(blocksize, SEEK_CUR) == -1)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void FindOggComments(FileReader &fr, uint32_t *loop_start, bool *startass, uint32_t *loop_end, bool *endass)
|
||||
static void FindOggComments(MusicIO::FileInterface *fr, uint32_t *loop_start, bool *startass, uint32_t *loop_end, bool *endass)
|
||||
{
|
||||
uint8_t ogghead[27];
|
||||
|
||||
// We already read and verified the OggS marker, so skip the first 4 bytes
|
||||
// of the Ogg page header.
|
||||
while(fr.Read(ogghead+4, 23) == 23)
|
||||
while(fr->read(ogghead+4, 23) == 23)
|
||||
{
|
||||
// The 19th byte of the Ogg header is a 32LE integer for the page
|
||||
// number, and the 27th is a uint8 for the number of segments in the
|
||||
|
|
@ -197,7 +197,7 @@ static void FindOggComments(FileReader &fr, uint32_t *loop_start, bool *startass
|
|||
// each segment in the page. The page segment data follows contiguously
|
||||
// after.
|
||||
uint8_t segsizes[256];
|
||||
if(fr.Read(segsizes, ogg_segments) != ogg_segments)
|
||||
if(fr->read(segsizes, ogg_segments) != ogg_segments)
|
||||
break;
|
||||
|
||||
// Find the segment with the Vorbis Comment packet (type 3)
|
||||
|
|
@ -208,7 +208,7 @@ static void FindOggComments(FileReader &fr, uint32_t *loop_start, bool *startass
|
|||
if(segsize > 16)
|
||||
{
|
||||
uint8_t vorbhead[7];
|
||||
if(fr.Read(vorbhead, 7) != 7)
|
||||
if(fr->read(vorbhead, 7) != 7)
|
||||
return;
|
||||
|
||||
if(vorbhead[0] == 3 && memcmp(vorbhead+1, "vorbis", 6) == 0)
|
||||
|
|
@ -235,7 +235,7 @@ static void FindOggComments(FileReader &fr, uint32_t *loop_start, bool *startass
|
|||
|
||||
segsize -= 7;
|
||||
}
|
||||
if(fr.Seek(segsize, FileReader::SeekCur) == -1)
|
||||
if(fr->seek(segsize, SEEK_CUR) == -1)
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -243,16 +243,16 @@ static void FindOggComments(FileReader &fr, uint32_t *loop_start, bool *startass
|
|||
if(ogg_pagenum >= 2)
|
||||
break;
|
||||
|
||||
if(fr.Read(ogghead, 4) != 4 || memcmp(ogghead, "OggS", 4) != 0)
|
||||
if(fr->read(ogghead, 4) != 4 || memcmp(ogghead, "OggS", 4) != 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void FindLoopTags(FileReader &fr, uint32_t *start, bool *startass, uint32_t *end, bool *endass)
|
||||
void FindLoopTags(MusicIO::FileInterface *fr, uint32_t *start, bool *startass, uint32_t *end, bool *endass)
|
||||
{
|
||||
uint8_t signature[4];
|
||||
|
||||
fr.Read(signature, 4);
|
||||
fr->read(signature, 4);
|
||||
if(memcmp(signature, "fLaC", 4) == 0)
|
||||
FindFlacComments(fr, start, startass, end, endass);
|
||||
else if(memcmp(signature, "OggS", 4) == 0)
|
||||
|
|
@ -266,18 +266,18 @@ void FindLoopTags(FileReader &fr, uint32_t *start, bool *startass, uint32_t *end
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
StreamSource *SndFile_OpenSong(FileReader &fr)
|
||||
StreamSource *SndFile_OpenSong(MusicIO::FileInterface *fr)
|
||||
{
|
||||
fr.Seek(0, FileReader::SeekSet);
|
||||
fr->seek(0, SEEK_SET);
|
||||
|
||||
uint32_t loop_start = 0, loop_end = ~0u;
|
||||
bool startass = false, endass = false;
|
||||
FindLoopTags(fr, &loop_start, &startass, &loop_end, &endass);
|
||||
|
||||
fr.Seek(0, FileReader::SeekSet);
|
||||
auto decoder = SoundRenderer::CreateDecoder(fr);
|
||||
if (decoder == nullptr) return nullptr;
|
||||
return new SndFileSong(fr, decoder, loop_start, loop_end, startass, endass);
|
||||
fr->seek(0, FileReader::SeekSet);
|
||||
auto decoder = SoundDecoder::CreateDecoder(fr);
|
||||
if (decoder == nullptr) return nullptr; // If this fails the file reader has not been taken over and the caller needs to clean up. This is to allow further analysis of the passed file.
|
||||
return new SndFileSong(decoder, loop_start, loop_end, startass, endass);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
|
@ -286,7 +286,7 @@ StreamSource *SndFile_OpenSong(FileReader &fr)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
SndFileSong::SndFileSong(FileReader &reader, SoundDecoder *decoder, uint32_t loop_start, uint32_t loop_end, bool startass, bool endass)
|
||||
SndFileSong::SndFileSong(SoundDecoder *decoder, uint32_t loop_start, uint32_t loop_end, bool startass, bool endass)
|
||||
{
|
||||
ChannelConfig iChannels;
|
||||
SampleType Type;
|
||||
|
|
@ -299,7 +299,6 @@ SndFileSong::SndFileSong(FileReader &reader, SoundDecoder *decoder, uint32_t loo
|
|||
const uint32_t sampleLength = (uint32_t)decoder->getSampleLength();
|
||||
Loop_Start = loop_start;
|
||||
Loop_End = sampleLength == 0 ? loop_end : clamp<uint32_t>(loop_end, 0, sampleLength);
|
||||
Reader = std::move(reader);
|
||||
Decoder = decoder;
|
||||
Channels = iChannels == ChannelConfig_Stereo? 2:1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -85,6 +85,7 @@
|
|||
#include "g_game.h"
|
||||
#include "atterm.h"
|
||||
#include "s_music.h"
|
||||
#include "filereadermusicinterface.h"
|
||||
|
||||
// MACROS ------------------------------------------------------------------
|
||||
|
||||
|
|
@ -304,6 +305,7 @@ bool S_StartMusic (const char *m_id)
|
|||
|
||||
bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force)
|
||||
{
|
||||
if (nomusic) return false; // skip the entire procedure if music is globally disabled.
|
||||
if (!force && PlayList)
|
||||
{ // Don't change if a playlist is active
|
||||
return false;
|
||||
|
|
@ -457,7 +459,8 @@ bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force)
|
|||
{
|
||||
try
|
||||
{
|
||||
mus_playing.handle = I_RegisterSong(reader, devp);
|
||||
auto mreader = new FileReaderMusicInterface(reader);
|
||||
mus_playing.handle = I_RegisterSong(mreader, devp);
|
||||
}
|
||||
catch (const std::runtime_error& err)
|
||||
{
|
||||
|
|
@ -647,6 +650,10 @@ CCMD (idmus)
|
|||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Printf("Music is disabled\n");
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
|
@ -681,6 +688,10 @@ CCMD (changemus)
|
|||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Printf("Music is disabled\n");
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
|
|
|||
|
|
@ -1532,7 +1532,7 @@ static void S_LoadSound3D(sfxinfo_t *sfx, FSoundLoadBuffer *pBuffer)
|
|||
|
||||
std::pair<SoundHandle, bool> snd;
|
||||
|
||||
if (pBuffer->mBuffer.Size() > 0)
|
||||
if (pBuffer->mBuffer.size() > 0)
|
||||
{
|
||||
snd = GSnd->LoadSoundBuffered(pBuffer, true);
|
||||
}
|
||||
|
|
|
|||
1202
src/sound/thirdparty/mpg123.h
vendored
1202
src/sound/thirdparty/mpg123.h
vendored
File diff suppressed because it is too large
Load diff
667
src/sound/thirdparty/sndfile.h
vendored
667
src/sound/thirdparty/sndfile.h
vendored
|
|
@ -1,667 +0,0 @@
|
|||
/*
|
||||
** Copyright (C) 1999-2011Erik de Castro Lopo <erikd@mega-nerd.com>
|
||||
**
|
||||
** This program 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 program 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 program; if not, write to the Free Software
|
||||
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
** sndfile.h -- system-wide definitions
|
||||
**
|
||||
** API documentation is in the doc/ directory of the source code tarball
|
||||
** and at http://www.mega-nerd.com/libsndfile/api.html.
|
||||
*/
|
||||
|
||||
#ifndef SNDFILE_H
|
||||
#define SNDFILE_H
|
||||
|
||||
/* This is the version 1.0.X header file. */
|
||||
#define SNDFILE_1
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/* The following file types can be read and written.
|
||||
** A file type would consist of a major type (ie SF_FORMAT_WAV) bitwise
|
||||
** ORed with a minor type (ie SF_FORMAT_PCM). SF_FORMAT_TYPEMASK and
|
||||
** SF_FORMAT_SUBMASK can be used to separate the major and minor file
|
||||
** types.
|
||||
*/
|
||||
|
||||
enum
|
||||
{ /* Major formats. */
|
||||
SF_FORMAT_WAV = 0x010000, /* Microsoft WAV format (little endian default). */
|
||||
SF_FORMAT_AIFF = 0x020000, /* Apple/SGI AIFF format (big endian). */
|
||||
SF_FORMAT_AU = 0x030000, /* Sun/NeXT AU format (big endian). */
|
||||
SF_FORMAT_RAW = 0x040000, /* RAW PCM data. */
|
||||
SF_FORMAT_PAF = 0x050000, /* Ensoniq PARIS file format. */
|
||||
SF_FORMAT_SVX = 0x060000, /* Amiga IFF / SVX8 / SV16 format. */
|
||||
SF_FORMAT_NIST = 0x070000, /* Sphere NIST format. */
|
||||
SF_FORMAT_VOC = 0x080000, /* VOC files. */
|
||||
SF_FORMAT_IRCAM = 0x0A0000, /* Berkeley/IRCAM/CARL */
|
||||
SF_FORMAT_W64 = 0x0B0000, /* Sonic Foundry's 64 bit RIFF/WAV */
|
||||
SF_FORMAT_MAT4 = 0x0C0000, /* Matlab (tm) V4.2 / GNU Octave 2.0 */
|
||||
SF_FORMAT_MAT5 = 0x0D0000, /* Matlab (tm) V5.0 / GNU Octave 2.1 */
|
||||
SF_FORMAT_PVF = 0x0E0000, /* Portable Voice Format */
|
||||
SF_FORMAT_XI = 0x0F0000, /* Fasttracker 2 Extended Instrument */
|
||||
SF_FORMAT_HTK = 0x100000, /* HMM Tool Kit format */
|
||||
SF_FORMAT_SDS = 0x110000, /* Midi Sample Dump Standard */
|
||||
SF_FORMAT_AVR = 0x120000, /* Audio Visual Research */
|
||||
SF_FORMAT_WAVEX = 0x130000, /* MS WAVE with WAVEFORMATEX */
|
||||
SF_FORMAT_SD2 = 0x160000, /* Sound Designer 2 */
|
||||
SF_FORMAT_FLAC = 0x170000, /* FLAC lossless file format */
|
||||
SF_FORMAT_CAF = 0x180000, /* Core Audio File format */
|
||||
SF_FORMAT_WVE = 0x190000, /* Psion WVE format */
|
||||
SF_FORMAT_OGG = 0x200000, /* Xiph OGG container */
|
||||
SF_FORMAT_MPC2K = 0x210000, /* Akai MPC 2000 sampler */
|
||||
SF_FORMAT_RF64 = 0x220000, /* RF64 WAV file */
|
||||
|
||||
/* Subtypes from here on. */
|
||||
|
||||
SF_FORMAT_PCM_S8 = 0x0001, /* Signed 8 bit data */
|
||||
SF_FORMAT_PCM_16 = 0x0002, /* Signed 16 bit data */
|
||||
SF_FORMAT_PCM_24 = 0x0003, /* Signed 24 bit data */
|
||||
SF_FORMAT_PCM_32 = 0x0004, /* Signed 32 bit data */
|
||||
|
||||
SF_FORMAT_PCM_U8 = 0x0005, /* Unsigned 8 bit data (WAV and RAW only) */
|
||||
|
||||
SF_FORMAT_FLOAT = 0x0006, /* 32 bit float data */
|
||||
SF_FORMAT_DOUBLE = 0x0007, /* 64 bit float data */
|
||||
|
||||
SF_FORMAT_ULAW = 0x0010, /* U-Law encoded. */
|
||||
SF_FORMAT_ALAW = 0x0011, /* A-Law encoded. */
|
||||
SF_FORMAT_IMA_ADPCM = 0x0012, /* IMA ADPCM. */
|
||||
SF_FORMAT_MS_ADPCM = 0x0013, /* Microsoft ADPCM. */
|
||||
|
||||
SF_FORMAT_GSM610 = 0x0020, /* GSM 6.10 encoding. */
|
||||
SF_FORMAT_VOX_ADPCM = 0x0021, /* OKI / Dialogix ADPCM */
|
||||
|
||||
SF_FORMAT_G721_32 = 0x0030, /* 32kbs G721 ADPCM encoding. */
|
||||
SF_FORMAT_G723_24 = 0x0031, /* 24kbs G723 ADPCM encoding. */
|
||||
SF_FORMAT_G723_40 = 0x0032, /* 40kbs G723 ADPCM encoding. */
|
||||
|
||||
SF_FORMAT_DWVW_12 = 0x0040, /* 12 bit Delta Width Variable Word encoding. */
|
||||
SF_FORMAT_DWVW_16 = 0x0041, /* 16 bit Delta Width Variable Word encoding. */
|
||||
SF_FORMAT_DWVW_24 = 0x0042, /* 24 bit Delta Width Variable Word encoding. */
|
||||
SF_FORMAT_DWVW_N = 0x0043, /* N bit Delta Width Variable Word encoding. */
|
||||
|
||||
SF_FORMAT_DPCM_8 = 0x0050, /* 8 bit differential PCM (XI only) */
|
||||
SF_FORMAT_DPCM_16 = 0x0051, /* 16 bit differential PCM (XI only) */
|
||||
|
||||
SF_FORMAT_VORBIS = 0x0060, /* Xiph Vorbis encoding. */
|
||||
|
||||
/* Endian-ness options. */
|
||||
|
||||
SF_ENDIAN_FILE = 0x00000000, /* Default file endian-ness. */
|
||||
SF_ENDIAN_LITTLE = 0x10000000, /* Force little endian-ness. */
|
||||
SF_ENDIAN_BIG = 0x20000000, /* Force big endian-ness. */
|
||||
SF_ENDIAN_CPU = 0x30000000, /* Force CPU endian-ness. */
|
||||
|
||||
SF_FORMAT_SUBMASK = 0x0000FFFF,
|
||||
SF_FORMAT_TYPEMASK = 0x0FFF0000,
|
||||
SF_FORMAT_ENDMASK = 0x30000000
|
||||
} ;
|
||||
|
||||
/*
|
||||
** The following are the valid command numbers for the sf_command()
|
||||
** interface. The use of these commands is documented in the file
|
||||
** command.html in the doc directory of the source code distribution.
|
||||
*/
|
||||
|
||||
enum
|
||||
{ SFC_GET_LIB_VERSION = 0x1000,
|
||||
SFC_GET_LOG_INFO = 0x1001,
|
||||
SFC_GET_CURRENT_SF_INFO = 0x1002,
|
||||
|
||||
|
||||
SFC_GET_NORM_DOUBLE = 0x1010,
|
||||
SFC_GET_NORM_FLOAT = 0x1011,
|
||||
SFC_SET_NORM_DOUBLE = 0x1012,
|
||||
SFC_SET_NORM_FLOAT = 0x1013,
|
||||
SFC_SET_SCALE_FLOAT_INT_READ = 0x1014,
|
||||
SFC_SET_SCALE_INT_FLOAT_WRITE = 0x1015,
|
||||
|
||||
SFC_GET_SIMPLE_FORMAT_COUNT = 0x1020,
|
||||
SFC_GET_SIMPLE_FORMAT = 0x1021,
|
||||
|
||||
SFC_GET_FORMAT_INFO = 0x1028,
|
||||
|
||||
SFC_GET_FORMAT_MAJOR_COUNT = 0x1030,
|
||||
SFC_GET_FORMAT_MAJOR = 0x1031,
|
||||
SFC_GET_FORMAT_SUBTYPE_COUNT = 0x1032,
|
||||
SFC_GET_FORMAT_SUBTYPE = 0x1033,
|
||||
|
||||
SFC_CALC_SIGNAL_MAX = 0x1040,
|
||||
SFC_CALC_NORM_SIGNAL_MAX = 0x1041,
|
||||
SFC_CALC_MAX_ALL_CHANNELS = 0x1042,
|
||||
SFC_CALC_NORM_MAX_ALL_CHANNELS = 0x1043,
|
||||
SFC_GET_SIGNAL_MAX = 0x1044,
|
||||
SFC_GET_MAX_ALL_CHANNELS = 0x1045,
|
||||
|
||||
SFC_SET_ADD_PEAK_CHUNK = 0x1050,
|
||||
SFC_SET_ADD_HEADER_PAD_CHUNK = 0x1051,
|
||||
|
||||
SFC_UPDATE_HEADER_NOW = 0x1060,
|
||||
SFC_SET_UPDATE_HEADER_AUTO = 0x1061,
|
||||
|
||||
SFC_FILE_TRUNCATE = 0x1080,
|
||||
|
||||
SFC_SET_RAW_START_OFFSET = 0x1090,
|
||||
|
||||
SFC_SET_DITHER_ON_WRITE = 0x10A0,
|
||||
SFC_SET_DITHER_ON_READ = 0x10A1,
|
||||
|
||||
SFC_GET_DITHER_INFO_COUNT = 0x10A2,
|
||||
SFC_GET_DITHER_INFO = 0x10A3,
|
||||
|
||||
SFC_GET_EMBED_FILE_INFO = 0x10B0,
|
||||
|
||||
SFC_SET_CLIPPING = 0x10C0,
|
||||
SFC_GET_CLIPPING = 0x10C1,
|
||||
|
||||
SFC_GET_INSTRUMENT = 0x10D0,
|
||||
SFC_SET_INSTRUMENT = 0x10D1,
|
||||
|
||||
SFC_GET_LOOP_INFO = 0x10E0,
|
||||
|
||||
SFC_GET_BROADCAST_INFO = 0x10F0,
|
||||
SFC_SET_BROADCAST_INFO = 0x10F1,
|
||||
|
||||
SFC_GET_CHANNEL_MAP_INFO = 0x1100,
|
||||
SFC_SET_CHANNEL_MAP_INFO = 0x1101,
|
||||
|
||||
SFC_RAW_DATA_NEEDS_ENDSWAP = 0x1110,
|
||||
|
||||
/* Support for Wavex Ambisonics Format */
|
||||
SFC_WAVEX_SET_AMBISONIC = 0x1200,
|
||||
SFC_WAVEX_GET_AMBISONIC = 0x1201,
|
||||
|
||||
SFC_SET_VBR_ENCODING_QUALITY = 0x1300,
|
||||
|
||||
/* Following commands for testing only. */
|
||||
SFC_TEST_IEEE_FLOAT_REPLACE = 0x6001,
|
||||
|
||||
/*
|
||||
** SFC_SET_ADD_* values are deprecated and will disappear at some
|
||||
** time in the future. They are guaranteed to be here up to and
|
||||
** including version 1.0.8 to avoid breakage of existng software.
|
||||
** They currently do nothing and will continue to do nothing.
|
||||
*/
|
||||
SFC_SET_ADD_DITHER_ON_WRITE = 0x1070,
|
||||
SFC_SET_ADD_DITHER_ON_READ = 0x1071
|
||||
} ;
|
||||
|
||||
|
||||
/*
|
||||
** String types that can be set and read from files. Not all file types
|
||||
** support this and even the file types which support one, may not support
|
||||
** all string types.
|
||||
*/
|
||||
|
||||
enum
|
||||
{ SF_STR_TITLE = 0x01,
|
||||
SF_STR_COPYRIGHT = 0x02,
|
||||
SF_STR_SOFTWARE = 0x03,
|
||||
SF_STR_ARTIST = 0x04,
|
||||
SF_STR_COMMENT = 0x05,
|
||||
SF_STR_DATE = 0x06,
|
||||
SF_STR_ALBUM = 0x07,
|
||||
SF_STR_LICENSE = 0x08,
|
||||
SF_STR_TRACKNUMBER = 0x09,
|
||||
SF_STR_GENRE = 0x10
|
||||
} ;
|
||||
|
||||
/*
|
||||
** Use the following as the start and end index when doing metadata
|
||||
** transcoding.
|
||||
*/
|
||||
|
||||
#define SF_STR_FIRST SF_STR_TITLE
|
||||
#define SF_STR_LAST SF_STR_GENRE
|
||||
|
||||
enum
|
||||
{ /* True and false */
|
||||
SF_FALSE = 0,
|
||||
SF_TRUE = 1,
|
||||
|
||||
/* Modes for opening files. */
|
||||
SFM_READ = 0x10,
|
||||
SFM_WRITE = 0x20,
|
||||
SFM_RDWR = 0x30,
|
||||
|
||||
SF_AMBISONIC_NONE = 0x40,
|
||||
SF_AMBISONIC_B_FORMAT = 0x41
|
||||
} ;
|
||||
|
||||
/* Public error values. These are guaranteed to remain unchanged for the duration
|
||||
** of the library major version number.
|
||||
** There are also a large number of private error numbers which are internal to
|
||||
** the library which can change at any time.
|
||||
*/
|
||||
|
||||
enum
|
||||
{ SF_ERR_NO_ERROR = 0,
|
||||
SF_ERR_UNRECOGNISED_FORMAT = 1,
|
||||
SF_ERR_SYSTEM = 2,
|
||||
SF_ERR_MALFORMED_FILE = 3,
|
||||
SF_ERR_UNSUPPORTED_ENCODING = 4
|
||||
} ;
|
||||
|
||||
|
||||
/* Channel map values (used with SFC_SET/GET_CHANNEL_MAP).
|
||||
*/
|
||||
|
||||
enum
|
||||
{ SF_CHANNEL_MAP_INVALID = 0,
|
||||
SF_CHANNEL_MAP_MONO = 1,
|
||||
SF_CHANNEL_MAP_LEFT, /* Apple calls this 'Left' */
|
||||
SF_CHANNEL_MAP_RIGHT, /* Apple calls this 'Right' */
|
||||
SF_CHANNEL_MAP_CENTER, /* Apple calls this 'Center' */
|
||||
SF_CHANNEL_MAP_FRONT_LEFT,
|
||||
SF_CHANNEL_MAP_FRONT_RIGHT,
|
||||
SF_CHANNEL_MAP_FRONT_CENTER,
|
||||
SF_CHANNEL_MAP_REAR_CENTER, /* Apple calls this 'Center Surround', Msft calls this 'Back Center' */
|
||||
SF_CHANNEL_MAP_REAR_LEFT, /* Apple calls this 'Left Surround', Msft calls this 'Back Left' */
|
||||
SF_CHANNEL_MAP_REAR_RIGHT, /* Apple calls this 'Right Surround', Msft calls this 'Back Right' */
|
||||
SF_CHANNEL_MAP_LFE, /* Apple calls this 'LFEScreen', Msft calls this 'Low Frequency' */
|
||||
SF_CHANNEL_MAP_FRONT_LEFT_OF_CENTER, /* Apple calls this 'Left Center' */
|
||||
SF_CHANNEL_MAP_FRONT_RIGHT_OF_CENTER, /* Apple calls this 'Right Center */
|
||||
SF_CHANNEL_MAP_SIDE_LEFT, /* Apple calls this 'Left Surround Direct' */
|
||||
SF_CHANNEL_MAP_SIDE_RIGHT, /* Apple calls this 'Right Surround Direct' */
|
||||
SF_CHANNEL_MAP_TOP_CENTER, /* Apple calls this 'Top Center Surround' */
|
||||
SF_CHANNEL_MAP_TOP_FRONT_LEFT, /* Apple calls this 'Vertical Height Left' */
|
||||
SF_CHANNEL_MAP_TOP_FRONT_RIGHT, /* Apple calls this 'Vertical Height Right' */
|
||||
SF_CHANNEL_MAP_TOP_FRONT_CENTER, /* Apple calls this 'Vertical Height Center' */
|
||||
SF_CHANNEL_MAP_TOP_REAR_LEFT, /* Apple and MS call this 'Top Back Left' */
|
||||
SF_CHANNEL_MAP_TOP_REAR_RIGHT, /* Apple and MS call this 'Top Back Right' */
|
||||
SF_CHANNEL_MAP_TOP_REAR_CENTER, /* Apple and MS call this 'Top Back Center' */
|
||||
|
||||
SF_CHANNEL_MAP_AMBISONIC_B_W,
|
||||
SF_CHANNEL_MAP_AMBISONIC_B_X,
|
||||
SF_CHANNEL_MAP_AMBISONIC_B_Y,
|
||||
SF_CHANNEL_MAP_AMBISONIC_B_Z,
|
||||
|
||||
SF_CHANNEL_MAP_MAX
|
||||
} ;
|
||||
|
||||
|
||||
/* A SNDFILE* pointer can be passed around much like stdio.h's FILE* pointer. */
|
||||
|
||||
typedef struct SNDFILE_tag SNDFILE ;
|
||||
|
||||
/* The following typedef is system specific and is defined when libsndfile is
|
||||
** compiled. sf_count_t will be a 64 bit value when the underlying OS allows
|
||||
** 64 bit file offsets.
|
||||
** On windows, we need to allow the same header file to be compiler by both GCC
|
||||
** and the Microsoft compiler.
|
||||
*/
|
||||
|
||||
#if (defined (_MSCVER) || defined (_MSC_VER))
|
||||
typedef __int64 sf_count_t ;
|
||||
#define SF_COUNT_MAX 0x7fffffffffffffffi64
|
||||
#else
|
||||
typedef int64_t sf_count_t ;
|
||||
#define SF_COUNT_MAX 0x7FFFFFFFFFFFFFFFLL
|
||||
#endif
|
||||
|
||||
|
||||
/* A pointer to a SF_INFO structure is passed to sf_open () and filled in.
|
||||
** On write, the SF_INFO structure is filled in by the user and passed into
|
||||
** sf_open ().
|
||||
*/
|
||||
|
||||
struct SF_INFO
|
||||
{ sf_count_t frames ; /* Used to be called samples. Changed to avoid confusion. */
|
||||
int samplerate ;
|
||||
int channels ;
|
||||
int format ;
|
||||
int sections ;
|
||||
int seekable ;
|
||||
} ;
|
||||
|
||||
typedef struct SF_INFO SF_INFO ;
|
||||
|
||||
/* The SF_FORMAT_INFO struct is used to retrieve information about the sound
|
||||
** file formats libsndfile supports using the sf_command () interface.
|
||||
**
|
||||
** Using this interface will allow applications to support new file formats
|
||||
** and encoding types when libsndfile is upgraded, without requiring
|
||||
** re-compilation of the application.
|
||||
**
|
||||
** Please consult the libsndfile documentation (particularly the information
|
||||
** on the sf_command () interface) for examples of its use.
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{ int format ;
|
||||
const char *name ;
|
||||
const char *extension ;
|
||||
} SF_FORMAT_INFO ;
|
||||
|
||||
/*
|
||||
** Enums and typedefs for adding dither on read and write.
|
||||
** See the html documentation for sf_command(), SFC_SET_DITHER_ON_WRITE
|
||||
** and SFC_SET_DITHER_ON_READ.
|
||||
*/
|
||||
|
||||
enum
|
||||
{ SFD_DEFAULT_LEVEL = 0,
|
||||
SFD_CUSTOM_LEVEL = 0x40000000,
|
||||
|
||||
SFD_NO_DITHER = 500,
|
||||
SFD_WHITE = 501,
|
||||
SFD_TRIANGULAR_PDF = 502
|
||||
} ;
|
||||
|
||||
typedef struct
|
||||
{ int type ;
|
||||
double level ;
|
||||
const char *name ;
|
||||
} SF_DITHER_INFO ;
|
||||
|
||||
/* Struct used to retrieve information about a file embedded within a
|
||||
** larger file. See SFC_GET_EMBED_FILE_INFO.
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{ sf_count_t offset ;
|
||||
sf_count_t length ;
|
||||
} SF_EMBED_FILE_INFO ;
|
||||
|
||||
/*
|
||||
** Structs used to retrieve music sample information from a file.
|
||||
*/
|
||||
|
||||
enum
|
||||
{ /*
|
||||
** The loop mode field in SF_INSTRUMENT will be one of the following.
|
||||
*/
|
||||
SF_LOOP_NONE = 800,
|
||||
SF_LOOP_FORWARD,
|
||||
SF_LOOP_BACKWARD,
|
||||
SF_LOOP_ALTERNATING
|
||||
} ;
|
||||
|
||||
typedef struct
|
||||
{ int gain ;
|
||||
char basenote, detune ;
|
||||
char velocity_lo, velocity_hi ;
|
||||
char key_lo, key_hi ;
|
||||
int loop_count ;
|
||||
|
||||
struct
|
||||
{ int mode ;
|
||||
unsigned int start ;
|
||||
unsigned int end ;
|
||||
unsigned int count ;
|
||||
} loops [16] ; /* make variable in a sensible way */
|
||||
} SF_INSTRUMENT ;
|
||||
|
||||
|
||||
|
||||
/* Struct used to retrieve loop information from a file.*/
|
||||
typedef struct
|
||||
{
|
||||
short time_sig_num ; /* any positive integer > 0 */
|
||||
short time_sig_den ; /* any positive power of 2 > 0 */
|
||||
int loop_mode ; /* see SF_LOOP enum */
|
||||
|
||||
int num_beats ; /* this is NOT the amount of quarter notes !!!*/
|
||||
/* a full bar of 4/4 is 4 beats */
|
||||
/* a full bar of 7/8 is 7 beats */
|
||||
|
||||
float bpm ; /* suggestion, as it can be calculated using other fields:*/
|
||||
/* file's lenght, file's sampleRate and our time_sig_den*/
|
||||
/* -> bpms are always the amount of _quarter notes_ per minute */
|
||||
|
||||
int root_key ; /* MIDI note, or -1 for None */
|
||||
int future [6] ;
|
||||
} SF_LOOP_INFO ;
|
||||
|
||||
|
||||
/* Struct used to retrieve broadcast (EBU) information from a file.
|
||||
** Strongly (!) based on EBU "bext" chunk format used in Broadcast WAVE.
|
||||
*/
|
||||
#define SF_BROADCAST_INFO_VAR(coding_hist_size) \
|
||||
struct \
|
||||
{ char description [256] ; \
|
||||
char originator [32] ; \
|
||||
char originator_reference [32] ; \
|
||||
char origination_date [10] ; \
|
||||
char origination_time [8] ; \
|
||||
unsigned int time_reference_low ; \
|
||||
unsigned int time_reference_high ; \
|
||||
short version ; \
|
||||
char umid [64] ; \
|
||||
char reserved [190] ; \
|
||||
unsigned int coding_history_size ; \
|
||||
char coding_history [coding_hist_size] ; \
|
||||
}
|
||||
|
||||
/* SF_BROADCAST_INFO is the above struct with coding_history field of 256 bytes. */
|
||||
typedef SF_BROADCAST_INFO_VAR (256) SF_BROADCAST_INFO ;
|
||||
|
||||
|
||||
/* Virtual I/O functionality. */
|
||||
|
||||
typedef sf_count_t (*sf_vio_get_filelen) (void *user_data) ;
|
||||
typedef sf_count_t (*sf_vio_seek) (sf_count_t offset, int whence, void *user_data) ;
|
||||
typedef sf_count_t (*sf_vio_read) (void *ptr, sf_count_t count, void *user_data) ;
|
||||
typedef sf_count_t (*sf_vio_write) (const void *ptr, sf_count_t count, void *user_data) ;
|
||||
typedef sf_count_t (*sf_vio_tell) (void *user_data) ;
|
||||
|
||||
struct SF_VIRTUAL_IO
|
||||
{ sf_vio_get_filelen get_filelen ;
|
||||
sf_vio_seek seek ;
|
||||
sf_vio_read read ;
|
||||
sf_vio_write write ;
|
||||
sf_vio_tell tell ;
|
||||
} ;
|
||||
|
||||
typedef struct SF_VIRTUAL_IO SF_VIRTUAL_IO ;
|
||||
|
||||
|
||||
/* Open the specified file for read, write or both. On error, this will
|
||||
** return a NULL pointer. To find the error number, pass a NULL SNDFILE
|
||||
** to sf_strerror ().
|
||||
** All calls to sf_open() should be matched with a call to sf_close().
|
||||
*/
|
||||
|
||||
SNDFILE* sf_open (const char *path, int mode, SF_INFO *sfinfo) ;
|
||||
|
||||
|
||||
/* Use the existing file descriptor to create a SNDFILE object. If close_desc
|
||||
** is TRUE, the file descriptor will be closed when sf_close() is called. If
|
||||
** it is FALSE, the descritor will not be closed.
|
||||
** When passed a descriptor like this, the library will assume that the start
|
||||
** of file header is at the current file offset. This allows sound files within
|
||||
** larger container files to be read and/or written.
|
||||
** On error, this will return a NULL pointer. To find the error number, pass a
|
||||
** NULL SNDFILE to sf_strerror ().
|
||||
** All calls to sf_open_fd() should be matched with a call to sf_close().
|
||||
|
||||
*/
|
||||
|
||||
SNDFILE* sf_open_fd (int fd, int mode, SF_INFO *sfinfo, int close_desc) ;
|
||||
|
||||
SNDFILE* sf_open_virtual (SF_VIRTUAL_IO *sfvirtual, int mode, SF_INFO *sfinfo, void *user_data) ;
|
||||
|
||||
|
||||
/* sf_error () returns a error number which can be translated to a text
|
||||
** string using sf_error_number().
|
||||
*/
|
||||
|
||||
int sf_error (SNDFILE *sndfile) ;
|
||||
|
||||
|
||||
/* sf_strerror () returns to the caller a pointer to the current error message for
|
||||
** the given SNDFILE.
|
||||
*/
|
||||
|
||||
const char* sf_strerror (SNDFILE *sndfile) ;
|
||||
|
||||
|
||||
/* sf_error_number () allows the retrieval of the error string for each internal
|
||||
** error number.
|
||||
**
|
||||
*/
|
||||
|
||||
const char* sf_error_number (int errnum) ;
|
||||
|
||||
|
||||
/* The following two error functions are deprecated but they will remain in the
|
||||
** library for the forseeable future. The function sf_strerror() should be used
|
||||
** in their place.
|
||||
*/
|
||||
|
||||
int sf_perror (SNDFILE *sndfile) ;
|
||||
int sf_error_str (SNDFILE *sndfile, char* str, size_t len) ;
|
||||
|
||||
|
||||
/* Return TRUE if fields of the SF_INFO struct are a valid combination of values. */
|
||||
|
||||
int sf_command (SNDFILE *sndfile, int command, void *data, int datasize) ;
|
||||
|
||||
|
||||
/* Return TRUE if fields of the SF_INFO struct are a valid combination of values. */
|
||||
|
||||
int sf_format_check (const SF_INFO *info) ;
|
||||
|
||||
|
||||
/* Seek within the waveform data chunk of the SNDFILE. sf_seek () uses
|
||||
** the same values for whence (SEEK_SET, SEEK_CUR and SEEK_END) as
|
||||
** stdio.h function fseek ().
|
||||
** An offset of zero with whence set to SEEK_SET will position the
|
||||
** read / write pointer to the first data sample.
|
||||
** On success sf_seek returns the current position in (multi-channel)
|
||||
** samples from the start of the file.
|
||||
** Please see the libsndfile documentation for moving the read pointer
|
||||
** separately from the write pointer on files open in mode SFM_RDWR.
|
||||
** On error all of these functions return -1.
|
||||
*/
|
||||
|
||||
sf_count_t sf_seek (SNDFILE *sndfile, sf_count_t frames, int whence) ;
|
||||
|
||||
|
||||
/* Functions for retrieving and setting string data within sound files.
|
||||
** Not all file types support this features; AIFF and WAV do. For both
|
||||
** functions, the str_type parameter must be one of the SF_STR_* values
|
||||
** defined above.
|
||||
** On error, sf_set_string() returns non-zero while sf_get_string()
|
||||
** returns NULL.
|
||||
*/
|
||||
|
||||
int sf_set_string (SNDFILE *sndfile, int str_type, const char* str) ;
|
||||
|
||||
const char* sf_get_string (SNDFILE *sndfile, int str_type) ;
|
||||
|
||||
|
||||
/* Return the library version string. */
|
||||
|
||||
const char * sf_version_string (void) ;
|
||||
|
||||
|
||||
/* Functions for reading/writing the waveform data of a sound file.
|
||||
*/
|
||||
|
||||
sf_count_t sf_read_raw (SNDFILE *sndfile, void *ptr, sf_count_t bytes) ;
|
||||
sf_count_t sf_write_raw (SNDFILE *sndfile, const void *ptr, sf_count_t bytes) ;
|
||||
|
||||
|
||||
/* Functions for reading and writing the data chunk in terms of frames.
|
||||
** The number of items actually read/written = frames * number of channels.
|
||||
** sf_xxxx_raw read/writes the raw data bytes from/to the file
|
||||
** sf_xxxx_short passes data in the native short format
|
||||
** sf_xxxx_int passes data in the native int format
|
||||
** sf_xxxx_float passes data in the native float format
|
||||
** sf_xxxx_double passes data in the native double format
|
||||
** All of these read/write function return number of frames read/written.
|
||||
*/
|
||||
|
||||
sf_count_t sf_readf_short (SNDFILE *sndfile, short *ptr, sf_count_t frames) ;
|
||||
sf_count_t sf_writef_short (SNDFILE *sndfile, const short *ptr, sf_count_t frames) ;
|
||||
|
||||
sf_count_t sf_readf_int (SNDFILE *sndfile, int *ptr, sf_count_t frames) ;
|
||||
sf_count_t sf_writef_int (SNDFILE *sndfile, const int *ptr, sf_count_t frames) ;
|
||||
|
||||
sf_count_t sf_readf_float (SNDFILE *sndfile, float *ptr, sf_count_t frames) ;
|
||||
sf_count_t sf_writef_float (SNDFILE *sndfile, const float *ptr, sf_count_t frames) ;
|
||||
|
||||
sf_count_t sf_readf_double (SNDFILE *sndfile, double *ptr, sf_count_t frames) ;
|
||||
sf_count_t sf_writef_double (SNDFILE *sndfile, const double *ptr, sf_count_t frames) ;
|
||||
|
||||
|
||||
/* Functions for reading and writing the data chunk in terms of items.
|
||||
** Otherwise similar to above.
|
||||
** All of these read/write function return number of items read/written.
|
||||
*/
|
||||
|
||||
sf_count_t sf_read_short (SNDFILE *sndfile, short *ptr, sf_count_t items) ;
|
||||
sf_count_t sf_write_short (SNDFILE *sndfile, const short *ptr, sf_count_t items) ;
|
||||
|
||||
sf_count_t sf_read_int (SNDFILE *sndfile, int *ptr, sf_count_t items) ;
|
||||
sf_count_t sf_write_int (SNDFILE *sndfile, const int *ptr, sf_count_t items) ;
|
||||
|
||||
sf_count_t sf_read_float (SNDFILE *sndfile, float *ptr, sf_count_t items) ;
|
||||
sf_count_t sf_write_float (SNDFILE *sndfile, const float *ptr, sf_count_t items) ;
|
||||
|
||||
sf_count_t sf_read_double (SNDFILE *sndfile, double *ptr, sf_count_t items) ;
|
||||
sf_count_t sf_write_double (SNDFILE *sndfile, const double *ptr, sf_count_t items) ;
|
||||
|
||||
|
||||
/* Close the SNDFILE and clean up all memory allocations associated with this
|
||||
** file.
|
||||
** Returns 0 on success, or an error number.
|
||||
*/
|
||||
|
||||
int sf_close (SNDFILE *sndfile) ;
|
||||
|
||||
|
||||
/* If the file is opened SFM_WRITE or SFM_RDWR, call fsync() on the file
|
||||
** to force the writing of data to disk. If the file is opened SFM_READ
|
||||
** no action is taken.
|
||||
*/
|
||||
|
||||
void sf_write_sync (SNDFILE *sndfile) ;
|
||||
|
||||
|
||||
|
||||
/* The function sf_wchar_open() is Windows Only!
|
||||
** Open a file passing in a Windows Unicode filename. Otherwise, this is
|
||||
** the same as sf_open().
|
||||
**
|
||||
** In order for this to work, you need to do the following:
|
||||
**
|
||||
** #include <windows.h>
|
||||
** #define ENABLE_SNDFILE_WINDOWS_PROTOTYPES 1
|
||||
** #including <sndfile.h>
|
||||
*/
|
||||
|
||||
#if (defined (ENABLE_SNDFILE_WINDOWS_PROTOTYPES) && ENABLE_SNDFILE_WINDOWS_PROTOTYPES)
|
||||
SNDFILE* sf_wchar_open (LPCWSTR wpath, int mode, SF_INFO *sfinfo) ;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* SNDFILE_H */
|
||||
|
||||
39
src/utility/filereadermusicinterface.h
Normal file
39
src/utility/filereadermusicinterface.h
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
#pragma once
|
||||
|
||||
#include "../libraries/music_common/fileio.h"
|
||||
#include "files.h"
|
||||
|
||||
struct FileReaderMusicInterface : public MusicIO::FileInterface
|
||||
{
|
||||
FileReader fr;
|
||||
|
||||
FileReaderMusicInterface(FileReader& fr_in)
|
||||
{
|
||||
fr = std::move(fr_in);
|
||||
}
|
||||
char* gets(char* buff, int n) override
|
||||
{
|
||||
if (!fr.isOpen()) return nullptr;
|
||||
return fr.Gets(buff, n);
|
||||
}
|
||||
long read(void* buff, int32_t size, int32_t nitems) override
|
||||
{
|
||||
if (!fr.isOpen()) return 0;
|
||||
return (long)fr.Read(buff, size * nitems) / size;
|
||||
}
|
||||
long seek(long offset, int whence) override
|
||||
{
|
||||
if (!fr.isOpen()) return 0;
|
||||
return (long)fr.Seek(offset, (FileReader::ESeek)whence);
|
||||
}
|
||||
long tell() override
|
||||
{
|
||||
if (!fr.isOpen()) return 0;
|
||||
return (long)fr.Tell();
|
||||
}
|
||||
FileReader& getReader()
|
||||
{
|
||||
return fr;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -328,4 +328,5 @@ public:
|
|||
TArray<unsigned char> *GetBuffer() { return &mBuffer; }
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue