mirror of
https://github.com/ZDoom/gzdoom-gles.git
synced 2025-01-31 04:20:34 +00:00
- 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. # Conflicts: # src/CMakeLists.txt # Conflicts: # libraries/zmusic/decoder/mpg123_decoder.cpp # libraries/zmusic/decoder/sndfile_decoder.cpp # src/CMakeLists.txt
This commit is contained in:
parent
fb3b6a0407
commit
f3f2ec5cb1
35 changed files with 548 additions and 438 deletions
|
@ -407,6 +407,11 @@ install(DIRECTORY docs/
|
|||
DESTINATION ${INSTALL_DOCS_PATH}
|
||||
COMPONENT "Documentation")
|
||||
|
||||
option( DYN_FLUIDSYNTH "Dynamically load fluidsynth" ON )
|
||||
option( DYN_OPENAL "Dynamically load OpenAL" ON )
|
||||
option( DYN_SNDFILE "Dynamically load libsndfile" ON )
|
||||
option( DYN_MPG123 "Dynamically load libmpg123" ON )
|
||||
|
||||
add_subdirectory( libraries/lzma )
|
||||
add_subdirectory( tools )
|
||||
add_subdirectory( libraries/dumb )
|
||||
|
|
|
@ -50,16 +50,35 @@ namespace MusicIO
|
|||
struct FileInterface
|
||||
{
|
||||
std::string filename;
|
||||
long length = -1;
|
||||
|
||||
// It's really too bad that the using code requires long instead of size_t.
|
||||
// Fortunately 2GB files are unlikely to come by here.
|
||||
protected:
|
||||
//
|
||||
virtual ~FileInterface() {}
|
||||
public:
|
||||
virtual char* gets(char* buff, int n) = 0;
|
||||
virtual long read(void* buff, int32_t size, int32_t nitems) = 0;
|
||||
long read(void* buff, int32_t size) { return read(buff, 1, size); }
|
||||
virtual long seek(long offset, int whence) = 0;
|
||||
virtual long tell() = 0;
|
||||
virtual void close() = 0;
|
||||
virtual void close()
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
long filelength()
|
||||
{
|
||||
if (length == -1)
|
||||
{
|
||||
long pos = tell();
|
||||
seek(0, SEEK_END);
|
||||
length = tell();
|
||||
seek(pos, SEEK_SET);
|
||||
}
|
||||
return length;
|
||||
}
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
|
@ -96,11 +115,6 @@ struct StdioFileReader : public FileInterface
|
|||
if (!f) return 0;
|
||||
return ftell(f);
|
||||
}
|
||||
void close() override
|
||||
{
|
||||
if (f) fclose(f);
|
||||
delete this;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
@ -113,7 +127,7 @@ struct StdioFileReader : public FileInterface
|
|||
struct MemoryReader : public FileInterface
|
||||
{
|
||||
const uint8_t *mData;
|
||||
const long mLength;
|
||||
long mLength;
|
||||
long mPos;
|
||||
|
||||
MemoryReader(const uint8_t *data, long length)
|
||||
|
@ -180,13 +194,32 @@ struct MemoryReader : public FileInterface
|
|||
{
|
||||
return mPos;
|
||||
}
|
||||
void close() override
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
protected:
|
||||
MemoryReader() {}
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Inplementation of the FileInterface for an std::vector owned by the reader
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
struct VectorReader : public MemoryReader
|
||||
{
|
||||
std::vector<uint8_t> mVector;
|
||||
|
||||
template <class getFunc>
|
||||
VectorReader(getFunc getter) // read contents to a buffer and return a reader to it
|
||||
{
|
||||
getter(mVector);
|
||||
mData = mVector.data();
|
||||
mLength = (long)mVector.size();
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// The follpwing two functions are needed to allow using UTF-8 in the file interface.
|
||||
|
|
|
@ -56,7 +56,7 @@ unsigned char *_WM_BufferFile(MusicIO::SoundFontReaderInterface *reader, const c
|
|||
return NULL;
|
||||
}
|
||||
|
||||
auto fsize = (fp->seek(0, SEEK_END), fp->tell());
|
||||
auto fsize = fp->filelength();
|
||||
|
||||
if (fsize > WM_MAXFILESIZE)
|
||||
{
|
||||
|
|
|
@ -9,8 +9,6 @@ set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${ZD_FASTMATH_FLAG}")
|
|||
|
||||
include( CheckFunctionExists )
|
||||
|
||||
option( DYN_FLUIDSYNTH "Dynamically load fluidsynth" ON )
|
||||
|
||||
CHECK_FUNCTION_EXISTS( stricmp STRICMP_EXISTS )
|
||||
if( NOT STRICMP_EXISTS )
|
||||
add_definitions( -Dstricmp=strcasecmp )
|
||||
|
@ -21,6 +19,25 @@ if( NOT STRNICMP_EXISTS )
|
|||
add_definitions( -Dstrnicmp=strncasecmp )
|
||||
endif()
|
||||
|
||||
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()
|
||||
|
||||
|
||||
include_directories( "${ADL_INCLUDE_DIR}" "${OPN_INCLUDE_DIR}" "${TIMIDITYPP_INCLUDE_DIR}" "${TIMIDITY_INCLUDE_DIR}" "${WILDMIDI_INCLUDE_DIR}" "${OPLSYNTH_INCLUDE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}" )
|
||||
|
||||
if (WIN32)
|
||||
|
@ -48,6 +65,9 @@ add_library( zmusic STATIC
|
|||
midisources/midisource_smf.cpp
|
||||
midisources/midisource_hmi.cpp
|
||||
midisources/midisource_xmi.cpp
|
||||
decoder/sounddecoder.cpp
|
||||
decoder/sndfile_decoder.cpp
|
||||
decoder/mpg123_decoder.cpp
|
||||
${PLAT_WIN32_SOURCES}
|
||||
)
|
||||
target_link_libraries( zmusic )
|
||||
|
|
|
@ -31,10 +31,10 @@
|
|||
**
|
||||
*/
|
||||
|
||||
#include "mpg123_decoder.h"
|
||||
#include "files.h"
|
||||
#include <algorithm>
|
||||
#include <stdio.h>
|
||||
#include "zmusic/mpg123_decoder.h"
|
||||
#include "i_module.h"
|
||||
#include "cmdlib.h"
|
||||
|
||||
#ifdef HAVE_MPG123
|
||||
|
||||
|
@ -62,7 +62,8 @@ bool IsMPG123Present()
|
|||
if (!done)
|
||||
{
|
||||
done = true;
|
||||
cached_result = MPG123Module.Load({NicePath("$PROGDIR/" MPG123LIB), MPG123LIB});
|
||||
auto abspath = module_progdir + "/" MPG123LIB;
|
||||
cached_result = MPG123Module.Load({abspath.c_str(), MPG123LIB});
|
||||
}
|
||||
return cached_result;
|
||||
#endif
|
||||
|
@ -78,24 +79,24 @@ off_t MPG123Decoder::file_lseek(void *handle, off_t offset, int whence)
|
|||
|
||||
if(whence == SEEK_CUR)
|
||||
{
|
||||
if(offset < 0 && reader.Tell()+offset < 0)
|
||||
if(offset < 0 && reader->tell()+offset < 0)
|
||||
return -1;
|
||||
}
|
||||
else if(whence == SEEK_END)
|
||||
{
|
||||
if(offset < 0 && reader.GetLength()+offset < 0)
|
||||
if(offset < 0 && reader->filelength() + offset < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(reader.Seek(offset, (FileReader::ESeek)whence) != 0)
|
||||
if(reader->seek(offset, whence) != 0)
|
||||
return -1;
|
||||
return (off_t)reader.Tell();
|
||||
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);
|
||||
return (ssize_t)reader->read(buffer, (long)bytes);
|
||||
}
|
||||
|
||||
|
||||
|
@ -107,9 +108,11 @@ MPG123Decoder::~MPG123Decoder()
|
|||
mpg123_delete(MPG123);
|
||||
MPG123 = 0;
|
||||
}
|
||||
if (Reader) Reader->close();
|
||||
Reader = nullptr;
|
||||
}
|
||||
|
||||
bool MPG123Decoder::open(FileReader &reader)
|
||||
bool MPG123Decoder::open(MusicIO::FileInterface *reader)
|
||||
{
|
||||
if(!inited)
|
||||
{
|
||||
|
@ -118,7 +121,7 @@ bool MPG123Decoder::open(FileReader &reader)
|
|||
inited = true;
|
||||
}
|
||||
|
||||
Reader = std::move(reader);
|
||||
Reader = reader;
|
||||
|
||||
{
|
||||
MPG123 = mpg123_new(NULL, NULL);
|
||||
|
@ -145,7 +148,7 @@ bool MPG123Decoder::open(FileReader &reader)
|
|||
MPG123 = 0;
|
||||
}
|
||||
|
||||
reader = std::move(Reader); // need to give it back.
|
||||
Reader = nullptr; // need to give it back.
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -215,7 +218,7 @@ bool MPG123Decoder::seek(size_t ms_offset, bool ms, bool mayrestart)
|
|||
mpg123_delete(MPG123);
|
||||
MPG123 = 0;
|
||||
}
|
||||
Reader.Seek(0, FileReader::SeekSet);
|
||||
Reader->seek(0, SEEK_SET);
|
||||
// Do not call open with our own reader variable, that would be catastrophic.
|
||||
auto reader = std::move(Reader);
|
||||
return open(reader);
|
|
@ -30,12 +30,10 @@
|
|||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
#include "sndfile_decoder.h"
|
||||
#include "templates.h"
|
||||
#include "files.h"
|
||||
#include "xs_Float.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include "zmusic/sndfile_decoder.h"
|
||||
#include "i_module.h"
|
||||
#include "cmdlib.h"
|
||||
|
||||
#ifdef HAVE_SNDFILE
|
||||
|
||||
|
@ -63,7 +61,8 @@ bool IsSndFilePresent()
|
|||
if (!done)
|
||||
{
|
||||
done = true;
|
||||
cached_result = SndFileModule.Load({NicePath("$PROGDIR/" SNDFILELIB), SNDFILELIB});
|
||||
auto abspath = module_progdir + "/" SNDFILELIB;
|
||||
cached_result = SndFileModule.Load({abspath.c_str(), SNDFILELIB});
|
||||
}
|
||||
return cached_result;
|
||||
#endif
|
||||
|
@ -73,22 +72,22 @@ bool IsSndFilePresent()
|
|||
sf_count_t SndFileDecoder::file_get_filelen(void *user_data)
|
||||
{
|
||||
auto &reader = reinterpret_cast<SndFileDecoder*>(user_data)->Reader;
|
||||
return reader.GetLength();
|
||||
return reader->filelength();
|
||||
}
|
||||
|
||||
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)
|
||||
if(reader->seek((long)offset, whence) != 0)
|
||||
return -1;
|
||||
return reader.Tell();
|
||||
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);
|
||||
return reader->read(ptr, (long)count);
|
||||
}
|
||||
|
||||
sf_count_t SndFileDecoder::file_write(const void *ptr, sf_count_t count, void *user_data)
|
||||
|
@ -99,7 +98,7 @@ sf_count_t SndFileDecoder::file_write(const void *ptr, sf_count_t count, void *u
|
|||
sf_count_t SndFileDecoder::file_tell(void *user_data)
|
||||
{
|
||||
auto &reader = reinterpret_cast<SndFileDecoder*>(user_data)->Reader;
|
||||
return reader.Tell();
|
||||
return reader->tell();
|
||||
}
|
||||
|
||||
|
||||
|
@ -108,15 +107,18 @@ SndFileDecoder::~SndFileDecoder()
|
|||
if(SndFile)
|
||||
sf_close(SndFile);
|
||||
SndFile = 0;
|
||||
|
||||
if (Reader) Reader->close();
|
||||
Reader = nullptr;
|
||||
}
|
||||
|
||||
bool SndFileDecoder::open(FileReader &reader)
|
||||
bool SndFileDecoder::open(MusicIO::FileInterface *reader)
|
||||
{
|
||||
if (!IsSndFilePresent()) return false;
|
||||
|
||||
SF_VIRTUAL_IO sfio = { file_get_filelen, file_seek, file_read, file_write, file_tell };
|
||||
|
||||
Reader = std::move(reader);
|
||||
Reader = reader;
|
||||
SndInfo.format = 0;
|
||||
SndFile = sf_open_virtual(&sfio, SFM_READ, &SndInfo, this);
|
||||
if (SndFile)
|
||||
|
@ -127,7 +129,7 @@ bool SndFileDecoder::open(FileReader &reader)
|
|||
sf_close(SndFile);
|
||||
SndFile = 0;
|
||||
}
|
||||
reader = std::move(Reader); // need to give it back.
|
||||
Reader = nullptr; // need to give it back.
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -158,30 +160,30 @@ size_t SndFileDecoder::read(char *buffer, size_t bytes)
|
|||
// could be more.
|
||||
while(total < frames)
|
||||
{
|
||||
size_t todo = MIN<size_t>(frames-total, 64/SndInfo.channels);
|
||||
size_t todo = std::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));
|
||||
*out++ = (short)std::max(std::min(tmp[i] * 32767.f, 32767.f), -32768.f);
|
||||
total += got;
|
||||
}
|
||||
return total * SndInfo.channels * 2;
|
||||
}
|
||||
|
||||
TArray<uint8_t> SndFileDecoder::readAll()
|
||||
std::vector<uint8_t> SndFileDecoder::readAll()
|
||||
{
|
||||
if(SndInfo.frames <= 0)
|
||||
return SoundDecoder::readAll();
|
||||
|
||||
int framesize = 2 * SndInfo.channels;
|
||||
TArray<uint8_t> output;
|
||||
std::vector<uint8_t> output;
|
||||
|
||||
output.Resize((unsigned)(SndInfo.frames * framesize));
|
||||
size_t got = read((char*)&output[0], output.Size());
|
||||
output.Resize((unsigned)got);
|
||||
output.resize((unsigned)(SndInfo.frames * framesize));
|
||||
size_t got = read((char*)&output[0], output.size());
|
||||
output.resize((unsigned)got);
|
||||
|
||||
return output;
|
||||
}
|
81
libraries/zmusic/decoder/sounddecoder.cpp
Normal file
81
libraries/zmusic/decoder/sounddecoder.cpp
Normal file
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
** sounddecoder.cpp
|
||||
** baseclass for sound format decoders
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2008-2019 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 "zmusic/sndfile_decoder.h"
|
||||
#include "zmusic/mpg123_decoder.h"
|
||||
|
||||
SoundDecoder *SoundDecoder::CreateDecoder(MusicIO::FileInterface *reader)
|
||||
{
|
||||
SoundDecoder *decoder = NULL;
|
||||
auto pos = reader->tell();
|
||||
|
||||
#ifdef HAVE_SNDFILE
|
||||
decoder = new SndFileDecoder;
|
||||
if (decoder->open(reader))
|
||||
return decoder;
|
||||
reader->seek(pos, SEEK_SET);
|
||||
|
||||
delete decoder;
|
||||
decoder = NULL;
|
||||
#endif
|
||||
#ifdef HAVE_MPG123
|
||||
decoder = new MPG123Decoder;
|
||||
if (decoder->open(reader))
|
||||
return decoder;
|
||||
reader->seek(pos, SEEK_SET);
|
||||
|
||||
delete decoder;
|
||||
decoder = NULL;
|
||||
#endif
|
||||
return decoder;
|
||||
}
|
||||
|
||||
|
||||
// Default readAll implementation, for decoders that can't do anything better
|
||||
std::vector<uint8_t> SoundDecoder::readAll()
|
||||
{
|
||||
std::vector<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;
|
||||
}
|
|
@ -40,6 +40,7 @@
|
|||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef _WIN32
|
||||
#define LoadLibraryA(x) dlopen((x), RTLD_LAZY)
|
||||
#define GetProcAddress(a,b) dlsym((a),(b))
|
||||
|
@ -98,3 +99,10 @@ void *FModule::GetSym(const char* name)
|
|||
{
|
||||
return (void *)GetProcAddress((HMODULE)handle, name);
|
||||
}
|
||||
|
||||
std::string module_progdir("."); // current program directory used to look up dynamic libraries. Default to something harmless in case the user didn't set it.
|
||||
|
||||
void FModule_SetProgDir(const char* progdir)
|
||||
{
|
||||
module_progdir = progdir;
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <assert.h>
|
||||
#include <string>
|
||||
#include <initializer_list>
|
||||
|
||||
/* FModule Run Time Library Loader
|
||||
|
@ -227,3 +228,6 @@ public:
|
|||
operator Proto() const { return Sym; }
|
||||
explicit operator bool() const { return Sym != nullptr; }
|
||||
};
|
||||
|
||||
void FModule_SetProgDir(const char* progdir);
|
||||
extern std::string module_progdir;
|
||||
|
|
|
@ -41,10 +41,6 @@
|
|||
|
||||
// FluidSynth implementation of a MIDI device -------------------------------
|
||||
|
||||
#if !defined DYN_FLUIDSYNTH && defined _WIN32
|
||||
#define DYN_FLUIDSYNTH 1 // On Windows this is the only supported way to link to FluidSynth.
|
||||
#endif
|
||||
|
||||
#if !defined DYN_FLUIDSYNTH
|
||||
#include <fluidsynth.h>
|
||||
#else
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
#ifndef MPG123_DECODER_H
|
||||
#define MPG123_DECODER_H
|
||||
|
||||
#include "i_soundinternal.h"
|
||||
#include "files.h"
|
||||
#include "sounddecoder.h"
|
||||
|
||||
#ifdef HAVE_MPG123
|
||||
|
||||
|
@ -19,25 +18,25 @@ typedef ptrdiff_t ssize_t;
|
|||
|
||||
struct MPG123Decoder : public SoundDecoder
|
||||
{
|
||||
virtual void getInfo(int *samplerate, ChannelConfig *chans, SampleType *type);
|
||||
virtual void getInfo(int* samplerate, ChannelConfig* chans, SampleType* type) override;
|
||||
|
||||
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();
|
||||
virtual size_t read(char* buffer, size_t bytes) override;
|
||||
virtual bool seek(size_t ms_offset, bool ms, bool mayrestart) override;
|
||||
virtual size_t getSampleOffset() override;
|
||||
virtual size_t getSampleLength() override;
|
||||
|
||||
MPG123Decoder() : MPG123(0) { }
|
||||
virtual ~MPG123Decoder();
|
||||
MPG123Decoder() : MPG123(0) { }
|
||||
virtual ~MPG123Decoder();
|
||||
|
||||
protected:
|
||||
virtual bool open(FileReader &reader);
|
||||
virtual bool open(MusicIO::FileInterface *reader) override;
|
||||
|
||||
private:
|
||||
mpg123_handle *MPG123;
|
||||
bool Done;
|
||||
|
||||
FileReader Reader;
|
||||
static off_t file_lseek(void *handle, off_t offset, int whence);
|
||||
MusicIO::FileInterface* 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
|
|
@ -1,8 +1,7 @@
|
|||
#ifndef SNDFILE_DECODER_H
|
||||
#define SNDFILE_DECODER_H
|
||||
|
||||
#include "i_soundinternal.h"
|
||||
#include "files.h"
|
||||
#include "sounddecoder.h"
|
||||
|
||||
#ifdef HAVE_SNDFILE
|
||||
|
||||
|
@ -14,25 +13,25 @@
|
|||
|
||||
struct SndFileDecoder : public SoundDecoder
|
||||
{
|
||||
virtual void getInfo(int *samplerate, ChannelConfig *chans, SampleType *type);
|
||||
virtual void getInfo(int *samplerate, ChannelConfig *chans, SampleType *type) override;
|
||||
|
||||
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();
|
||||
virtual size_t read(char *buffer, size_t bytes) override;
|
||||
virtual std::vector<uint8_t> readAll() override;
|
||||
virtual bool seek(size_t ms_offset, bool ms, bool mayrestart) override;
|
||||
virtual size_t getSampleOffset() override;
|
||||
virtual size_t getSampleLength() override;
|
||||
|
||||
SndFileDecoder() : SndFile(0) { }
|
||||
virtual ~SndFileDecoder();
|
||||
|
||||
protected:
|
||||
virtual bool open(FileReader &reader);
|
||||
virtual bool open(MusicIO::FileInterface *reader) override;
|
||||
|
||||
private:
|
||||
SNDFILE *SndFile;
|
||||
SF_INFO SndInfo;
|
||||
|
||||
FileReader Reader;
|
||||
MusicIO::FileInterface* 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);
|
40
libraries/zmusic/zmusic/sounddecoder.h
Normal file
40
libraries/zmusic/zmusic/sounddecoder.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
#pragma once
|
||||
|
||||
#include "../../music_common/fileio.h"
|
||||
#include <vector>
|
||||
|
||||
enum SampleType
|
||||
{
|
||||
SampleType_UInt8,
|
||||
SampleType_Int16
|
||||
};
|
||||
enum ChannelConfig
|
||||
{
|
||||
ChannelConfig_Mono,
|
||||
ChannelConfig_Stereo
|
||||
};
|
||||
|
||||
struct SoundDecoder
|
||||
{
|
||||
static SoundDecoder* CreateDecoder(MusicIO::FileInterface* reader);
|
||||
|
||||
virtual void getInfo(int *samplerate, ChannelConfig *chans, SampleType *type) = 0;
|
||||
|
||||
virtual size_t read(char *buffer, size_t bytes) = 0;
|
||||
virtual std::vector<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; }
|
||||
virtual bool open(MusicIO::FileInterface* reader) = 0;
|
||||
|
||||
SoundDecoder() { }
|
||||
virtual ~SoundDecoder() { }
|
||||
|
||||
protected:
|
||||
friend class SoundRenderer;
|
||||
|
||||
// Make non-copyable
|
||||
SoundDecoder(const SoundDecoder &rhs) = delete;
|
||||
SoundDecoder& operator=(const SoundDecoder &rhs) = delete;
|
||||
};
|
||||
|
|
@ -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()
|
||||
|
@ -640,24 +636,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( VM_JIT_SOURCES
|
|||
set( FASTMATH_SOURCES
|
||||
swrenderer/r_all.cpp
|
||||
polyrenderer/poly_all.cpp
|
||||
sound/backend/mpg123_decoder.cpp
|
||||
sound/music/music_midi_base.cpp
|
||||
sound/backend/oalsound.cpp
|
||||
sound/backend/sndfile_decoder.cpp
|
||||
gl/utility/gl_clock.cpp
|
||||
gl/renderer/gl_2ddrawer.cpp
|
||||
gl/hqnx/init.cpp
|
||||
|
|
39
src/filereadermusicinterface.h
Normal file
39
src/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;
|
||||
}
|
||||
};
|
||||
|
|
@ -319,4 +319,5 @@ public:
|
|||
TArray<unsigned char> *GetBuffer() { return &mBuffer; }
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -41,8 +41,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 "m_swap.h"
|
||||
#include "stats.h"
|
||||
|
@ -262,6 +264,7 @@ public:
|
|||
|
||||
void I_InitSound ()
|
||||
{
|
||||
FModule_SetProgDir(progdir);
|
||||
/* Get command line options: */
|
||||
nosound = !!Args->CheckParm ("-nosound");
|
||||
nosfx = !!Args->CheckParm ("-nosfx");
|
||||
|
@ -366,16 +369,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)
|
||||
|
@ -560,46 +567,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
|
||||
{
|
||||
|
|
|
@ -51,6 +51,8 @@
|
|||
#include "i_music.h"
|
||||
#include "cmdlib.h"
|
||||
#include "menu/menu.h"
|
||||
#include "zmusic/sounddecoder.h"
|
||||
#include "filereadermusicinterface.h"
|
||||
|
||||
FModule OpenALModule{"OpenAL"};
|
||||
|
||||
|
@ -236,7 +238,6 @@ class OpenALSoundStream : public SoundStream
|
|||
ALfloat Volume;
|
||||
|
||||
|
||||
FileReader Reader;
|
||||
SoundDecoder *Decoder;
|
||||
static bool DecoderCallback(SoundStream *_sstream, void *ptr, int length, void *user)
|
||||
{
|
||||
|
@ -619,9 +620,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;
|
||||
|
@ -1292,7 +1297,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;
|
||||
|
@ -1303,13 +1307,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;
|
||||
|
@ -1331,12 +1338,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)
|
||||
{
|
||||
|
@ -1360,13 +1367,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));
|
||||
|
@ -1377,7 +1384,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;
|
||||
|
||||
|
@ -1432,12 +1439,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)
|
||||
{
|
||||
|
@ -1461,13 +1468,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));
|
||||
|
|
|
@ -63,7 +63,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"
|
||||
|
||||
|
@ -99,7 +99,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;
|
||||
|
@ -221,8 +221,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;
|
||||
|
@ -303,24 +301,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;
|
||||
|
@ -394,153 +389,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;
|
||||
|
@ -574,7 +570,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;
|
||||
|
@ -613,7 +609,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);
|
||||
|
@ -721,6 +717,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)
|
||||
|
@ -728,9 +725,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);
|
||||
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#include "w_wad.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);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
|
|
|
@ -112,33 +112,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)
|
||||
{
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#include "templates.h"
|
||||
#include "m_fixed.h"
|
||||
#include "streamsource.h"
|
||||
#include "zmusic/sounddecoder.h"
|
||||
|
||||
// MACROS ------------------------------------------------------------------
|
||||
|
||||
|
@ -49,7 +50,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;
|
||||
|
@ -57,7 +58,6 @@ public:
|
|||
|
||||
protected:
|
||||
std::mutex CritSec;
|
||||
FileReader Reader;
|
||||
SoundDecoder *Decoder;
|
||||
int Channels;
|
||||
int SampleRate;
|
||||
|
@ -104,23 +104,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);
|
||||
|
||||
|
@ -128,20 +128,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;
|
||||
|
||||
|
@ -152,13 +152,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
|
||||
|
@ -174,18 +174,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
|
||||
|
@ -198,7 +198,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)
|
||||
|
@ -209,7 +209,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)
|
||||
|
@ -236,7 +236,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;
|
||||
}
|
||||
|
||||
|
@ -244,16 +244,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)
|
||||
|
@ -267,18 +267,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);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -287,7 +287,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;
|
||||
|
@ -300,7 +300,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");
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
|
|
@ -70,7 +70,6 @@
|
|||
#include "c_dispatch.h"
|
||||
#include "m_random.h"
|
||||
#include "w_wad.h"
|
||||
#include "doomdef.h"
|
||||
#include "p_local.h"
|
||||
#include "doomstat.h"
|
||||
#include "cmdlib.h"
|
||||
|
@ -79,13 +78,9 @@
|
|||
#include "a_sharedglobal.h"
|
||||
#include "gstrings.h"
|
||||
#include "gi.h"
|
||||
#include "templates.h"
|
||||
#include "timidity/timidity.h"
|
||||
#include "g_level.h"
|
||||
#include "po_man.h"
|
||||
#include "serializer.h"
|
||||
#include "d_player.h"
|
||||
#include "r_state.h"
|
||||
#include "g_levellocals.h"
|
||||
#include "vm.h"
|
||||
#include "atterm.h"
|
||||
|
@ -1535,7 +1530,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);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue