use libxmp instead
This commit is contained in:
parent
4c570131c3
commit
6f8ee4c7ae
26 changed files with 333 additions and 4039 deletions
|
|
@ -12,6 +12,7 @@ static void cleanup(int sig){
|
|||
|
||||
int main(){
|
||||
fishbone::SoundDriver* drv;
|
||||
fishbone::Sound* snd;
|
||||
|
||||
#ifndef _WIN32
|
||||
signal(SIGINT, cleanup);
|
||||
|
|
@ -20,7 +21,9 @@ int main(){
|
|||
|
||||
drv = new fishbone::SoundDriver();
|
||||
|
||||
drv->mixer.open("betrayal.mod");
|
||||
snd = drv->mixer.open("dubmood.xm");
|
||||
snd->setLoop(true);
|
||||
snd->resume();
|
||||
|
||||
while(!quit);
|
||||
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ fb_add_dep(fishbone stb_image)
|
|||
# Sound
|
||||
fb_add_dep(fishbone stb_vorbis)
|
||||
fb_add_dep(fishbone dr_libs)
|
||||
fb_add_dep(fishbone jar)
|
||||
fb_add_dep(fishbone libxmp)
|
||||
|
||||
# Compression
|
||||
fb_add_dep(fishbone lz4)
|
||||
|
|
|
|||
|
|
@ -1,2 +0,0 @@
|
|||
add_library(jar INTERFACE)
|
||||
target_include_directories(jar INTERFACE jar)
|
||||
12
engine/cmake/deps/libxmp.cmake
Normal file
12
engine/cmake/deps/libxmp.cmake
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/CPM.cmake")
|
||||
|
||||
CPMAddPackage(
|
||||
NAME "libxmp"
|
||||
GITHUB_REPOSITORY "libxmp/libxmp"
|
||||
GIT_TAG master
|
||||
OPTIONS
|
||||
"BUILD_SHARED OFF"
|
||||
"BUILD_LITE ON"
|
||||
)
|
||||
|
||||
add_library(deps::libxmp ALIAS xmp_lite_static)
|
||||
|
|
@ -14,7 +14,9 @@ function(fb_add_dep TARGET_NAME DEP_NAME)
|
|||
|
||||
include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/deps/${DEP_NAME}.cmake")
|
||||
|
||||
add_library(deps::${DEP_NAME} ALIAS ${DEP_NAME})
|
||||
if(NOT TARGET deps::${DEP_NAME})
|
||||
add_library(deps::${DEP_NAME} ALIAS ${DEP_NAME})
|
||||
endif()
|
||||
|
||||
target_link_libraries(${TARGET_NAME} ${LINK_SCOPE} deps::${DEP_NAME})
|
||||
endfunction()
|
||||
|
|
|
|||
27
engine/include/fishbone/file.h
Normal file
27
engine/include/fishbone/file.h
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
#ifndef __FISHBONE_FILE_H__
|
||||
#define __FISHBONE_FILE_H__
|
||||
|
||||
namespace fishbone {
|
||||
class File;
|
||||
};
|
||||
|
||||
#include <fishbone/machdep.h>
|
||||
|
||||
namespace fishbone {
|
||||
class File {
|
||||
std::ifstream ifs;
|
||||
std::ofstream ofs;
|
||||
|
||||
public:
|
||||
File(std::string path, std::string type);
|
||||
~File();
|
||||
|
||||
size_t read(void* buffer, size_t size);
|
||||
size_t write(const void* buffer, size_t size);
|
||||
|
||||
size_t size;
|
||||
bool good;
|
||||
};
|
||||
}; // namespace fishbone
|
||||
|
||||
#endif
|
||||
|
|
@ -5,5 +5,6 @@
|
|||
#include <fishbone/sound.h>
|
||||
#include <fishbone/mixer.h>
|
||||
#include <fishbone/thread.h>
|
||||
#include <fishbone/file.h>
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -2,6 +2,10 @@
|
|||
#define __FISHBONE_MACHDEP_H__
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
#include <fishbone/config.h>
|
||||
|
||||
|
|
@ -11,8 +15,7 @@
|
|||
#endif
|
||||
|
||||
#define STB_VORBIS_HEADER_ONLY
|
||||
#include <jar_xm.h>
|
||||
#include <jar_mod.h>
|
||||
#include <xmp.h>
|
||||
#include <dr_mp3.h>
|
||||
#include <dr_wav.h>
|
||||
#include <dr_flac.h>
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@ namespace fishbone {
|
|||
|
||||
void read(short* buffer, size_t frames);
|
||||
fishbone::Sound* open(const char* path);
|
||||
void lock();
|
||||
void unlock();
|
||||
|
||||
static const int rate = 44100;
|
||||
std::vector<fishbone::SoundLoader*> loaders;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,35 @@
|
|||
#ifndef __FISHBONE_SOUND_H__
|
||||
#define __FISHBONE_SOUND_H__
|
||||
|
||||
#define FB_SOUND_DECL(prefix) \
|
||||
class prefix##SoundLoader; \
|
||||
class prefix##Sound
|
||||
|
||||
#define FB_SOUND_DEF(prefix) \
|
||||
class prefix##SoundLoader : public SoundLoader { \
|
||||
public: \
|
||||
Sound* open(Mixer* mixer, void* buffer, size_t size); \
|
||||
int read(Sound* sound, short* buffer, size_t frames); \
|
||||
void seek(Sound* sound, size_t pos); \
|
||||
}; \
|
||||
\
|
||||
class prefix##Sound : public Sound { \
|
||||
public: \
|
||||
prefix##Sound(Mixer* mixer, prefix##SoundLoader* loader, struct Sound::Impl* impl) \
|
||||
: Sound(mixer, loader, impl){}; \
|
||||
~prefix##Sound(); \
|
||||
}
|
||||
|
||||
#define FB_SOUND_LOADERS LOADER(XMP)
|
||||
|
||||
namespace fishbone {
|
||||
class SoundDriver;
|
||||
class SoundLoader;
|
||||
class Sound;
|
||||
|
||||
#define LOADER(X) FB_SOUND_DECL(X);
|
||||
FB_SOUND_LOADERS
|
||||
#undef LOADER
|
||||
}; // namespace fishbone
|
||||
|
||||
#include <fishbone/machdep.h>
|
||||
|
|
@ -27,21 +52,43 @@ namespace fishbone {
|
|||
SoundLoader();
|
||||
~SoundLoader();
|
||||
|
||||
virtual Sound* open(void* buffer, size_t size);
|
||||
virtual Sound* open(Mixer* mixer, void* buffer, size_t size);
|
||||
virtual int read(Sound* sound, short* buffer, size_t frames);
|
||||
virtual void seek(Sound* sound, size_t pos);
|
||||
};
|
||||
|
||||
class Sound {
|
||||
public:
|
||||
struct Impl;
|
||||
Impl* impl;
|
||||
|
||||
private:
|
||||
SoundLoader* loader;
|
||||
Mixer* mixer;
|
||||
|
||||
protected:
|
||||
bool loop;
|
||||
bool paused;
|
||||
|
||||
public:
|
||||
Sound(SoundLoader* loader);
|
||||
Sound(Mixer* mixer, SoundLoader* loader, struct Impl* impl);
|
||||
|
||||
int read(short* buffer, size_t frames);
|
||||
int read(short* buffer, size_t frames);
|
||||
void seek(size_t pos);
|
||||
void resume();
|
||||
void pause();
|
||||
void pauseNoLock(); /* do NOT use this! */
|
||||
bool isPaused();
|
||||
void setLoop(bool v);
|
||||
bool isLoop();
|
||||
|
||||
int rate;
|
||||
int channels;
|
||||
};
|
||||
|
||||
#define LOADER(X) FB_SOUND_DEF(X);
|
||||
FB_SOUND_LOADERS
|
||||
#undef LOADER
|
||||
}; // namespace fishbone
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,14 +0,0 @@
|
|||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
Version 2, December 2004
|
||||
|
||||
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim or modified
|
||||
copies of this license document, and changing it is allowed as long
|
||||
as the name is changed.
|
||||
|
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. You just DO WHAT THE FUCK YOU WANT TO.
|
||||
|
||||
1396
engine/jar/jar_mod.h
1396
engine/jar/jar_mod.h
File diff suppressed because it is too large
Load diff
2605
engine/jar/jar_xm.h
2605
engine/jar/jar_xm.h
File diff suppressed because it is too large
Load diff
2
engine/src/external/jar_mod.c
vendored
2
engine/src/external/jar_mod.c
vendored
|
|
@ -1,2 +0,0 @@
|
|||
#define JAR_MOD_IMPLEMENTATION
|
||||
#include <jar_mod.h>
|
||||
2
engine/src/external/jar_xm.c
vendored
2
engine/src/external/jar_xm.c
vendored
|
|
@ -1,2 +0,0 @@
|
|||
#define JAR_XM_IMPLEMENTATION
|
||||
#include <jar_xm.h>
|
||||
43
engine/src/file.cc
Normal file
43
engine/src/file.cc
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
#include <fishbone/file.h>
|
||||
|
||||
fishbone::File::File(std::string path, std::string type) {
|
||||
this->good = false;
|
||||
this->size = 0;
|
||||
|
||||
if(type == "r") {
|
||||
this->ifs = std::ifstream(path, std::ios::binary);
|
||||
|
||||
this->ifs.seekg(0, std::ios_base::end);
|
||||
this->size = this->ifs.tellg();
|
||||
this->ifs.seekg(0, std::ios_base::beg);
|
||||
|
||||
if(!this->ifs.good()) return;
|
||||
} else if(type == "w") {
|
||||
this->ofs = std::ofstream(path, std::ios::binary);
|
||||
|
||||
if(!this->ofs.good()) return;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
this->good = true;
|
||||
}
|
||||
|
||||
fishbone::File::~File() {
|
||||
}
|
||||
|
||||
size_t fishbone::File::read(void* buffer, size_t size) {
|
||||
if(!this->ifs.good()) return -1;
|
||||
|
||||
if(!this->ifs.read(reinterpret_cast<char*>(buffer), size)) return -1;
|
||||
|
||||
return this->ifs.gcount();
|
||||
}
|
||||
|
||||
size_t fishbone::File::write(const void* buffer, size_t size) {
|
||||
if(!this->ofs.good()) return -1;
|
||||
|
||||
if(!this->ofs.write(reinterpret_cast<const char*>(buffer), size)) return -1;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
|
@ -2,6 +2,10 @@
|
|||
|
||||
fishbone::Mixer::Mixer() {
|
||||
this->mutex = new fishbone::Mutex();
|
||||
|
||||
#define LOADER(X) this->loaders.push_back(new fishbone::X##SoundLoader());
|
||||
FB_SOUND_LOADERS
|
||||
#undef LOADER
|
||||
}
|
||||
|
||||
fishbone::Mixer::~Mixer() {
|
||||
|
|
@ -20,18 +24,86 @@ void fishbone::Mixer::read(short* buffer, size_t frames) {
|
|||
|
||||
for(int i = 0; i < frames * 2; i++) tmp[i] = 0;
|
||||
|
||||
this->mutex->lock();
|
||||
this->mutex->unlock();
|
||||
this->lock();
|
||||
for(int i = 0; i < this->sounds.size(); i++) {
|
||||
size_t ask;
|
||||
short* req;
|
||||
size_t got;
|
||||
|
||||
if(this->sounds[i]->isPaused()) continue;
|
||||
|
||||
ask = frames * this->sounds[i]->rate / fishbone::Mixer::rate;
|
||||
req = new short[ask * this->sounds[i]->channels];
|
||||
got = this->sounds[i]->read(req, ask) * fishbone::Mixer::rate / this->sounds[i]->rate;
|
||||
|
||||
if(got <= 0) {
|
||||
delete[] req;
|
||||
|
||||
this->sounds[i]->pauseNoLock();
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
for(int j = 0; j < got; j++) {
|
||||
short l, r;
|
||||
|
||||
if(this->sounds[i]->channels == 1) {
|
||||
l = r = req[j * this->sounds[i]->rate / fishbone::Mixer::rate];
|
||||
} else if(this->sounds[i]->channels == 2) {
|
||||
l = req[(j * this->sounds[i]->rate / fishbone::Mixer::rate) * 2 + 0];
|
||||
r = req[(j * this->sounds[i]->rate / fishbone::Mixer::rate) * 2 + 1];
|
||||
}
|
||||
|
||||
tmp[2 * j + 0] += l / 32767.0;
|
||||
tmp[2 * j + 1] += r / 32767.0;
|
||||
}
|
||||
|
||||
delete[] req;
|
||||
}
|
||||
this->unlock();
|
||||
|
||||
for(int i = 0; i < frames * 2; i++) buffer[i] = tmp[i] * 32767;
|
||||
|
||||
delete tmp;
|
||||
delete[] tmp;
|
||||
}
|
||||
|
||||
fishbone::Sound* fishbone::Mixer::open(const char* path) {
|
||||
fishbone::File f(path, "r");
|
||||
unsigned char* buffer;
|
||||
fishbone::Sound* snd;
|
||||
|
||||
if(!f.good) return nullptr;
|
||||
|
||||
buffer = new unsigned char[f.size];
|
||||
|
||||
f.read(buffer, f.size);
|
||||
|
||||
for(int i = 0; i < this->loaders.size(); i++) {
|
||||
// this->loaders[i]->open();
|
||||
snd = this->loaders[i]->open(this, buffer, f.size);
|
||||
|
||||
if(snd != nullptr) break;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
delete[] buffer;
|
||||
|
||||
if(snd != nullptr) {
|
||||
if(snd->channels != 1 && snd->channels != 2) {
|
||||
delete snd;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
this->lock();
|
||||
this->sounds.push_back(snd);
|
||||
this->unlock();
|
||||
}
|
||||
|
||||
return snd;
|
||||
}
|
||||
|
||||
void fishbone::Mixer::lock() {
|
||||
this->mutex->lock();
|
||||
}
|
||||
|
||||
void fishbone::Mixer::unlock() {
|
||||
this->mutex->unlock();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ fishbone::SoundLoader::SoundLoader() {
|
|||
fishbone::SoundLoader::~SoundLoader() {
|
||||
}
|
||||
|
||||
fishbone::Sound* fishbone::SoundLoader::open(void* buffer, size_t size) {
|
||||
fishbone::Sound* fishbone::SoundLoader::open(fishbone::Mixer* mixer, void* buffer, size_t size) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
@ -14,15 +14,63 @@ int fishbone::SoundLoader::read(fishbone::Sound* sound, short* buffer, size_t fr
|
|||
return 0;
|
||||
}
|
||||
|
||||
fishbone::Sound::Sound(SoundLoader* loader) {
|
||||
void fishbone::SoundLoader::seek(fishbone::Sound* sound, size_t pos) {
|
||||
}
|
||||
|
||||
fishbone::Sound::Sound(fishbone::Mixer* mixer, fishbone::SoundLoader* loader, struct fishbone::Sound::Impl* impl) {
|
||||
this->mixer = mixer;
|
||||
this->loader = loader;
|
||||
this->impl = impl;
|
||||
|
||||
this->paused = true;
|
||||
this->loop = false;
|
||||
}
|
||||
|
||||
int fishbone::Sound::read(short* buffer, size_t frames) {
|
||||
int seek = 0;
|
||||
int l;
|
||||
|
||||
while((l = this->loader->read(this, buffer + seek * this->channels, frames - seek)) > 0) seek += l;
|
||||
while(seek < frames && (l = this->loader->read(this, buffer + seek * this->channels, frames - seek)) > 0) seek += l;
|
||||
|
||||
return seek;
|
||||
}
|
||||
|
||||
void fishbone::Sound::seek(size_t pos) {
|
||||
this->loader->seek(this, pos);
|
||||
}
|
||||
|
||||
void fishbone::Sound::resume() {
|
||||
this->mixer->lock();
|
||||
this->paused = false;
|
||||
this->mixer->unlock();
|
||||
}
|
||||
|
||||
void fishbone::Sound::pause() {
|
||||
this->mixer->lock();
|
||||
this->pauseNoLock();
|
||||
this->mixer->unlock();
|
||||
}
|
||||
|
||||
void fishbone::Sound::pauseNoLock() {
|
||||
this->paused = true;
|
||||
}
|
||||
|
||||
bool fishbone::Sound::isPaused() {
|
||||
bool v;
|
||||
|
||||
this->mixer->lock();
|
||||
v = this->paused;
|
||||
this->mixer->unlock();
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
void fishbone::Sound::setLoop(bool v) {
|
||||
this->mixer->lock();
|
||||
this->loop = v;
|
||||
this->mixer->unlock();
|
||||
}
|
||||
|
||||
bool fishbone::Sound::isLoop() {
|
||||
return this->loop;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
#ifdef FISHBONE_SOUND_USE_SDL2
|
||||
#include <fishbone/foundation.h>
|
||||
|
||||
static int sdl_audio_init = 0;
|
||||
static bool sdl_audio_init = false;
|
||||
|
||||
static void SDLCALL sound_callback(void* userdata, Uint8* stream, int len) {
|
||||
fishbone::SoundDriver* sd = (fishbone::SoundDriver*)userdata;
|
||||
|
|
@ -21,7 +21,7 @@ fishbone::SoundDriver::SoundDriver() {
|
|||
|
||||
if(!sdl_audio_init) {
|
||||
SDL_InitSubSystem(SDL_INIT_AUDIO);
|
||||
sdl_audio_init = 1;
|
||||
sdl_audio_init = true;
|
||||
}
|
||||
|
||||
SDL_memset(&spec, 0, sizeof(spec));
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
#include <fishbone/foundation.h>
|
||||
|
|
@ -0,0 +1 @@
|
|||
#include <fishbone/foundation.h>
|
||||
1
engine/src/soundldr/vorbis.cc
Normal file
1
engine/src/soundldr/vorbis.cc
Normal file
|
|
@ -0,0 +1 @@
|
|||
#include <fishbone/foundation.h>
|
||||
|
|
@ -0,0 +1 @@
|
|||
#include <fishbone/foundation.h>
|
||||
51
engine/src/soundldr/xmp.cc
Normal file
51
engine/src/soundldr/xmp.cc
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
#include <fishbone/foundation.h>
|
||||
|
||||
struct fishbone::Sound::Impl {
|
||||
xmp_context ctx;
|
||||
unsigned char* buffer;
|
||||
};
|
||||
|
||||
fishbone::Sound* fishbone::XMPSoundLoader::open(fishbone::Mixer* mixer, void* buffer, size_t size) {
|
||||
struct fishbone::Sound::Impl* impl;
|
||||
fishbone::XMPSound* snd;
|
||||
|
||||
impl = new struct fishbone::Sound::Impl();
|
||||
|
||||
impl->buffer = new unsigned char[size];
|
||||
memcpy(impl->buffer, buffer, size);
|
||||
|
||||
impl->ctx = xmp_create_context();
|
||||
if(xmp_load_module_from_memory(impl->ctx, impl->buffer, size) < 0) {
|
||||
xmp_free_context(impl->ctx);
|
||||
delete[] impl->buffer;
|
||||
delete impl;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
xmp_start_player(impl->ctx, 44100, 0);
|
||||
|
||||
snd = new fishbone::XMPSound(mixer, this, impl);
|
||||
snd->rate = 44100;
|
||||
snd->channels = 2;
|
||||
|
||||
return snd;
|
||||
}
|
||||
|
||||
int fishbone::XMPSoundLoader::read(fishbone::Sound* sound, short* buffer, size_t frames) {
|
||||
if(xmp_play_buffer(sound->impl->ctx, buffer, frames * 4, 0) < 0) return -1;
|
||||
|
||||
return frames;
|
||||
}
|
||||
|
||||
void fishbone::XMPSoundLoader::seek(fishbone::Sound* sound, size_t pos) {
|
||||
xmp_set_position(sound->impl->ctx, pos);
|
||||
}
|
||||
|
||||
fishbone::XMPSound::~XMPSound() {
|
||||
xmp_end_player(this->impl->ctx);
|
||||
xmp_release_module(this->impl->ctx);
|
||||
xmp_free_context(this->impl->ctx);
|
||||
delete[] this->impl->buffer;
|
||||
delete this->impl;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue