Skip to content

Commit

Permalink
Switch to libxmp for most tracker formats
Browse files Browse the repository at this point in the history
DSIK still uses foo_DUMB
  • Loading branch information
Cacodemon345 committed Oct 4, 2024
1 parent 7307ecf commit 0b9d08d
Show file tree
Hide file tree
Showing 129 changed files with 53,292 additions and 2 deletions.
3 changes: 2 additions & 1 deletion source/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ INTERFACE
streamsources/music_dumb.cpp
streamsources/music_gme.cpp
streamsources/music_libsndfile.cpp
streamsources/music_libxmp.cpp
streamsources/music_opl.cpp
streamsources/music_xa.cpp
musicformats/music_stream.cpp
Expand Down Expand Up @@ -127,7 +128,7 @@ if(WIN32)
)
endif()

target_link_libraries(zmusic-obj INTERFACE dumb gme miniz ${CMAKE_DL_LIBS})
target_link_libraries(zmusic-obj INTERFACE dumb gme libxmp miniz ${CMAKE_DL_LIBS})

target_include_directories(zmusic-obj
INTERFACE
Expand Down
153 changes: 153 additions & 0 deletions source/streamsources/music_libxmp.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
/*
** music_libxmp.cpp
** libxmp module player.
**
**---------------------------------------------------------------------------
** Copyright 2024 Cacodemon345
** 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 <math.h>
#include <mutex>
#include <string>
#include <stdint.h>
#include "streamsource.h"


#include "../libxmp/include/xmp.h"
#include "zmusic/m_swap.h"
#include "zmusic/mididefs.h"
#include "zmusic/midiconfig.h"
#include "fileio.h"

extern DumbConfig dumbConfig;

static unsigned long xmp_read(void *dest, unsigned long len, unsigned long nmemb, void *priv)
{
if (len == 0 || nmemb == 0)
return (unsigned long)0;

MusicIO::FileInterface* interface = (MusicIO::FileInterface*)priv;

auto origpos = interface->tell();
auto length = interface->read(dest, (int32_t)(len * nmemb));

if (length != len * nmemb)
{
// Let's hope the compiler doesn't misoptimize this.
interface->seek(origpos + (length / len) * len, SEEK_SET);
}
return length / len;
}

static struct xmp_callbacks callbacks =
{
xmp_read,
[](void *priv, long offset, int whence) -> int { return ((MusicIO::FileInterface*)priv)->seek(offset, whence); },
[](void *priv) -> long { return ((MusicIO::FileInterface*)priv)->tell(); },
[](void *priv) -> int { return 0; }
};

class XMPSong : public StreamSource
{
private:
xmp_context context = nullptr;
int samplerate = 44100;
int subsong = 0;

public:
XMPSong(xmp_context ctx, int samplerate);
bool SetSubsong(int subsong) override;
bool Start() override;
SoundStreamInfoEx GetFormatEx() override;

protected:
bool GetData(void *buffer, size_t len) override;
};

XMPSong::XMPSong(xmp_context ctx, int rate)
{
context = ctx;
samplerate = (dumbConfig.mod_samplerate != 0) ? dumbConfig.mod_samplerate : rate;
xmp_set_player(context, XMP_PLAYER_VOLUME, dumbConfig.mod_dumb_mastervolume * 100);
xmp_set_player(context, XMP_PLAYER_INTERP, dumbConfig.mod_interp);
}

SoundStreamInfoEx XMPSong::GetFormatEx()
{
return { 32 * 1024, samplerate, SampleType_Int16, ChannelConfig_Stereo };
}

bool XMPSong::SetSubsong(int subsong)
{
this->subsong = subsong;
if (xmp_get_player(context, XMP_PLAYER_STATE) >= XMP_STATE_PLAYING)
return xmp_set_position(context, subsong) >= 0;
return true;
}

bool XMPSong::GetData(void *buffer, size_t len)
{
int ret = xmp_play_buffer(context, buffer, len, 0);
// These two calls are very lightweight.
xmp_set_player(context, XMP_PLAYER_VOLUME, dumbConfig.mod_dumb_mastervolume * 100);
xmp_set_player(context, XMP_PLAYER_INTERP, dumbConfig.mod_interp);
if (ret < 0 && m_Looping)
{
xmp_restart_module(context);
xmp_set_position(context, subsong);
return true;
}

return ret >= 0;
}

bool XMPSong::Start()
{
return xmp_start_player(context, samplerate, 0) >= 0;
}

StreamSource* XMP_OpenSong(MusicIO::FileInterface* reader, int samplerate)
{
if (xmp_test_module_from_callbacks((void*)reader, callbacks, nullptr) < 0)
return nullptr;

xmp_context ctx = xmp_create_context();
if (!ctx)
return nullptr;

reader->seek(0, SEEK_SET);

if (xmp_load_module_from_callbacks(ctx, (void*)reader, callbacks) < 0)
{
return nullptr;
}

return new XMPSong(ctx, samplerate);
}

1 change: 1 addition & 0 deletions source/streamsources/streamsource.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ class StreamSource


StreamSource *MOD_OpenSong(MusicIO::FileInterface* reader, int samplerate);
StreamSource *XMP_OpenSong(MusicIO::FileInterface* reader, int samplerate);
StreamSource* GME_OpenSong(MusicIO::FileInterface* reader, const char* fmt, int sample_rate);
StreamSource *SndFile_OpenSong(MusicIO::FileInterface* fr);
StreamSource* XA_OpenSong(MusicIO::FileInterface* reader);
Expand Down
11 changes: 10 additions & 1 deletion source/zmusic/zmusic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -257,10 +257,19 @@ static MusInfo *ZMusic_OpenSongInternal (MusicIO::FileInterface *reader, EMidiD
streamsource = GME_OpenSong(reader, fmt, miscConfig.snd_outputrate);
}
// Check for module formats
else
else if ((id[0] == MAKE_ID('R', 'I', 'F', 'F') && id[2] == MAKE_ID('D', 'S', 'M', 'F')))
{
streamsource = MOD_OpenSong(reader, miscConfig.snd_outputrate);
}
else
{
streamsource = XMP_OpenSong(reader, miscConfig.snd_outputrate);
if (!streamsource) {
ZMusic_Printf(ZMUSIC_MSG_WARNING, "Fallback to DUMB\n");
reader->seek(0, SEEK_SET);
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.
Expand Down
1 change: 1 addition & 0 deletions thirdparty/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,5 @@ add_subdirectory(timidity)
add_subdirectory(timidityplus)
add_subdirectory(wildmidi)
add_subdirectory(oplsynth)
add_subdirectory(libxmp)
add_subdirectory(fluidsynth/src)
102 changes: 102 additions & 0 deletions thirdparty/libxmp/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
make_release_only()

add_library(libxmp OBJECT
src/virtual.c
src/format.c
src/period.c
src/player.c
src/read_event.c
src/dataio.c
src/misc.c
src/mkstemp.c
src/md5.c
src/lfo.c
src/scan.c
src/control.c
src/far_extras.c
src/med_extras.c
src/filter.c
src/effects.c
src/mixer.c
src/mix_all.c
src/load_helpers.c
src/load.c
src/hio.c
src/hmn_extras.c
src/extras.c
src/smix.c
src/filetype.c
src/memio.c
src/tempfile.c
src/mix_paula.c
src/win32.c
src/loaders/common.c
src/loaders/iff.c
src/loaders/itsex.c
src/loaders/lzw.c
src/loaders/voltable.c
src/loaders/sample.c
src/loaders/vorbis.c
src/loaders/xm_load.c
src/loaders/mod_load.c
src/loaders/s3m_load.c
src/loaders/stm_load.c
src/loaders/669_load.c
src/loaders/far_load.c
src/loaders/mtm_load.c
src/loaders/ptm_load.c
src/loaders/okt_load.c
src/loaders/ult_load.c
src/loaders/mdl_load.c
src/loaders/it_load.c
src/loaders/stx_load.c
src/loaders/pt3_load.c
src/loaders/sfx_load.c
src/loaders/flt_load.c
src/loaders/st_load.c
src/loaders/emod_load.c
src/loaders/imf_load.c
src/loaders/digi_load.c
src/loaders/fnk_load.c
src/loaders/ice_load.c
src/loaders/liq_load.c
src/loaders/ims_load.c
src/loaders/masi_load.c
src/loaders/masi16_load.c
src/loaders/amf_load.c
src/loaders/stim_load.c
src/loaders/mmd_common.c
src/loaders/mmd1_load.c
src/loaders/mmd3_load.c
src/loaders/rtm_load.c
src/loaders/dt_load.c
src/loaders/no_load.c
src/loaders/arch_load.c
src/loaders/sym_load.c
src/loaders/med2_load.c
src/loaders/med3_load.c
src/loaders/med4_load.c
src/loaders/dbm_load.c
src/loaders/umx_load.c
src/loaders/gdm_load.c
src/loaders/pw_load.c
src/loaders/gal5_load.c
src/loaders/gal4_load.c
src/loaders/mfp_load.c
src/loaders/asylum_load.c
src/loaders/muse_load.c
src/loaders/hmn_load.c
src/loaders/mgt_load.c
src/loaders/chip_load.c
src/loaders/abk_load.c
src/loaders/coco_load.c
src/loaders/xmf_load.c
)

use_fast_math(libxmp)

target_include_directories(libxmp PRIVATE include ../miniz/)
target_compile_definitions(libxmp PRIVATE -DHAVE_POWF=1 -DLIBXMP_STATIC=1 -DLIBXMP_NO_PROWIZARD=1 -DLIBXMP_NO_DEPACKERS=1)
if (NOT WIN32)
target_compile_definitions(libxmp PRIVATE -DHAVE_DIRENT=1 -DHAVE_UNISTD=1)
endif ()
Loading

0 comments on commit 0b9d08d

Please sign in to comment.