mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-10 23:02:08 +00:00
- moved the music loader code to ZMusic.
This was the final piece of code reorganization. What's left is cleaning up the interface.
This commit is contained in:
parent
c42deda6e6
commit
02507effe8
7 changed files with 343 additions and 297 deletions
|
@ -38,7 +38,7 @@ elseif( FLUIDSYNTH_FOUND )
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
||||||
include_directories( "../libraries/dumb/include" "${ADL_INCLUDE_DIR}" "${OPN_INCLUDE_DIR}" "${TIMIDITYPP_INCLUDE_DIR}" "${TIMIDITY_INCLUDE_DIR}" "${WILDMIDI_INCLUDE_DIR}" "${OPLSYNTH_INCLUDE_DIR}" "${GME_INCLUDE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}" )
|
include_directories( "${CMAKE_CURRENT_SOURCE_DIR}/../libraries/dumb/include" "${ADL_INCLUDE_DIR}" "${OPN_INCLUDE_DIR}" "${TIMIDITYPP_INCLUDE_DIR}" "${TIMIDITY_INCLUDE_DIR}" "${WILDMIDI_INCLUDE_DIR}" "${OPLSYNTH_INCLUDE_DIR}" "${GME_INCLUDE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}" )
|
||||||
|
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
set( PLAT_SOURCES
|
set( PLAT_SOURCES
|
||||||
|
@ -87,6 +87,7 @@ add_library( zmusic STATIC
|
||||||
decoder/sndfile_decoder.cpp
|
decoder/sndfile_decoder.cpp
|
||||||
decoder/mpg123_decoder.cpp
|
decoder/mpg123_decoder.cpp
|
||||||
zmusic/configuration.cpp
|
zmusic/configuration.cpp
|
||||||
|
zmusic/zmusic.cpp
|
||||||
${PLAT_SOURCES}
|
${PLAT_SOURCES}
|
||||||
)
|
)
|
||||||
target_link_libraries( zmusic )
|
target_link_libraries( zmusic )
|
||||||
|
|
334
libraries/zmusic/zmusic/zmusic.cpp
Normal file
334
libraries/zmusic/zmusic/zmusic.cpp
Normal file
|
@ -0,0 +1,334 @@
|
||||||
|
/*
|
||||||
|
** i_music.cpp
|
||||||
|
** Plays music
|
||||||
|
**
|
||||||
|
**---------------------------------------------------------------------------
|
||||||
|
** Copyright 1998-2016 Randy Heit
|
||||||
|
** Copyright 2005-2019 Christoph Oelckers
|
||||||
|
** 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 <stdint.h>
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include <zlib.h>
|
||||||
|
#include "m_swap.h"
|
||||||
|
#include "zmusic.h"
|
||||||
|
#include "midiconfig.h"
|
||||||
|
#include "musinfo.h"
|
||||||
|
#include "streamsources/streamsource.h"
|
||||||
|
#include "midisources/midisource.h"
|
||||||
|
|
||||||
|
#define GZIP_ID1 31
|
||||||
|
#define GZIP_ID2 139
|
||||||
|
#define GZIP_CM 8
|
||||||
|
#define GZIP_ID MAKE_ID(GZIP_ID1,GZIP_ID2,GZIP_CM,0)
|
||||||
|
|
||||||
|
#define GZIP_FTEXT 1
|
||||||
|
#define GZIP_FHCRC 2
|
||||||
|
#define GZIP_FEXTRA 4
|
||||||
|
#define GZIP_FNAME 8
|
||||||
|
#define GZIP_FCOMMENT 16
|
||||||
|
|
||||||
|
class MIDIDevice;
|
||||||
|
class OPLmusicFile;
|
||||||
|
class StreamSource;
|
||||||
|
class MusInfo;
|
||||||
|
|
||||||
|
MusInfo *OpenStreamSong(StreamSource *source);
|
||||||
|
const char *GME_CheckFormat(uint32_t header);
|
||||||
|
MusInfo* CDDA_OpenSong(MusicIO::FileInterface* reader);
|
||||||
|
MusInfo* CD_OpenSong(int track, int id);
|
||||||
|
MusInfo* CreateMIDIStreamer(MIDISource *source, EMidiDevice devtype, const char* args);
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// ungzip
|
||||||
|
//
|
||||||
|
// VGZ files are compressed with gzip, so we need to uncompress them before
|
||||||
|
// handing them to GME.
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
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;
|
||||||
|
uint8_t flags = data[3];
|
||||||
|
unsigned isize;
|
||||||
|
z_stream stream;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
// Find start of compressed data stream
|
||||||
|
if (flags & GZIP_FEXTRA)
|
||||||
|
{
|
||||||
|
compstart += 2 + LittleShort(*(uint16_t *)(data + 10));
|
||||||
|
}
|
||||||
|
if (flags & GZIP_FNAME)
|
||||||
|
{
|
||||||
|
while (compstart < max && *compstart != 0)
|
||||||
|
{
|
||||||
|
compstart++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (flags & GZIP_FCOMMENT)
|
||||||
|
{
|
||||||
|
while (compstart < max && *compstart != 0)
|
||||||
|
{
|
||||||
|
compstart++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (flags & GZIP_FHCRC)
|
||||||
|
{
|
||||||
|
compstart += 2;
|
||||||
|
}
|
||||||
|
if (compstart >= max - 1)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decompress
|
||||||
|
isize = LittleLong(*(uint32_t *)(data + complen - 4));
|
||||||
|
newdata.resize(isize);
|
||||||
|
|
||||||
|
stream.next_in = (Bytef *)compstart;
|
||||||
|
stream.avail_in = (uInt)(max - compstart);
|
||||||
|
stream.next_out = &newdata[0];
|
||||||
|
stream.avail_out = isize;
|
||||||
|
stream.zalloc = (alloc_func)0;
|
||||||
|
stream.zfree = (free_func)0;
|
||||||
|
|
||||||
|
err = inflateInit2(&stream, -MAX_WBITS);
|
||||||
|
if (err != Z_OK)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
err = inflate(&stream, Z_FINISH);
|
||||||
|
if (err != Z_STREAM_END)
|
||||||
|
{
|
||||||
|
inflateEnd(&stream);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
err = inflateEnd(&stream);
|
||||||
|
if (err != Z_OK)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// identify a music lump's type and set up a player for it
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
MusInfo *I_RegisterSong (MusicIO::FileInterface *reader, EMidiDevice device, const char *Args)
|
||||||
|
{
|
||||||
|
MusInfo *info = nullptr;
|
||||||
|
StreamSource *streamsource = nullptr;
|
||||||
|
const char *fmt;
|
||||||
|
uint32_t id[32/4];
|
||||||
|
|
||||||
|
if(reader->read(id, 32) != 32 || reader->seek(-32, SEEK_CUR) != 0)
|
||||||
|
{
|
||||||
|
reader->close();
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// 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)
|
||||||
|
{
|
||||||
|
// 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, SEEK_CUR) != 0)
|
||||||
|
{
|
||||||
|
reader->close();
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EMIDIType miditype = IdentifyMIDIType(id, sizeof(id));
|
||||||
|
if (miditype != MIDI_NOTMIDI)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
// non-Windows platforms don't support MDEV_MMAPI so map to MDEV_SNDSYS
|
||||||
|
if (device == MDEV_MMAPI)
|
||||||
|
device = MDEV_SNDSYS;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
info = CreateMIDIStreamer(source, device, Args? Args : "");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for CDDA "format"
|
||||||
|
else 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 = CDDA_OpenSong(reader);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
{
|
||||||
|
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, miscConfig.snd_outputrate);
|
||||||
|
}
|
||||||
|
// Check for module formats
|
||||||
|
else
|
||||||
|
{
|
||||||
|
streamsource = MOD_OpenSong(reader, miscConfig.snd_outputrate);
|
||||||
|
}
|
||||||
|
if (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)
|
||||||
|
{
|
||||||
|
// File could not be identified as music.
|
||||||
|
if (reader) reader->close();
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info && !info->IsValid())
|
||||||
|
{
|
||||||
|
delete info;
|
||||||
|
info = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
// Make sure the reader is closed if this function abnormally terminates
|
||||||
|
if (reader) reader->close();
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
if (reader) reader->close();
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// play CD music
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
MusInfo *I_RegisterCDSong (int track, int id)
|
||||||
|
{
|
||||||
|
MusInfo *info = CD_OpenSong (track, id);
|
||||||
|
|
||||||
|
if (info && !info->IsValid ())
|
||||||
|
{
|
||||||
|
delete info;
|
||||||
|
info = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
void TimidityPP_Shutdown();
|
||||||
|
extern "C" void dumb_exit();
|
||||||
|
|
||||||
|
void ZMusic_Shutdown()
|
||||||
|
{
|
||||||
|
// free static data in the backends.
|
||||||
|
TimidityPP_Shutdown();
|
||||||
|
dumb_exit();
|
||||||
|
}
|
|
@ -151,10 +151,16 @@ void SetDmxGus(const void* data, unsigned len);
|
||||||
|
|
||||||
// These exports are needed by the MIDI dumpers which need to remain on the client side.
|
// These exports are needed by the MIDI dumpers which need to remain on the client side.
|
||||||
class MIDISource; // abstract for the client
|
class MIDISource; // abstract for the client
|
||||||
|
class MusInfo;
|
||||||
EMIDIType IdentifyMIDIType(uint32_t *id, int size);
|
EMIDIType IdentifyMIDIType(uint32_t *id, int size);
|
||||||
MIDISource *CreateMIDISource(const uint8_t *data, size_t length, EMIDIType miditype);
|
MIDISource *CreateMIDISource(const uint8_t *data, size_t length, EMIDIType miditype);
|
||||||
void MIDIDumpWave(MIDISource* source, EMidiDevice devtype, const char* devarg, const char* outname, int subsong, int samplerate);
|
void MIDIDumpWave(MIDISource* source, EMidiDevice devtype, const char* devarg, const char* outname, int subsong, int samplerate);
|
||||||
|
|
||||||
|
MusInfo *I_RegisterSong (MusicIO::FileInterface *reader, EMidiDevice device, const char *Args);
|
||||||
|
MusInfo *I_RegisterCDSong (int track, int cdid = 0);
|
||||||
|
|
||||||
|
void ZMusic_Shutdown();
|
||||||
|
|
||||||
class MusInfo;
|
class MusInfo;
|
||||||
// Configuration interface. The return value specifies if a music restart is needed.
|
// Configuration interface. The return value specifies if a music restart is needed.
|
||||||
// RealValue should be written back to the CVAR or whatever other method the client uses to store configuration state.
|
// RealValue should be written back to the CVAR or whatever other method the client uses to store configuration state.
|
||||||
|
|
|
@ -39,7 +39,6 @@
|
||||||
|
|
||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
|
|
||||||
#include "i_musicinterns.h"
|
|
||||||
#include "m_argv.h"
|
#include "m_argv.h"
|
||||||
#include "w_wad.h"
|
#include "w_wad.h"
|
||||||
#include "c_dispatch.h"
|
#include "c_dispatch.h"
|
||||||
|
@ -59,16 +58,7 @@
|
||||||
#include "filereadermusicinterface.h"
|
#include "filereadermusicinterface.h"
|
||||||
#include "../libraries/zmusic/midisources/midisource.h"
|
#include "../libraries/zmusic/midisources/midisource.h"
|
||||||
|
|
||||||
#define GZIP_ID1 31
|
|
||||||
#define GZIP_ID2 139
|
|
||||||
#define GZIP_CM 8
|
|
||||||
#define GZIP_ID MAKE_ID(GZIP_ID1,GZIP_ID2,GZIP_CM,0)
|
|
||||||
|
|
||||||
#define GZIP_FTEXT 1
|
|
||||||
#define GZIP_FHCRC 2
|
|
||||||
#define GZIP_FEXTRA 4
|
|
||||||
#define GZIP_FNAME 8
|
|
||||||
#define GZIP_FCOMMENT 16
|
|
||||||
|
|
||||||
|
|
||||||
void I_InitSoundFonts();
|
void I_InitSoundFonts();
|
||||||
|
@ -287,257 +277,6 @@ void I_ShutdownMusic(bool onexit)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
|
||||||
//
|
|
||||||
// identify a music lump's type and set up a player for it
|
|
||||||
//
|
|
||||||
//==========================================================================
|
|
||||||
|
|
||||||
MusInfo *I_RegisterSong (MusicIO::FileInterface *reader, EMidiDevice device, const char *Args)
|
|
||||||
{
|
|
||||||
MusInfo *info = nullptr;
|
|
||||||
StreamSource *streamsource = nullptr;
|
|
||||||
const char *fmt;
|
|
||||||
uint32_t id[32/4];
|
|
||||||
|
|
||||||
if(reader->read(id, 32) != 32 || reader->seek(-32, FileReader::SeekCur) != 0)
|
|
||||||
{
|
|
||||||
reader->close();
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// 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)
|
|
||||||
{
|
|
||||||
// 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)
|
|
||||||
{
|
|
||||||
reader->close();
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
EMIDIType miditype = IdentifyMIDIType(id, sizeof(id));
|
|
||||||
if (miditype != MIDI_NOTMIDI)
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef _WIN32
|
|
||||||
// non-Windows platforms don't support MDEV_MMAPI so map to MDEV_SNDSYS
|
|
||||||
if (device == MDEV_MMAPI)
|
|
||||||
device = MDEV_SNDSYS;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
info = CreateMIDIStreamer(source, device, Args? Args : "");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for CDDA "format"
|
|
||||||
else 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 = CDDA_OpenSong(reader);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
|
||||||
{
|
|
||||||
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, (int)GSnd->GetOutputRate());
|
|
||||||
}
|
|
||||||
// Check for module formats
|
|
||||||
else
|
|
||||||
{
|
|
||||||
streamsource = MOD_OpenSong(reader, (int)GSnd->GetOutputRate());
|
|
||||||
}
|
|
||||||
if (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)
|
|
||||||
{
|
|
||||||
// File could not be identified as music.
|
|
||||||
if (reader) reader->close();
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (info && !info->IsValid())
|
|
||||||
{
|
|
||||||
delete info;
|
|
||||||
info = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (...)
|
|
||||||
{
|
|
||||||
// Make sure the reader is closed if this function abnormally terminates
|
|
||||||
if (reader) reader->close();
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
if (reader) reader->close();
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
|
|
||||||
//==========================================================================
|
|
||||||
//
|
|
||||||
// play CD music
|
|
||||||
//
|
|
||||||
//==========================================================================
|
|
||||||
|
|
||||||
MusInfo *I_RegisterCDSong (int track, int id)
|
|
||||||
{
|
|
||||||
MusInfo *info = CD_OpenSong (track, id);
|
|
||||||
|
|
||||||
if (info && !info->IsValid ())
|
|
||||||
{
|
|
||||||
delete info;
|
|
||||||
info = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
|
|
||||||
//==========================================================================
|
|
||||||
//
|
|
||||||
// ungzip
|
|
||||||
//
|
|
||||||
// VGZ files are compressed with gzip, so we need to uncompress them before
|
|
||||||
// handing them to GME.
|
|
||||||
//
|
|
||||||
//==========================================================================
|
|
||||||
|
|
||||||
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;
|
|
||||||
uint8_t flags = data[3];
|
|
||||||
unsigned isize;
|
|
||||||
z_stream stream;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
// Find start of compressed data stream
|
|
||||||
if (flags & GZIP_FEXTRA)
|
|
||||||
{
|
|
||||||
compstart += 2 + LittleShort(*(uint16_t *)(data + 10));
|
|
||||||
}
|
|
||||||
if (flags & GZIP_FNAME)
|
|
||||||
{
|
|
||||||
while (compstart < max && *compstart != 0)
|
|
||||||
{
|
|
||||||
compstart++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (flags & GZIP_FCOMMENT)
|
|
||||||
{
|
|
||||||
while (compstart < max && *compstart != 0)
|
|
||||||
{
|
|
||||||
compstart++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (flags & GZIP_FHCRC)
|
|
||||||
{
|
|
||||||
compstart += 2;
|
|
||||||
}
|
|
||||||
if (compstart >= max - 1)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Decompress
|
|
||||||
isize = LittleLong(*(uint32_t *)(data + complen - 4));
|
|
||||||
newdata.resize(isize);
|
|
||||||
|
|
||||||
stream.next_in = (Bytef *)compstart;
|
|
||||||
stream.avail_in = (uInt)(max - compstart);
|
|
||||||
stream.next_out = &newdata[0];
|
|
||||||
stream.avail_out = isize;
|
|
||||||
stream.zalloc = (alloc_func)0;
|
|
||||||
stream.zfree = (free_func)0;
|
|
||||||
|
|
||||||
err = inflateInit2(&stream, -MAX_WBITS);
|
|
||||||
if (err != Z_OK)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
err = inflate(&stream, Z_FINISH);
|
|
||||||
if (err != Z_STREAM_END)
|
|
||||||
{
|
|
||||||
inflateEnd(&stream);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
err = inflateEnd(&stream);
|
|
||||||
if (err != Z_OK)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
|
|
|
@ -1,32 +0,0 @@
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <mutex>
|
|
||||||
#include <string>
|
|
||||||
#include "zmusic/zmusic.h"
|
|
||||||
|
|
||||||
class MIDISource;
|
|
||||||
class MIDIDevice;
|
|
||||||
class OPLmusicFile;
|
|
||||||
class StreamSource;
|
|
||||||
class MusInfo;
|
|
||||||
|
|
||||||
MusInfo *OpenStreamSong(StreamSource *source);
|
|
||||||
const char *GME_CheckFormat(uint32_t header);
|
|
||||||
MusInfo* CDDA_OpenSong(MusicIO::FileInterface* reader);
|
|
||||||
MusInfo* CD_OpenSong(int track, int id);
|
|
||||||
MusInfo* CreateMIDIStreamer(MIDISource *source, EMidiDevice devtype, const char* args);
|
|
||||||
|
|
||||||
// Registers a song handle to song data.
|
|
||||||
|
|
||||||
MusInfo *I_RegisterSong (MusicIO::FileInterface *reader, EMidiDevice device, const char *Args);
|
|
||||||
MusInfo *I_RegisterCDSong (int track, int cdid = 0);
|
|
||||||
|
|
||||||
void TimidityPP_Shutdown();
|
|
||||||
extern "C" void dumb_exit();
|
|
||||||
|
|
||||||
inline void ZMusic_Shutdown()
|
|
||||||
{
|
|
||||||
// free static data in the backends.
|
|
||||||
TimidityPP_Shutdown();
|
|
||||||
dumb_exit();
|
|
||||||
}
|
|
|
@ -42,7 +42,6 @@
|
||||||
#include "filereadermusicinterface.h"
|
#include "filereadermusicinterface.h"
|
||||||
#include "zmusic/zmusic.h"
|
#include "zmusic/zmusic.h"
|
||||||
#include "resourcefiles/resourcefile.h"
|
#include "resourcefiles/resourcefile.h"
|
||||||
#include "../libraries/timidityplus/timiditypp/common.h"
|
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
|
|
|
@ -88,8 +88,7 @@
|
||||||
#include "s_music.h"
|
#include "s_music.h"
|
||||||
#include "filereadermusicinterface.h"
|
#include "filereadermusicinterface.h"
|
||||||
#include "zmusic/musinfo.h"
|
#include "zmusic/musinfo.h"
|
||||||
|
#include "zmusic/zmusic.h"
|
||||||
#include "i_musicinterns.h"
|
|
||||||
|
|
||||||
// MACROS ------------------------------------------------------------------
|
// MACROS ------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue