mirror of
https://github.com/QB64-Phoenix-Edition/QB64pe.git
synced 2024-07-05 22:50:23 +00:00
Merge pull request #143 from mkilgore/a740g-miniaudio-backend
a740g's miniaudio audio backend
This commit is contained in:
commit
4241d41e4f
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -15,3 +15,4 @@ internal/c/qbx[2-9].cpp
|
|||
/qb64pe
|
||||
mingw32.exe
|
||||
mingw64.exe
|
||||
.vscode
|
||||
|
|
12
Makefile
12
Makefile
|
@ -181,6 +181,7 @@ include $(PATH_INTERNAL_C)/parts/audio/conversion/build.mk
|
|||
include $(PATH_INTERNAL_C)/parts/audio/decode/mp3_mini/build.mk
|
||||
include $(PATH_INTERNAL_C)/parts/audio/decode/ogg/build.mk
|
||||
include $(PATH_INTERNAL_C)/parts/audio/out/build.mk
|
||||
include $(PATH_INTERNAL_C)/parts/audio/build.mk
|
||||
include $(PATH_INTERNAL_C)/parts/core/build.mk
|
||||
include $(PATH_INTERNAL_C)/parts/input/game_controller/build.mk
|
||||
include $(PATH_INTERNAL_C)/parts/video/font/ttf/build.mk
|
||||
|
@ -266,6 +267,15 @@ else
|
|||
QBLIB_NAME := $(addsuffix 0,$(QBLIB_NAME))
|
||||
endif
|
||||
|
||||
ifneq ($(filter y,$(DEP_AUDIO_MINIAUDIO)),)
|
||||
EXE_LIBS += $(MINIAUDIO_OBJS)
|
||||
|
||||
CXXFLAGS += -DDEPENDENCY_AUDIO_MINIAUDIO
|
||||
QBLIB_NAME := $(addsuffix 1,$(QBLIB_NAME))
|
||||
else
|
||||
QBLIB_NAME := $(addsuffix 0,$(QBLIB_NAME))
|
||||
endif
|
||||
|
||||
ifneq ($(filter y,$(DEP_AUDIO_CONVERSION) $(DEP_AUDIO_DECODE)),)
|
||||
EXE_LIBS += $(QB_AUDIO_CONVERSION_LIB)
|
||||
CXXFLAGS += -DDEPENDENCY_AUDIO_CONVERSION
|
||||
|
@ -329,7 +339,7 @@ ifeq ($(OS),win)
|
|||
CXXLIBS += -lwinspool
|
||||
endif
|
||||
|
||||
ifneq ($(filter y,$(DEP_AUDIO_OUT) $(DEP_AUDIO_CONVERSION) $(DEP_AUDIO_DECODE)),)
|
||||
ifneq ($(filter y,$(DEP_AUDIO_OUT) $(DEP_AUDIO_CONVERSION) $(DEP_AUDIO_DECODE) $(DEP_AUDIO_MINIAUDIO)),)
|
||||
CXXLIBS += -lwinmm -lksguid -ldxguid -lole32
|
||||
endif
|
||||
|
||||
|
|
|
@ -128,6 +128,7 @@ These flags controls whether certain dependencies are compiled in or not. All of
|
|||
| `DEP_DATA` | Compiles in data produced via `DATA` statements. |
|
||||
| `DEP_CONSOLE` | On Windows, this gives the program console support (graphical support is still allowed) |
|
||||
| `DEP_CONSOLE_ONLY` | Same as `DEP_CONSOLE`, but also removes GLUT and graphics support. |
|
||||
| `DEP_AUDIO_MINIAUDIO` | Enables the miniaudio backend. Should not be used with the other `DEP_AUDIO` switches which enable the old backend. |
|
||||
|
||||
Versioning
|
||||
----------
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#endif
|
||||
|
||||
#include "mutex.h"
|
||||
#include "audio.h"
|
||||
|
||||
int32 disableEvents = 0;
|
||||
|
||||
|
@ -22101,26 +22102,15 @@ double func_sqr(double value) {
|
|||
return sqrt(value);
|
||||
}
|
||||
|
||||
#ifdef QB64_BACKSLASH_FILESYSTEM
|
||||
# include "parts\\audio\\out\\src.c"
|
||||
#else
|
||||
#ifndef DEPENDENCY_AUDIO_MINIAUDIO
|
||||
# include "parts/audio/out/src.c"
|
||||
#endif
|
||||
|
||||
#ifdef QB64_BACKSLASH_FILESYSTEM
|
||||
# include "parts\\audio\\conversion\\src.c"
|
||||
# include "parts\\audio\\decode\\src.c"
|
||||
#else
|
||||
# include "parts/audio/conversion/src.c"
|
||||
# include "parts/audio/decode/src.c"
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef DEPENDENCY_ZLIB
|
||||
# ifdef QB64_BACKSLASH_FILESYSTEM
|
||||
# include "parts\\zlib\\src.c"
|
||||
# else
|
||||
# include "parts/zlib/src.c"
|
||||
# endif
|
||||
# include "parts/zlib/src.c"
|
||||
#endif
|
||||
|
||||
qbs *func_command_str = NULL;
|
||||
|
|
91
internal/c/libqb/include/audio.h
Normal file
91
internal/c/libqb/include/audio.h
Normal file
|
@ -0,0 +1,91 @@
|
|||
//----------------------------------------------------------------------------------------------------
|
||||
// ___ ___ __ _ _ ___ ___ _ _ _ ___ _
|
||||
// / _ \| _ ) / /| | || _ \ __| /_\ _ _ __| (_)___ | __|_ _ __ _(_)_ _ ___
|
||||
// | (_) | _ \/ _ \_ _| _/ _| / _ \ || / _` | / _ \ | _|| ' \/ _` | | ' \/ -_)
|
||||
// \__\_\___/\___/ |_||_| |___| /_/ \_\_,_\__,_|_\___/ |___|_||_\__, |_|_||_\___|
|
||||
// |___/
|
||||
//
|
||||
// QB64-PE Audio Engine powered by miniaudio (https://miniaud.io/)
|
||||
//
|
||||
// Copyright (c) 2022 Samuel Gomes
|
||||
// https://github.com/a740g
|
||||
//
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
// HEADER FILES
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
// MACROS
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
#if defined(AUDIO_DEBUG) && AUDIO_DEBUG > 0
|
||||
# ifdef _MSC_VER
|
||||
# define AUDIO_DEBUG_PRINT(_fmt_, ...) fprintf(stderr, "DEBUG: %s:%d:%s(): " _fmt_ "\n", __FILE__, __LINE__, __func__, __VA_ARGS__)
|
||||
# else
|
||||
# define AUDIO_DEBUG_PRINT(_fmt_, _args_...) fprintf(stderr, "DEBUG: %s:%d:%s(): " _fmt_ "\n", __FILE__, __LINE__, __func__, ##_args_)
|
||||
# endif
|
||||
# define AUDIO_DEBUG_CHECK(_exp_) \
|
||||
if (!(_exp_)) \
|
||||
AUDIO_DEBUG_PRINT("Condition (%s) failed", #_exp_)
|
||||
#else
|
||||
# ifdef _MSC_VER
|
||||
# define AUDIO_DEBUG_PRINT(_fmt_, ...) // Don't do anything in release builds
|
||||
# else
|
||||
# define AUDIO_DEBUG_PRINT(_fmt_, _args_...) // Don't do anything in release builds
|
||||
# endif
|
||||
# define AUDIO_DEBUG_CHECK(_exp_) // Don't do anything in release builds
|
||||
#endif
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
// FORWARD DECLARATIONS
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
struct qbs;
|
||||
struct mem_block;
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
// FUNCTIONS
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
void sub_sound(double frequency, double lengthInClockTicks);
|
||||
void sub_beep();
|
||||
void sub_play(qbs *str);
|
||||
int32_t func_play(int32_t ignore);
|
||||
|
||||
int32_t func__sndrate();
|
||||
int32_t func__sndopen(qbs *fileName, qbs *requirements, int32_t passed);
|
||||
void sub__sndclose(int32_t handle);
|
||||
int32_t func__sndcopy(int32_t src_handle);
|
||||
void sub__sndplay(int32_t handle);
|
||||
void sub__sndplaycopy(int32_t src_handle, double volume, int32_t passed);
|
||||
void sub__sndplayfile(qbs *fileName, int32_t sync, double volume, int32_t passed);
|
||||
void sub__sndpause(int32_t handle);
|
||||
int32_t func__sndplaying(int32_t handle);
|
||||
int32_t func__sndpaused(int32_t handle);
|
||||
void sub__sndvol(int32_t handle, float volume);
|
||||
void sub__sndloop(int32_t handle);
|
||||
void sub__sndbal(int32_t handle, double x, double y, double z, int32_t channel, int32_t passed);
|
||||
double func__sndlen(int32_t handle);
|
||||
double func__sndgetpos(int32_t handle);
|
||||
void sub__sndsetpos(int32_t handle, double seconds);
|
||||
void sub__sndlimit(int32_t handle, double limit);
|
||||
void sub__sndstop(int32_t handle);
|
||||
|
||||
int32_t func__sndopenraw();
|
||||
void sub__sndraw(float left, float right, int32_t handle, int32_t passed);
|
||||
void sub__sndrawdone(int32_t handle, int32_t passed);
|
||||
double func__sndrawlen(int32_t handle, int32_t passed);
|
||||
|
||||
mem_block func__memsound(int32_t handle, int32_t targetChannel);
|
||||
|
||||
void snd_init();
|
||||
void snd_un_init();
|
||||
void snd_mainloop();
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------------------------------
|
2134
internal/c/parts/audio/audio.cpp
Normal file
2134
internal/c/parts/audio/audio.cpp
Normal file
File diff suppressed because it is too large
Load diff
58
internal/c/parts/audio/build.mk
Normal file
58
internal/c/parts/audio/build.mk
Normal file
|
@ -0,0 +1,58 @@
|
|||
|
||||
MINIAUDIO_REAL_SRCS := \
|
||||
audio.cpp \
|
||||
miniaudio_impl.cpp
|
||||
|
||||
MINIAUDIO_REAL_EXTRAS_SRCS := \
|
||||
extras/libxmp-lite/common.c \
|
||||
extras/libxmp-lite/control.c \
|
||||
extras/libxmp-lite/dataio.c \
|
||||
extras/libxmp-lite/effects.c \
|
||||
extras/libxmp-lite/filter.c \
|
||||
extras/libxmp-lite/format.c \
|
||||
extras/libxmp-lite/hio.c \
|
||||
extras/libxmp-lite/it_load.c \
|
||||
extras/libxmp-lite/itsex.c \
|
||||
extras/libxmp-lite/lfo.c \
|
||||
extras/libxmp-lite/load.c \
|
||||
extras/libxmp-lite/load_helpers.c \
|
||||
extras/libxmp-lite/md5.c \
|
||||
extras/libxmp-lite/memio.c \
|
||||
extras/libxmp-lite/misc.c \
|
||||
extras/libxmp-lite/mix_all.c \
|
||||
extras/libxmp-lite/mixer.c \
|
||||
extras/libxmp-lite/mod_load.c \
|
||||
extras/libxmp-lite/period.c \
|
||||
extras/libxmp-lite/player.c \
|
||||
extras/libxmp-lite/read_event.c \
|
||||
extras/libxmp-lite/s3m_load.c \
|
||||
extras/libxmp-lite/sample.c \
|
||||
extras/libxmp-lite/scan.c \
|
||||
extras/libxmp-lite/smix.c \
|
||||
extras/libxmp-lite/virtual.c \
|
||||
extras/libxmp-lite/win32.c \
|
||||
extras/libxmp-lite/xm_load.c
|
||||
|
||||
MINIAUDIO_STUB_SRCS := \
|
||||
stub_audio.cpp
|
||||
|
||||
# We always produce both lists so that `make clean` will clean them up even
|
||||
# when not passed a paticular DEP_* flag
|
||||
MINIAUDIO_REAL_OBJS := $(patsubst %.cpp,$(PATH_INTERNAL_C)/parts/audio/%.o,$(MINIAUDIO_REAL_SRCS))
|
||||
MINIAUDIO_REAL_OBJS += $(patsubst %.c,$(PATH_INTERNAL_C)/parts/audio/%.o,$(MINIAUDIO_REAL_EXTRAS_SRCS))
|
||||
|
||||
MINIAUDIO_STUB_OBJS := $(patsubst %.cpp,$(PATH_INTERNAL_C)/parts/audio/%.o,$(MINIAUDIO_STUB_SRCS))
|
||||
|
||||
ifdef DEP_AUDIO_MINIAUDIO
|
||||
MINIAUDIO_OBJS := $(MINIAUDIO_REAL_OBJS)
|
||||
else
|
||||
MINIAUDIO_OBJS := $(MINIAUDIO_STUB_OBJS)
|
||||
endif
|
||||
|
||||
$(PATH_INTERNAL_C)/parts/audio/%.o: $(PATH_INTERNAL_C)/parts/audio/%.cpp
|
||||
$(CXX) $(CXXFLAGS) -Wall $< -c -o $@
|
||||
|
||||
$(PATH_INTERNAL_C)/parts/audio/extras/libxmp-lite/%.o: $(PATH_INTERNAL_C)/parts/audio/extras/libxmp-lite/%.c
|
||||
$(CC) $(CFLAGS) -Wall -DLIBXMP_CORE_PLAYER -DLIBXMP_NO_PROWIZARD -DLIBXMP_NO_DEPACKERS -DBUILDING_STATIC $< -c -o $@
|
||||
|
||||
CLEAN_LIST += $(MINIAUDIO_REAL_OBJS) $(MINIAUDIO_STUB_OBJS)
|
190
internal/c/parts/audio/extras/libxmp-lite/callbackio.h
Normal file
190
internal/c/parts/audio/extras/libxmp-lite/callbackio.h
Normal file
|
@ -0,0 +1,190 @@
|
|||
#ifndef LIBXMP_CALLBACKIO_H
|
||||
#define LIBXMP_CALLBACKIO_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include "common.h"
|
||||
|
||||
typedef struct {
|
||||
void *priv;
|
||||
struct xmp_callbacks callbacks;
|
||||
int eof;
|
||||
} CBFILE;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
static inline uint8 cbread8(CBFILE *f, int *err)
|
||||
{
|
||||
uint8 x = 0xff;
|
||||
size_t r = f->callbacks.read_func(&x, 1, 1, f->priv);
|
||||
f->eof = (r == 1) ? 0 : EOF;
|
||||
|
||||
if (err) *err = f->eof;
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
static inline int8 cbread8s(CBFILE *f, int *err)
|
||||
{
|
||||
return (int8)cbread8(f, err);
|
||||
}
|
||||
|
||||
static inline uint16 cbread16l(CBFILE *f, int *err)
|
||||
{
|
||||
uint8 buf[2];
|
||||
uint16 x = EOF;
|
||||
size_t r = f->callbacks.read_func(buf, 2, 1, f->priv);
|
||||
f->eof = (r == 1) ? 0 : EOF;
|
||||
|
||||
if (r) x = readmem16l(buf);
|
||||
if (err) *err = f->eof;
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
static inline uint16 cbread16b(CBFILE *f, int *err)
|
||||
{
|
||||
uint8 buf[2];
|
||||
uint16 x = EOF;
|
||||
size_t r = f->callbacks.read_func(buf, 2, 1, f->priv);
|
||||
f->eof = (r == 1) ? 0 : EOF;
|
||||
|
||||
if (r) x = readmem16b(buf);
|
||||
if (err) *err = f->eof;
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
static inline uint32 cbread24l(CBFILE *f, int *err)
|
||||
{
|
||||
uint8 buf[3];
|
||||
uint32 x = EOF;
|
||||
size_t r = f->callbacks.read_func(buf, 3, 1, f->priv);
|
||||
f->eof = (r == 1) ? 0 : EOF;
|
||||
|
||||
if (r) x = readmem24l(buf);
|
||||
if (err) *err = f->eof;
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
static inline uint32 cbread24b(CBFILE *f, int *err)
|
||||
{
|
||||
uint8 buf[3];
|
||||
uint32 x = EOF;
|
||||
size_t r = f->callbacks.read_func(buf, 3, 1, f->priv);
|
||||
f->eof = (r == 1) ? 0 : EOF;
|
||||
|
||||
if (r) x = readmem24b(buf);
|
||||
if (err) *err = f->eof;
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
static inline uint32 cbread32l(CBFILE *f, int *err)
|
||||
{
|
||||
uint8 buf[4];
|
||||
uint32 x = EOF;
|
||||
size_t r = f->callbacks.read_func(buf, 4, 1, f->priv);
|
||||
f->eof = (r == 1) ? 0 : EOF;
|
||||
|
||||
if (r) x = readmem32l(buf);
|
||||
if (err) *err = f->eof;
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
static inline uint32 cbread32b(CBFILE *f, int *err)
|
||||
{
|
||||
uint8 buf[4];
|
||||
uint32 x = EOF;
|
||||
size_t r = f->callbacks.read_func(buf, 4, 1, f->priv);
|
||||
f->eof = (r == 1) ? 0 : EOF;
|
||||
|
||||
if (r) x = readmem32b(buf);
|
||||
if (err) *err = f->eof;
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
static inline size_t cbread(void *dest, size_t len, size_t nmemb, CBFILE *f)
|
||||
{
|
||||
size_t r = f->callbacks.read_func(dest, len, nmemb, f->priv);
|
||||
f->eof = (r < nmemb) ? EOF : 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
static inline int cbseek(CBFILE *f, long offset, int whence)
|
||||
{
|
||||
f->eof = 0;
|
||||
return f->callbacks.seek_func(f->priv, offset, whence);
|
||||
}
|
||||
|
||||
static inline long cbtell(CBFILE *f)
|
||||
{
|
||||
return f->callbacks.tell_func(f->priv);
|
||||
}
|
||||
|
||||
static inline int cbeof(CBFILE *f)
|
||||
{
|
||||
return f->eof;
|
||||
}
|
||||
|
||||
static inline long cbfilelength(CBFILE *f)
|
||||
{
|
||||
long pos = f->callbacks.tell_func(f->priv);
|
||||
long length;
|
||||
int r;
|
||||
|
||||
if (pos < 0)
|
||||
return EOF;
|
||||
|
||||
r = f->callbacks.seek_func(f->priv, 0, SEEK_END);
|
||||
if (r < 0)
|
||||
return EOF;
|
||||
|
||||
length = f->callbacks.tell_func(f->priv);
|
||||
r = f->callbacks.seek_func(f->priv, pos, SEEK_SET);
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
static inline CBFILE *cbopen(void *priv, struct xmp_callbacks callbacks)
|
||||
{
|
||||
CBFILE *f;
|
||||
if (priv == NULL || callbacks.read_func == NULL ||
|
||||
callbacks.seek_func == NULL || callbacks.tell_func == NULL)
|
||||
goto err;
|
||||
|
||||
f = (CBFILE *)calloc(1, sizeof(CBFILE));
|
||||
if (f == NULL)
|
||||
goto err;
|
||||
|
||||
f->priv = priv;
|
||||
f->callbacks = callbacks;
|
||||
f->eof = 0;
|
||||
return f;
|
||||
|
||||
err:
|
||||
if (priv && callbacks.close_func)
|
||||
callbacks.close_func(priv);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline int cbclose(CBFILE *f)
|
||||
{
|
||||
int r = 0;
|
||||
if (f->callbacks.close_func != NULL)
|
||||
r = f->callbacks.close_func(f->priv);
|
||||
|
||||
free(f);
|
||||
return r;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* LIBXMP_CALLBACKIO_H */
|
573
internal/c/parts/audio/extras/libxmp-lite/common.c
Normal file
573
internal/c/parts/audio/extras/libxmp-lite/common.c
Normal file
|
@ -0,0 +1,573 @@
|
|||
/* Extended Module Player
|
||||
* Copyright (C) 1996-2021 Claudio Matsuoka and Hipolito Carraro Jr
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
#if defined(_WIN32)
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#include <limits.h>
|
||||
#elif defined(__OS2__) || defined(__EMX__)
|
||||
#define INCL_DOS
|
||||
#define INCL_DOSERRORS
|
||||
#include <os2.h>
|
||||
#elif defined(__DJGPP__)
|
||||
#include <dos.h>
|
||||
#include <io.h>
|
||||
#elif defined(HAVE_DIRENT_H)
|
||||
#include <dirent.h>
|
||||
#endif
|
||||
#endif /* LIBXMP_CORE_PLAYER */
|
||||
|
||||
#include "xmp.h"
|
||||
#include "common.h"
|
||||
#include "period.h"
|
||||
#include "loader.h"
|
||||
|
||||
int libxmp_init_instrument(struct module_data *m)
|
||||
{
|
||||
struct xmp_module *mod = &m->mod;
|
||||
|
||||
if (mod->ins > 0) {
|
||||
mod->xxi = calloc(sizeof (struct xmp_instrument), mod->ins);
|
||||
if (mod->xxi == NULL)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (mod->smp > 0) {
|
||||
int i;
|
||||
/* Sanity check */
|
||||
if (mod->smp > MAX_SAMPLES) {
|
||||
D_(D_CRIT "sample count %d exceeds maximum (%d)",
|
||||
mod->smp, MAX_SAMPLES);
|
||||
return -1;
|
||||
}
|
||||
|
||||
mod->xxs = calloc(sizeof (struct xmp_sample), mod->smp);
|
||||
if (mod->xxs == NULL)
|
||||
return -1;
|
||||
m->xtra = calloc(sizeof (struct extra_sample_data), mod->smp);
|
||||
if (m->xtra == NULL)
|
||||
return -1;
|
||||
|
||||
for (i = 0; i < mod->smp; i++) {
|
||||
m->xtra[i].c5spd = m->c4rate;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Sample number adjustment (originally by Vitamin/CAIG).
|
||||
* Only use this AFTER a previous usage of libxmp_init_instrument,
|
||||
* and don't use this to free samples that have already been loaded. */
|
||||
int libxmp_realloc_samples(struct module_data *m, int new_size)
|
||||
{
|
||||
struct xmp_module *mod = &m->mod;
|
||||
struct xmp_sample *xxs;
|
||||
struct extra_sample_data *xtra;
|
||||
|
||||
/* Sanity check */
|
||||
if (new_size < 0)
|
||||
return -1;
|
||||
|
||||
if (new_size == 0) {
|
||||
/* Don't rely on implementation-defined realloc(x,0) behavior. */
|
||||
mod->smp = 0;
|
||||
free(mod->xxs);
|
||||
mod->xxs = NULL;
|
||||
free(m->xtra);
|
||||
m->xtra = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
xxs = realloc(mod->xxs, sizeof(struct xmp_sample) * new_size);
|
||||
if (xxs == NULL)
|
||||
return -1;
|
||||
mod->xxs = xxs;
|
||||
|
||||
xtra = realloc(m->xtra, sizeof(struct extra_sample_data) * new_size);
|
||||
if (xtra == NULL)
|
||||
return -1;
|
||||
m->xtra = xtra;
|
||||
|
||||
if (new_size > mod->smp) {
|
||||
int clear_size = new_size - mod->smp;
|
||||
int i;
|
||||
|
||||
memset(xxs + mod->smp, 0, sizeof(struct xmp_sample) * clear_size);
|
||||
memset(xtra + mod->smp, 0, sizeof(struct extra_sample_data) * clear_size);
|
||||
|
||||
for (i = mod->smp; i < new_size; i++) {
|
||||
m->xtra[i].c5spd = m->c4rate;
|
||||
}
|
||||
}
|
||||
mod->smp = new_size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int libxmp_alloc_subinstrument(struct xmp_module *mod, int i, int num)
|
||||
{
|
||||
if (num == 0)
|
||||
return 0;
|
||||
|
||||
mod->xxi[i].sub = calloc(sizeof (struct xmp_subinstrument), num);
|
||||
if (mod->xxi[i].sub == NULL)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int libxmp_init_pattern(struct xmp_module *mod)
|
||||
{
|
||||
mod->xxt = calloc(sizeof (struct xmp_track *), mod->trk);
|
||||
if (mod->xxt == NULL)
|
||||
return -1;
|
||||
|
||||
mod->xxp = calloc(sizeof (struct xmp_pattern *), mod->pat);
|
||||
if (mod->xxp == NULL)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int libxmp_alloc_pattern(struct xmp_module *mod, int num)
|
||||
{
|
||||
/* Sanity check */
|
||||
if (num < 0 || num >= mod->pat || mod->xxp[num] != NULL)
|
||||
return -1;
|
||||
|
||||
mod->xxp[num] = calloc(1, sizeof (struct xmp_pattern) +
|
||||
sizeof (int) * (mod->chn - 1));
|
||||
if (mod->xxp[num] == NULL)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int libxmp_alloc_track(struct xmp_module *mod, int num, int rows)
|
||||
{
|
||||
/* Sanity check */
|
||||
if (num < 0 || num >= mod->trk || mod->xxt[num] != NULL || rows <= 0)
|
||||
return -1;
|
||||
|
||||
mod->xxt[num] = calloc(sizeof (struct xmp_track) +
|
||||
sizeof (struct xmp_event) * (rows - 1), 1);
|
||||
if (mod->xxt[num] == NULL)
|
||||
return -1;
|
||||
|
||||
mod->xxt[num]->rows = rows;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int libxmp_alloc_tracks_in_pattern(struct xmp_module *mod, int num)
|
||||
{
|
||||
int i;
|
||||
|
||||
D_(D_INFO "Alloc %d tracks of %d rows", mod->chn, mod->xxp[num]->rows);
|
||||
for (i = 0; i < mod->chn; i++) {
|
||||
int t = num * mod->chn + i;
|
||||
int rows = mod->xxp[num]->rows;
|
||||
|
||||
if (libxmp_alloc_track(mod, t, rows) < 0)
|
||||
return -1;
|
||||
|
||||
mod->xxp[num]->index[i] = t;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int libxmp_alloc_pattern_tracks(struct xmp_module *mod, int num, int rows)
|
||||
{
|
||||
/* Sanity check */
|
||||
if (rows <= 0 || rows > 256)
|
||||
return -1;
|
||||
|
||||
if (libxmp_alloc_pattern(mod, num) < 0)
|
||||
return -1;
|
||||
|
||||
mod->xxp[num]->rows = rows;
|
||||
|
||||
if (libxmp_alloc_tracks_in_pattern(mod, num) < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Some formats explicitly allow more than 256 rows (e.g. OctaMED). This function
|
||||
* allows those formats to work without disrupting the sanity check for other formats.
|
||||
*/
|
||||
int libxmp_alloc_pattern_tracks_long(struct xmp_module *mod, int num, int rows)
|
||||
{
|
||||
/* Sanity check */
|
||||
if (rows <= 0 || rows > 32768)
|
||||
return -1;
|
||||
|
||||
if (libxmp_alloc_pattern(mod, num) < 0)
|
||||
return -1;
|
||||
|
||||
mod->xxp[num]->rows = rows;
|
||||
|
||||
if (libxmp_alloc_tracks_in_pattern(mod, num) < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *libxmp_instrument_name(struct xmp_module *mod, int i, uint8 *r, int n)
|
||||
{
|
||||
CLAMP(n, 0, 31);
|
||||
|
||||
return libxmp_copy_adjust(mod->xxi[i].name, r, n);
|
||||
}
|
||||
|
||||
char *libxmp_copy_adjust(char *s, uint8 *r, int n)
|
||||
{
|
||||
int i;
|
||||
|
||||
memset(s, 0, n + 1);
|
||||
strncpy(s, (char *)r, n);
|
||||
|
||||
for (i = 0; s[i] && i < n; i++) {
|
||||
if (!isprint((int)s[i]) || ((uint8)s[i] > 127))
|
||||
s[i] = '.';
|
||||
}
|
||||
|
||||
while (*s && (s[strlen(s) - 1] == ' '))
|
||||
s[strlen(s) - 1] = 0;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
void libxmp_read_title(HIO_HANDLE *f, char *t, int s)
|
||||
{
|
||||
uint8 buf[XMP_NAME_SIZE];
|
||||
|
||||
if (t == NULL)
|
||||
return;
|
||||
|
||||
if (s >= XMP_NAME_SIZE)
|
||||
s = XMP_NAME_SIZE -1;
|
||||
|
||||
memset(t, 0, s + 1);
|
||||
|
||||
hio_read(buf, 1, s, f); /* coverity[check_return] */
|
||||
buf[s] = 0;
|
||||
libxmp_copy_adjust(t, buf, s);
|
||||
}
|
||||
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
|
||||
int libxmp_test_name(uint8 *s, int n)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
if (s[i] > 0x7f)
|
||||
return -1;
|
||||
/* ACS_Team2.mod has a backspace in instrument name */
|
||||
if (s[i] > 0 && s[i] < 32 && s[i] != 0x08)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int libxmp_copy_name_for_fopen(char *dest, const char *name, int n)
|
||||
{
|
||||
int converted_colon = 0;
|
||||
int i;
|
||||
|
||||
/* libxmp_copy_adjust, but make sure the filename won't do anything
|
||||
* malicious when given to fopen. This should only be used on song files.
|
||||
*/
|
||||
if (!strcmp(name, ".") || strstr(name, "..") ||
|
||||
name[0] == '\\' || name[0] == '/' || name[0] == ':')
|
||||
return -1;
|
||||
|
||||
|
||||
for (i = 0; i < n - 1; i++) {
|
||||
uint8 t = name[i];
|
||||
if (!t)
|
||||
break;
|
||||
|
||||
/* Reject non-ASCII symbols as they have poorly defined behavior.
|
||||
*/
|
||||
if (t < 32 || t >= 0x7f)
|
||||
return -1;
|
||||
|
||||
/* Reject anything resembling a Windows-style root path. Allow
|
||||
* converting a single : to / so things like ST-01:samplename
|
||||
* work. (Leave the : as-is on Amiga.)
|
||||
*/
|
||||
if (i > 0 && t == ':' && !converted_colon) {
|
||||
uint8 t2 = name[i + 1];
|
||||
if (!t2 || t2 == '/' || t2 == '\\')
|
||||
return -1;
|
||||
|
||||
converted_colon = 1;
|
||||
#ifndef LIBXMP_AMIGA
|
||||
dest[i] = '/';
|
||||
continue;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (t == '\\') {
|
||||
dest[i] = '/';
|
||||
continue;
|
||||
}
|
||||
|
||||
dest[i] = t;
|
||||
}
|
||||
dest[i] = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Honor Noisetracker effects:
|
||||
*
|
||||
* 0 - arpeggio
|
||||
* 1 - portamento up
|
||||
* 2 - portamento down
|
||||
* 3 - Tone-portamento
|
||||
* 4 - Vibrato
|
||||
* A - Slide volume
|
||||
* B - Position jump
|
||||
* C - Set volume
|
||||
* D - Pattern break
|
||||
* E - Set filter (keep the led off, please!)
|
||||
* F - Set speed (now up to $1F)
|
||||
*
|
||||
* Pex Tufvesson's notes from http://www.livet.se/mahoney/:
|
||||
*
|
||||
* Note that some of the modules will have bugs in the playback with all
|
||||
* known PC module players. This is due to that in many demos where I synced
|
||||
* events in the demo with the music, I used commands that these newer PC
|
||||
* module players erroneously interpret as "newer-version-trackers commands".
|
||||
* Which they aren't.
|
||||
*/
|
||||
void libxmp_decode_noisetracker_event(struct xmp_event *event, uint8 *mod_event)
|
||||
{
|
||||
int fxt;
|
||||
|
||||
memset(event, 0, sizeof (struct xmp_event));
|
||||
event->note = libxmp_period_to_note((LSN(mod_event[0]) << 8) + mod_event[1]);
|
||||
event->ins = ((MSN(mod_event[0]) << 4) | MSN(mod_event[2]));
|
||||
fxt = LSN(mod_event[2]);
|
||||
|
||||
if (fxt <= 0x06 || (fxt >= 0x0a && fxt != 0x0e)) {
|
||||
event->fxt = fxt;
|
||||
event->fxp = mod_event[3];
|
||||
}
|
||||
|
||||
libxmp_disable_continue_fx(event);
|
||||
}
|
||||
#endif
|
||||
|
||||
void libxmp_decode_protracker_event(struct xmp_event *event, uint8 *mod_event)
|
||||
{
|
||||
int fxt = LSN(mod_event[2]);
|
||||
|
||||
memset(event, 0, sizeof (struct xmp_event));
|
||||
event->note = libxmp_period_to_note((LSN(mod_event[0]) << 8) + mod_event[1]);
|
||||
event->ins = ((MSN(mod_event[0]) << 4) | MSN(mod_event[2]));
|
||||
|
||||
if (fxt != 0x08) {
|
||||
event->fxt = fxt;
|
||||
event->fxp = mod_event[3];
|
||||
}
|
||||
|
||||
libxmp_disable_continue_fx(event);
|
||||
}
|
||||
|
||||
void libxmp_disable_continue_fx(struct xmp_event *event)
|
||||
{
|
||||
if (event->fxp == 0) {
|
||||
switch (event->fxt) {
|
||||
case 0x05:
|
||||
event->fxt = 0x03;
|
||||
break;
|
||||
case 0x06:
|
||||
event->fxt = 0x04;
|
||||
break;
|
||||
case 0x01:
|
||||
case 0x02:
|
||||
case 0x0a:
|
||||
event->fxt = 0x00;
|
||||
}
|
||||
} else if (event->fxt == 0x0e) {
|
||||
if (event->fxp == 0xa0 || event->fxp == 0xb0) {
|
||||
event->fxt = event->fxp = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
/* libxmp_check_filename_case(): */
|
||||
/* Given a directory, see if file exists there, ignoring case */
|
||||
|
||||
#if defined(_WIN32)
|
||||
int libxmp_check_filename_case(const char *dir, const char *name, char *new_name, int size)
|
||||
{
|
||||
char path[_MAX_PATH];
|
||||
DWORD rc;
|
||||
/* win32 is case-insensitive: directly probe the file. */
|
||||
snprintf(path, sizeof(path), "%s/%s", dir, name);
|
||||
rc = GetFileAttributesA(path);
|
||||
if (rc == (DWORD)(-1)) return 0;
|
||||
if (rc & FILE_ATTRIBUTE_DIRECTORY) return 0;
|
||||
strncpy(new_name, name, size);
|
||||
return 1;
|
||||
}
|
||||
#elif defined(__OS2__) || defined(__EMX__)
|
||||
int libxmp_check_filename_case(const char *dir, const char *name, char *new_name, int size)
|
||||
{
|
||||
char path[CCHMAXPATH];
|
||||
FILESTATUS3 fs;
|
||||
/* os/2 is case-insensitive: directly probe the file. */
|
||||
snprintf(path, sizeof(path), "%s/%s", dir, name);
|
||||
if (DosQueryPathInfo(path, FIL_STANDARD, &fs, sizeof(fs)) != NO_ERROR) return 0;
|
||||
if (fs.attrFile & FILE_DIRECTORY) return 0;
|
||||
strncpy(new_name, name, size);
|
||||
return 1;
|
||||
}
|
||||
#elif defined(__DJGPP__)
|
||||
int libxmp_check_filename_case(const char *dir, const char *name, char *new_name, int size)
|
||||
{
|
||||
char path[256];
|
||||
int attr;
|
||||
/* dos is case-insensitive: directly probe the file. */
|
||||
snprintf(path, sizeof(path), "%s/%s", dir, name);
|
||||
attr = _chmod(path, 0);
|
||||
if (attr == -1) return 0;
|
||||
if (attr & (_A_SUBDIR|_A_VOLID)) return 0;
|
||||
strncpy(new_name, name, size);
|
||||
return 1;
|
||||
}
|
||||
#elif defined(HAVE_DIRENT_H)
|
||||
int libxmp_check_filename_case(const char *dir, const char *name, char *new_name, int size)
|
||||
{
|
||||
int found = 0;
|
||||
DIR *dirfd;
|
||||
struct dirent *d;
|
||||
|
||||
dirfd = opendir(dir);
|
||||
if (dirfd == NULL)
|
||||
return 0;
|
||||
|
||||
while ((d = readdir(dirfd)) != NULL) {
|
||||
if (!strcasecmp(d->d_name, name)) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found)
|
||||
strncpy(new_name, d->d_name, size);
|
||||
|
||||
closedir(dirfd);
|
||||
|
||||
return found;
|
||||
}
|
||||
#else
|
||||
int libxmp_check_filename_case(const char *dir, const char *name, char *new_name, int size)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
void libxmp_get_instrument_path(struct module_data *m, char *path, int size)
|
||||
{
|
||||
if (m->instrument_path) {
|
||||
strncpy(path, m->instrument_path, size);
|
||||
} else if (getenv("XMP_INSTRUMENT_PATH")) {
|
||||
strncpy(path, getenv("XMP_INSTRUMENT_PATH"), size);
|
||||
} else {
|
||||
strncpy(path, ".", size);
|
||||
}
|
||||
}
|
||||
#endif /* LIBXMP_CORE_PLAYER */
|
||||
|
||||
void libxmp_set_type(struct module_data *m, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
|
||||
vsnprintf(m->mod.type, XMP_NAME_SIZE, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
static int schism_tracker_date(int year, int month, int day)
|
||||
{
|
||||
int mm = (month + 9) % 12;
|
||||
int yy = year - mm / 10;
|
||||
|
||||
yy = yy * 365 + (yy / 4) - (yy / 100) + (yy / 400);
|
||||
mm = (mm * 306 + 5) / 10;
|
||||
|
||||
return yy + mm + (day - 1);
|
||||
}
|
||||
|
||||
/* Generate a Schism Tracker version string.
|
||||
* Schism Tracker versions are stored as follows:
|
||||
*
|
||||
* s_ver <= 0x50: 0.s_ver
|
||||
* s_ver > 0x50, < 0xfff: days from epoch=(s_ver - 0x50)
|
||||
* s_ver = 0xfff: days from epoch=l_ver
|
||||
*/
|
||||
void libxmp_schism_tracker_string(char *buf, size_t size, int s_ver, int l_ver)
|
||||
{
|
||||
if (s_ver >= 0x50) {
|
||||
/* time_t epoch_sec = 1256947200; */
|
||||
int t = schism_tracker_date(2009, 10, 31);
|
||||
int year, month, day, dayofyear;
|
||||
|
||||
if (s_ver == 0xfff) {
|
||||
t += l_ver;
|
||||
} else
|
||||
t += s_ver - 0x50;
|
||||
|
||||
/* Date algorithm reimplemented from OpenMPT.
|
||||
*/
|
||||
year = (int)(((int64)t * 10000L + 14780) / 3652425);
|
||||
dayofyear = t - (365 * year + (year / 4) - (year / 100) + (year / 400));
|
||||
if (dayofyear < 0) {
|
||||
year--;
|
||||
dayofyear = t - (365 * year + (year / 4) - (year / 100) + (year / 400));
|
||||
}
|
||||
month = (100 * dayofyear + 52) / 3060;
|
||||
day = dayofyear - (month * 306 + 5) / 10 + 1;
|
||||
|
||||
year += (month + 2) / 12;
|
||||
month = (month + 2) % 12 + 1;
|
||||
|
||||
snprintf(buf, size, "Schism Tracker %04d-%02d-%02d",
|
||||
year, month, day);
|
||||
} else {
|
||||
snprintf(buf, size, "Schism Tracker 0.%x", s_ver);
|
||||
}
|
||||
}
|
473
internal/c/parts/audio/extras/libxmp-lite/common.h
Normal file
473
internal/c/parts/audio/extras/libxmp-lite/common.h
Normal file
|
@ -0,0 +1,473 @@
|
|||
#ifndef LIBXMP_COMMON_H
|
||||
#define LIBXMP_COMMON_H
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "xmp.h"
|
||||
|
||||
#undef LIBXMP_EXPORT_VAR
|
||||
#if defined(EMSCRIPTEN)
|
||||
#include <emscripten.h>
|
||||
#define LIBXMP_EXPORT_VAR EMSCRIPTEN_KEEPALIVE
|
||||
#else
|
||||
#define LIBXMP_EXPORT_VAR
|
||||
#endif
|
||||
|
||||
#if defined(__MORPHOS__) || defined(__AROS__) || defined(AMIGAOS) || \
|
||||
defined(__amigaos__) || defined(__amigaos4__) ||defined(__amigados__) || \
|
||||
defined(AMIGA) || defined(_AMIGA) || defined(__AMIGA__)
|
||||
#define LIBXMP_AMIGA 1 /* to identify amiga platforms. */
|
||||
#endif
|
||||
|
||||
#if (defined(__GNUC__) || defined(__clang__)) && defined(XMP_SYM_VISIBILITY)
|
||||
#if !defined(_WIN32) && !defined(__ANDROID__) && !defined(__APPLE__) && !defined(LIBXMP_AMIGA) && !defined(__MSDOS__) && !defined(B_BEOS_VERSION) && !defined(__ATHEOS__) && !defined(EMSCRIPTEN) && !defined(__MINT__)
|
||||
#define USE_VERSIONED_SYMBOLS
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* AmigaOS fixes by Chris Young <cdyoung@ntlworld.com>, Nov 25, 2007
|
||||
*/
|
||||
#if defined B_BEOS_VERSION
|
||||
# include <SupportDefs.h>
|
||||
#elif defined __amigaos4__
|
||||
# include <exec/types.h>
|
||||
#else
|
||||
typedef signed char int8;
|
||||
typedef signed short int int16;
|
||||
typedef signed int int32;
|
||||
typedef unsigned char uint8;
|
||||
typedef unsigned short int uint16;
|
||||
typedef unsigned int uint32;
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER /* MSVC++6.0 has no long long */
|
||||
typedef signed __int64 int64;
|
||||
typedef unsigned __int64 uint64;
|
||||
#elif !defined B_BEOS_VERSION /* BeOS has its own int64 definition */
|
||||
typedef unsigned long long uint64;
|
||||
typedef signed long long int64;
|
||||
#endif
|
||||
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
#define LIBXMP_PAULA_SIMULATOR
|
||||
#endif
|
||||
|
||||
/* Constants */
|
||||
#define PAL_RATE 250.0 /* 1 / (50Hz * 80us) */
|
||||
#define NTSC_RATE 208.0 /* 1 / (60Hz * 80us) */
|
||||
#define C4_PAL_RATE 8287 /* 7093789.2 / period (C4) * 2 */
|
||||
#define C4_NTSC_RATE 8363 /* 7159090.5 / period (C4) * 2 */
|
||||
|
||||
/* [Amiga] PAL color carrier frequency (PCCF) = 4.43361825 MHz */
|
||||
/* [Amiga] CPU clock = 1.6 * PCCF = 7.0937892 MHz */
|
||||
|
||||
#define DEFAULT_AMPLIFY 1
|
||||
#define DEFAULT_MIX 100
|
||||
|
||||
#define MSN(x) (((x)&0xf0)>>4)
|
||||
#define LSN(x) ((x)&0x0f)
|
||||
#define SET_FLAG(a,b) ((a)|=(b))
|
||||
#define RESET_FLAG(a,b) ((a)&=~(b))
|
||||
#define TEST_FLAG(a,b) !!((a)&(b))
|
||||
|
||||
#define CLAMP(x,a,b) do { \
|
||||
if ((x) < (a)) (x) = (a); \
|
||||
else if ((x) > (b)) (x) = (b); \
|
||||
} while (0)
|
||||
#define MIN(x,y) ((x) < (y) ? (x) : (y))
|
||||
#define MAX(x,y) ((x) > (y) ? (x) : (y))
|
||||
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
|
||||
|
||||
#define TRACK_NUM(a,c) m->mod.xxp[a]->index[c]
|
||||
#define EVENT(a,c,r) m->mod.xxt[TRACK_NUM((a),(c))]->event[r]
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define D_CRIT " Error: "
|
||||
#define D_WARN "Warning: "
|
||||
#define D_INFO " Info: "
|
||||
#ifndef CLIB_DECL
|
||||
#define CLIB_DECL
|
||||
#endif
|
||||
#ifdef DEBUG
|
||||
#ifndef ATTR_PRINTF
|
||||
#define ATTR_PRINTF(x,y)
|
||||
#endif
|
||||
void CLIB_DECL D_(const char *text, ...) ATTR_PRINTF(1,2);
|
||||
#else
|
||||
// VS prior to VC7.1 does not support variadic macros. VC8.0 does not optimize unused parameters passing
|
||||
#if _MSC_VER < 1400
|
||||
void __inline CLIB_DECL D_(const char *text, ...) { do {} while (0); }
|
||||
#else
|
||||
#define D_(args, ...) do {} while (0)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#elif defined __ANDROID__
|
||||
|
||||
#ifdef DEBUG
|
||||
#include <android/log.h>
|
||||
#define D_CRIT " Error: "
|
||||
#define D_WARN "Warning: "
|
||||
#define D_INFO " Info: "
|
||||
#define D_(args...) do { \
|
||||
__android_log_print(ANDROID_LOG_DEBUG, "libxmp", args); \
|
||||
} while (0)
|
||||
#else
|
||||
#define D_(args...) do {} while (0)
|
||||
#endif
|
||||
|
||||
#elif defined(__WATCOMC__)
|
||||
#ifdef DEBUG
|
||||
#define D_INFO "\x1b[33m"
|
||||
#define D_CRIT "\x1b[31m"
|
||||
#define D_WARN "\x1b[36m"
|
||||
#define D_(...) do { \
|
||||
printf("\x1b[33m%s \x1b[37m[%s:%d] " D_INFO, __FUNCTION__, \
|
||||
__FILE__, __LINE__); printf (__VA_ARGS__); printf ("\x1b[0m\n"); \
|
||||
} while (0)
|
||||
#else
|
||||
#define D_(...) do {} while (0)
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#ifdef DEBUG
|
||||
#define D_INFO "\x1b[33m"
|
||||
#define D_CRIT "\x1b[31m"
|
||||
#define D_WARN "\x1b[36m"
|
||||
#define D_(args...) do { \
|
||||
printf("\x1b[33m%s \x1b[37m[%s:%d] " D_INFO, __FUNCTION__, \
|
||||
__FILE__, __LINE__); printf (args); printf ("\x1b[0m\n"); \
|
||||
} while (0)
|
||||
#else
|
||||
#define D_(args...) do {} while (0)
|
||||
#endif
|
||||
|
||||
#endif /* !_MSC_VER */
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define dup _dup
|
||||
#define fileno _fileno
|
||||
#define strnicmp _strnicmp
|
||||
#define strdup _strdup
|
||||
#define fdopen _fdopen
|
||||
#define open _open
|
||||
#define close _close
|
||||
#define unlink _unlink
|
||||
#define S_ISDIR(x) (((x)&_S_IFDIR) != 0)
|
||||
#endif
|
||||
#if defined(_WIN32) || defined(__WATCOMC__) /* in win32.c */
|
||||
#define USE_LIBXMP_SNPRINTF
|
||||
/* MSVC 2015+ has C99 compliant snprintf and vsnprintf implementations.
|
||||
* If __USE_MINGW_ANSI_STDIO is defined for MinGW (which it is by default),
|
||||
* compliant implementations will be used instead of the broken MSVCRT
|
||||
* functions. Additionally, GCC may optimize some calls to those functions. */
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1900
|
||||
#undef USE_LIBXMP_SNPRINTF
|
||||
#endif
|
||||
#if defined(__MINGW32__) && defined(__USE_MINGW_ANSI_STDIO) && (__USE_MINGW_ANSI_STDIO != 0)
|
||||
#undef USE_LIBXMP_SNPRINTF
|
||||
#endif
|
||||
#ifdef USE_LIBXMP_SNPRINTF
|
||||
int libxmp_vsnprintf(char *, size_t, const char *, va_list);
|
||||
int libxmp_snprintf (char *, size_t, const char *, ...);
|
||||
#define snprintf libxmp_snprintf
|
||||
#define vsnprintf libxmp_vsnprintf
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Quirks */
|
||||
#define QUIRK_S3MLOOP (1 << 0) /* S3M loop mode */
|
||||
#define QUIRK_ENVFADE (1 << 1) /* Fade at end of envelope */
|
||||
#define QUIRK_PROTRACK (1 << 2) /* Use Protracker-specific quirks */
|
||||
#define QUIRK_ST3BUGS (1 << 4) /* Scream Tracker 3 bug compatibility */
|
||||
#define QUIRK_FINEFX (1 << 5) /* Enable 0xf/0xe for fine effects */
|
||||
#define QUIRK_VSALL (1 << 6) /* Volume slides in all frames */
|
||||
#define QUIRK_PBALL (1 << 7) /* Pitch bending in all frames */
|
||||
#define QUIRK_PERPAT (1 << 8) /* Cancel persistent fx at pat start */
|
||||
#define QUIRK_VOLPDN (1 << 9) /* Set priority to volume slide down */
|
||||
#define QUIRK_UNISLD (1 << 10) /* Unified pitch slide/portamento */
|
||||
#define QUIRK_ITVPOR (1 << 11) /* Disable fine bends in IT vol fx */
|
||||
#define QUIRK_FTMOD (1 << 12) /* Flag for multichannel mods */
|
||||
/*#define QUIRK_MODRNG (1 << 13)*/ /* Limit periods to MOD range */
|
||||
#define QUIRK_INSVOL (1 << 14) /* Use instrument volume */
|
||||
#define QUIRK_VIRTUAL (1 << 15) /* Enable virtual channels */
|
||||
#define QUIRK_FILTER (1 << 16) /* Enable filter */
|
||||
#define QUIRK_IGSTPOR (1 << 17) /* Ignore stray tone portamento */
|
||||
#define QUIRK_KEYOFF (1 << 18) /* Keyoff doesn't reset fadeout */
|
||||
#define QUIRK_VIBHALF (1 << 19) /* Vibrato is half as deep */
|
||||
#define QUIRK_VIBALL (1 << 20) /* Vibrato in all frames */
|
||||
#define QUIRK_VIBINV (1 << 21) /* Vibrato has inverse waveform */
|
||||
#define QUIRK_PRENV (1 << 22) /* Portamento resets envelope & fade */
|
||||
#define QUIRK_ITOLDFX (1 << 23) /* IT old effects mode */
|
||||
#define QUIRK_S3MRTG (1 << 24) /* S3M-style retrig when count == 0 */
|
||||
#define QUIRK_RTDELAY (1 << 25) /* Delay effect retrigs instrument */
|
||||
#define QUIRK_FT2BUGS (1 << 26) /* FT2 bug compatibility */
|
||||
#define QUIRK_MARKER (1 << 27) /* Patterns 0xfe and 0xff reserved */
|
||||
#define QUIRK_NOBPM (1 << 28) /* Adjust speed only, no BPM */
|
||||
#define QUIRK_ARPMEM (1 << 29) /* Arpeggio has memory (S3M_ARPEGGIO) */
|
||||
#define QUIRK_RSTCHN (1 << 30) /* Reset channel on sample end */
|
||||
|
||||
#define HAS_QUIRK(x) (m->quirk & (x))
|
||||
|
||||
|
||||
/* Format quirks */
|
||||
#define QUIRKS_ST3 (QUIRK_S3MLOOP | QUIRK_VOLPDN | QUIRK_FINEFX | \
|
||||
QUIRK_S3MRTG | QUIRK_MARKER | QUIRK_RSTCHN )
|
||||
#define QUIRKS_FT2 (QUIRK_RTDELAY | QUIRK_FINEFX )
|
||||
#define QUIRKS_IT (QUIRK_S3MLOOP | QUIRK_FINEFX | QUIRK_VIBALL | \
|
||||
QUIRK_ENVFADE | QUIRK_ITVPOR | QUIRK_KEYOFF | \
|
||||
QUIRK_VIRTUAL | QUIRK_FILTER | QUIRK_RSTCHN | \
|
||||
QUIRK_IGSTPOR | QUIRK_S3MRTG | QUIRK_MARKER )
|
||||
|
||||
/* DSP effects */
|
||||
#define DSP_EFFECT_CUTOFF 0x02
|
||||
#define DSP_EFFECT_RESONANCE 0x03
|
||||
#define DSP_EFFECT_FILTER_A0 0xb0
|
||||
#define DSP_EFFECT_FILTER_B0 0xb1
|
||||
#define DSP_EFFECT_FILTER_B1 0xb2
|
||||
|
||||
/* Time factor */
|
||||
#define DEFAULT_TIME_FACTOR 10.0
|
||||
#define MED_TIME_FACTOR 2.64
|
||||
|
||||
#define MAX_SEQUENCES 16
|
||||
#define MAX_SAMPLE_SIZE 0x10000000
|
||||
#define MAX_SAMPLES 1024
|
||||
#define MAX_INSTRUMENTS 255
|
||||
#define MAX_PATTERNS 256
|
||||
|
||||
#define IS_PLAYER_MODE_MOD() (m->read_event_type == READ_EVENT_MOD)
|
||||
#define IS_PLAYER_MODE_FT2() (m->read_event_type == READ_EVENT_FT2)
|
||||
#define IS_PLAYER_MODE_ST3() (m->read_event_type == READ_EVENT_ST3)
|
||||
#define IS_PLAYER_MODE_IT() (m->read_event_type == READ_EVENT_IT)
|
||||
#define IS_PLAYER_MODE_MED() (m->read_event_type == READ_EVENT_MED)
|
||||
#define IS_PERIOD_MODRNG() (m->period_type == PERIOD_MODRNG)
|
||||
#define IS_PERIOD_LINEAR() (m->period_type == PERIOD_LINEAR)
|
||||
#define IS_PERIOD_CSPD() (m->period_type == PERIOD_CSPD)
|
||||
|
||||
#define IS_AMIGA_MOD() (IS_PLAYER_MODE_MOD() && IS_PERIOD_MODRNG())
|
||||
|
||||
struct ord_data {
|
||||
int speed;
|
||||
int bpm;
|
||||
int gvl;
|
||||
int time;
|
||||
int start_row;
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
int st26_speed;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* Context */
|
||||
|
||||
struct smix_data {
|
||||
int chn;
|
||||
int ins;
|
||||
int smp;
|
||||
struct xmp_instrument *xxi;
|
||||
struct xmp_sample *xxs;
|
||||
};
|
||||
|
||||
/* This will be added to the sample structure in the next API revision */
|
||||
struct extra_sample_data {
|
||||
double c5spd;
|
||||
};
|
||||
|
||||
struct module_data {
|
||||
struct xmp_module mod;
|
||||
|
||||
char *dirname; /* file dirname */
|
||||
char *basename; /* file basename */
|
||||
const char *filename; /* Module file name */
|
||||
char *comment; /* Comments, if any */
|
||||
uint8 md5[16]; /* MD5 message digest */
|
||||
int size; /* File size */
|
||||
double rrate; /* Replay rate */
|
||||
double time_factor; /* Time conversion constant */
|
||||
int c4rate; /* C4 replay rate */
|
||||
int volbase; /* Volume base */
|
||||
int gvolbase; /* Global volume base */
|
||||
int gvol; /* Global volume */
|
||||
int *vol_table; /* Volume translation table */
|
||||
int quirk; /* player quirks */
|
||||
#define READ_EVENT_MOD 0
|
||||
#define READ_EVENT_FT2 1
|
||||
#define READ_EVENT_ST3 2
|
||||
#define READ_EVENT_IT 3
|
||||
#define READ_EVENT_MED 4
|
||||
int read_event_type;
|
||||
#define PERIOD_AMIGA 0
|
||||
#define PERIOD_MODRNG 1
|
||||
#define PERIOD_LINEAR 2
|
||||
#define PERIOD_CSPD 3
|
||||
int period_type;
|
||||
int smpctl; /* sample control flags */
|
||||
int defpan; /* default pan setting */
|
||||
struct ord_data xxo_info[XMP_MAX_MOD_LENGTH];
|
||||
int num_sequences;
|
||||
struct xmp_sequence seq_data[MAX_SEQUENCES];
|
||||
char *instrument_path;
|
||||
void *extra; /* format-specific extra fields */
|
||||
uint8 **scan_cnt; /* scan counters */
|
||||
struct extra_sample_data *xtra;
|
||||
#ifndef LIBXMP_CORE_DISABLE_IT
|
||||
struct xmp_sample *xsmp; /* sustain loop samples */
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
struct pattern_loop {
|
||||
int start;
|
||||
int count;
|
||||
};
|
||||
|
||||
struct flow_control {
|
||||
int pbreak;
|
||||
int jump;
|
||||
int delay;
|
||||
int jumpline;
|
||||
int loop_chn;
|
||||
|
||||
struct pattern_loop *loop;
|
||||
|
||||
int num_rows;
|
||||
int end_point;
|
||||
#define ROWDELAY_ON (1 << 0)
|
||||
#define ROWDELAY_FIRST_FRAME (1 << 1)
|
||||
int rowdelay; /* For IT pattern row delay */
|
||||
int rowdelay_set;
|
||||
};
|
||||
|
||||
struct virt_channel {
|
||||
int count;
|
||||
int map;
|
||||
};
|
||||
|
||||
struct player_data {
|
||||
int ord;
|
||||
int pos;
|
||||
int row;
|
||||
int frame;
|
||||
int speed;
|
||||
int bpm;
|
||||
int mode;
|
||||
int player_flags;
|
||||
int flags;
|
||||
|
||||
double current_time;
|
||||
double frame_time;
|
||||
|
||||
int loop_count;
|
||||
int sequence;
|
||||
unsigned char sequence_control[XMP_MAX_MOD_LENGTH];
|
||||
|
||||
int smix_vol; /* SFX volume */
|
||||
int master_vol; /* Music volume */
|
||||
int gvol;
|
||||
|
||||
struct flow_control flow;
|
||||
|
||||
struct {
|
||||
int time; /* replay time in ms */
|
||||
int ord;
|
||||
int row;
|
||||
int num;
|
||||
} scan[MAX_SEQUENCES];
|
||||
|
||||
struct channel_data *xc_data;
|
||||
|
||||
int channel_vol[XMP_MAX_CHANNELS];
|
||||
char channel_mute[XMP_MAX_CHANNELS];
|
||||
|
||||
struct virt_control {
|
||||
int num_tracks; /* Number of tracks */
|
||||
int virt_channels; /* Number of virtual channels */
|
||||
int virt_used; /* Number of voices currently in use */
|
||||
int maxvoc; /* Number of sound card voices */
|
||||
|
||||
struct virt_channel *virt_channel;
|
||||
|
||||
struct mixer_voice *voice_array;
|
||||
} virt;
|
||||
|
||||
struct xmp_event inject_event[XMP_MAX_CHANNELS];
|
||||
|
||||
struct {
|
||||
int consumed;
|
||||
int in_size;
|
||||
char *in_buffer;
|
||||
} buffer_data;
|
||||
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
int st26_speed; /* For IceTracker speed effect */
|
||||
#endif
|
||||
int filter; /* Amiga led filter */
|
||||
};
|
||||
|
||||
struct mixer_data {
|
||||
int freq; /* sampling rate */
|
||||
int format; /* sample format */
|
||||
int amplify; /* amplification multiplier */
|
||||
int mix; /* percentage of channel separation */
|
||||
int interp; /* interpolation type */
|
||||
int dsp; /* dsp effect flags */
|
||||
char* buffer; /* output buffer */
|
||||
int32* buf32; /* temporary buffer for 32 bit samples */
|
||||
int numvoc; /* default softmixer voices number */
|
||||
int ticksize;
|
||||
int dtright; /* anticlick control, right channel */
|
||||
int dtleft; /* anticlick control, left channel */
|
||||
double pbase; /* period base */
|
||||
};
|
||||
|
||||
struct context_data {
|
||||
struct player_data p;
|
||||
struct mixer_data s;
|
||||
struct module_data m;
|
||||
struct smix_data smix;
|
||||
int state;
|
||||
};
|
||||
|
||||
|
||||
/* Prototypes */
|
||||
|
||||
char *libxmp_adjust_string (char *);
|
||||
int libxmp_prepare_scan (struct context_data *);
|
||||
void libxmp_free_scan (struct context_data *);
|
||||
int libxmp_scan_sequences (struct context_data *);
|
||||
int libxmp_get_sequence (struct context_data *, int);
|
||||
int libxmp_set_player_mode (struct context_data *);
|
||||
|
||||
int8 read8s (FILE *, int *err);
|
||||
uint8 read8 (FILE *, int *err);
|
||||
uint16 read16l (FILE *, int *err);
|
||||
uint16 read16b (FILE *, int *err);
|
||||
uint32 read24l (FILE *, int *err);
|
||||
uint32 read24b (FILE *, int *err);
|
||||
uint32 read32l (FILE *, int *err);
|
||||
uint32 read32b (FILE *, int *err);
|
||||
static inline void write8 (FILE *f, uint8 b) {
|
||||
fputc(b, f);
|
||||
}
|
||||
void write16l (FILE *, uint16);
|
||||
void write16b (FILE *, uint16);
|
||||
void write32l (FILE *, uint32);
|
||||
void write32b (FILE *, uint32);
|
||||
int move_data (FILE *, FILE *, int);
|
||||
|
||||
uint16 readmem16l (const uint8 *);
|
||||
uint16 readmem16b (const uint8 *);
|
||||
uint32 readmem24l (const uint8 *);
|
||||
uint32 readmem24b (const uint8 *);
|
||||
uint32 readmem32l (const uint8 *);
|
||||
uint32 readmem32b (const uint8 *);
|
||||
|
||||
struct xmp_instrument *libxmp_get_instrument(struct context_data *, int);
|
||||
struct xmp_sample *libxmp_get_sample(struct context_data *, int);
|
||||
|
||||
#endif /* LIBXMP_COMMON_H */
|
585
internal/c/parts/audio/extras/libxmp-lite/control.c
Normal file
585
internal/c/parts/audio/extras/libxmp-lite/control.c
Normal file
|
@ -0,0 +1,585 @@
|
|||
/* Extended Module Player
|
||||
* Copyright (C) 1996-2021 Claudio Matsuoka and Hipolito Carraro Jr
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "format.h"
|
||||
#include "virtual.h"
|
||||
#include "mixer.h"
|
||||
|
||||
const char *xmp_version LIBXMP_EXPORT_VAR = XMP_VERSION;
|
||||
const unsigned int xmp_vercode LIBXMP_EXPORT_VAR = XMP_VERCODE;
|
||||
|
||||
xmp_context xmp_create_context(void)
|
||||
{
|
||||
struct context_data *ctx;
|
||||
|
||||
ctx = calloc(1, sizeof(struct context_data));
|
||||
if (ctx == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ctx->state = XMP_STATE_UNLOADED;
|
||||
ctx->m.defpan = 100;
|
||||
ctx->s.numvoc = SMIX_NUMVOC;
|
||||
|
||||
return (xmp_context)ctx;
|
||||
}
|
||||
|
||||
void xmp_free_context(xmp_context opaque)
|
||||
{
|
||||
struct context_data *ctx = (struct context_data *)opaque;
|
||||
struct module_data *m = &ctx->m;
|
||||
|
||||
if (ctx->state > XMP_STATE_UNLOADED)
|
||||
xmp_release_module(opaque);
|
||||
|
||||
free(m->instrument_path);
|
||||
free(opaque);
|
||||
}
|
||||
|
||||
static void set_position(struct context_data *ctx, int pos, int dir)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
struct module_data *m = &ctx->m;
|
||||
struct xmp_module *mod = &m->mod;
|
||||
struct flow_control *f = &p->flow;
|
||||
int seq;
|
||||
int has_marker;
|
||||
|
||||
/* If dir is 0, we can jump to a different sequence */
|
||||
if (dir == 0) {
|
||||
seq = libxmp_get_sequence(ctx, pos);
|
||||
} else {
|
||||
seq = p->sequence;
|
||||
}
|
||||
|
||||
if (seq == 0xff) {
|
||||
return;
|
||||
}
|
||||
|
||||
has_marker = HAS_QUIRK(QUIRK_MARKER);
|
||||
|
||||
if (seq >= 0) {
|
||||
int start = m->seq_data[seq].entry_point;
|
||||
|
||||
p->sequence = seq;
|
||||
|
||||
if (pos >= 0) {
|
||||
int pat;
|
||||
|
||||
while (has_marker && mod->xxo[pos] == 0xfe) {
|
||||
if (dir < 0) {
|
||||
if (pos > start) {
|
||||
pos--;
|
||||
}
|
||||
} else {
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
pat = mod->xxo[pos];
|
||||
|
||||
if (pat < mod->pat) {
|
||||
if (has_marker && pat == 0xff) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (pos > p->scan[seq].ord) {
|
||||
f->end_point = 0;
|
||||
} else {
|
||||
f->num_rows = mod->xxp[pat]->rows;
|
||||
f->end_point = p->scan[seq].num;
|
||||
f->jumpline = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pos < mod->len) {
|
||||
if (pos == 0) {
|
||||
p->pos = -1;
|
||||
} else {
|
||||
p->pos = pos;
|
||||
}
|
||||
f->jumpline = 0;
|
||||
f->jump = -1;
|
||||
f->pbreak = 0;
|
||||
f->loop_chn = 0;
|
||||
f->delay = 0;
|
||||
f->rowdelay = 0;
|
||||
f->rowdelay_set = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int xmp_next_position(xmp_context opaque)
|
||||
{
|
||||
struct context_data *ctx = (struct context_data *)opaque;
|
||||
struct player_data *p = &ctx->p;
|
||||
struct module_data *m = &ctx->m;
|
||||
|
||||
if (ctx->state < XMP_STATE_PLAYING)
|
||||
return -XMP_ERROR_STATE;
|
||||
|
||||
if (p->pos < m->mod.len)
|
||||
set_position(ctx, p->pos + 1, 1);
|
||||
|
||||
return p->pos;
|
||||
}
|
||||
|
||||
int xmp_prev_position(xmp_context opaque)
|
||||
{
|
||||
struct context_data *ctx = (struct context_data *)opaque;
|
||||
struct player_data *p = &ctx->p;
|
||||
struct module_data *m = &ctx->m;
|
||||
|
||||
if (ctx->state < XMP_STATE_PLAYING)
|
||||
return -XMP_ERROR_STATE;
|
||||
|
||||
if (p->pos == m->seq_data[p->sequence].entry_point) {
|
||||
set_position(ctx, -1, -1);
|
||||
} else if (p->pos > m->seq_data[p->sequence].entry_point) {
|
||||
set_position(ctx, p->pos - 1, -1);
|
||||
}
|
||||
return p->pos < 0 ? 0 : p->pos;
|
||||
}
|
||||
|
||||
int xmp_set_position(xmp_context opaque, int pos)
|
||||
{
|
||||
struct context_data *ctx = (struct context_data *)opaque;
|
||||
struct player_data *p = &ctx->p;
|
||||
struct module_data *m = &ctx->m;
|
||||
|
||||
if (ctx->state < XMP_STATE_PLAYING)
|
||||
return -XMP_ERROR_STATE;
|
||||
|
||||
if (pos >= m->mod.len)
|
||||
return -XMP_ERROR_INVALID;
|
||||
|
||||
set_position(ctx, pos, 0);
|
||||
|
||||
return p->pos;
|
||||
}
|
||||
|
||||
int xmp_set_row(xmp_context opaque, int row)
|
||||
{
|
||||
struct context_data *ctx = (struct context_data *)opaque;
|
||||
struct player_data *p = &ctx->p;
|
||||
struct module_data *m = &ctx->m;
|
||||
struct xmp_module *mod = &m->mod;
|
||||
struct flow_control *f = &p->flow;
|
||||
int pos = p->pos;
|
||||
int pattern = mod->xxo[pos];
|
||||
|
||||
if (pos < 0 || pos >= mod->len) {
|
||||
pos = 0;
|
||||
}
|
||||
|
||||
if (ctx->state < XMP_STATE_PLAYING)
|
||||
return -XMP_ERROR_STATE;
|
||||
|
||||
if (row >= mod->xxp[pattern]->rows)
|
||||
return -XMP_ERROR_INVALID;
|
||||
|
||||
/* See set_position. */
|
||||
if (p->pos < 0)
|
||||
p->pos = 0;
|
||||
p->ord = p->pos;
|
||||
p->row = row;
|
||||
p->frame = -1;
|
||||
f->num_rows = mod->xxp[mod->xxo[p->ord]]->rows;
|
||||
|
||||
return row;
|
||||
}
|
||||
|
||||
void xmp_stop_module(xmp_context opaque)
|
||||
{
|
||||
struct context_data *ctx = (struct context_data *)opaque;
|
||||
struct player_data *p = &ctx->p;
|
||||
|
||||
if (ctx->state < XMP_STATE_PLAYING)
|
||||
return;
|
||||
|
||||
p->pos = -2;
|
||||
}
|
||||
|
||||
void xmp_restart_module(xmp_context opaque)
|
||||
{
|
||||
struct context_data *ctx = (struct context_data *)opaque;
|
||||
struct player_data *p = &ctx->p;
|
||||
|
||||
if (ctx->state < XMP_STATE_PLAYING)
|
||||
return;
|
||||
|
||||
p->loop_count = 0;
|
||||
p->pos = -1;
|
||||
}
|
||||
|
||||
int xmp_seek_time(xmp_context opaque, int time)
|
||||
{
|
||||
struct context_data *ctx = (struct context_data *)opaque;
|
||||
struct player_data *p = &ctx->p;
|
||||
struct module_data *m = &ctx->m;
|
||||
int i, t;
|
||||
|
||||
if (ctx->state < XMP_STATE_PLAYING)
|
||||
return -XMP_ERROR_STATE;
|
||||
|
||||
for (i = m->mod.len - 1; i >= 0; i--) {
|
||||
int pat = m->mod.xxo[i];
|
||||
if (pat >= m->mod.pat) {
|
||||
continue;
|
||||
}
|
||||
if (libxmp_get_sequence(ctx, i) != p->sequence) {
|
||||
continue;
|
||||
}
|
||||
t = m->xxo_info[i].time;
|
||||
if (time >= t) {
|
||||
set_position(ctx, i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i < 0) {
|
||||
xmp_set_position(opaque, 0);
|
||||
}
|
||||
|
||||
return p->pos < 0 ? 0 : p->pos;
|
||||
}
|
||||
|
||||
int xmp_channel_mute(xmp_context opaque, int chn, int status)
|
||||
{
|
||||
struct context_data *ctx = (struct context_data *)opaque;
|
||||
struct player_data *p = &ctx->p;
|
||||
int ret;
|
||||
|
||||
if (ctx->state < XMP_STATE_PLAYING)
|
||||
return -XMP_ERROR_STATE;
|
||||
|
||||
if (chn < 0 || chn >= XMP_MAX_CHANNELS) {
|
||||
return -XMP_ERROR_INVALID;
|
||||
}
|
||||
|
||||
ret = p->channel_mute[chn];
|
||||
|
||||
if (status >= 2) {
|
||||
p->channel_mute[chn] = !p->channel_mute[chn];
|
||||
} else if (status >= 0) {
|
||||
p->channel_mute[chn] = status;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int xmp_channel_vol(xmp_context opaque, int chn, int vol)
|
||||
{
|
||||
struct context_data *ctx = (struct context_data *)opaque;
|
||||
struct player_data *p = &ctx->p;
|
||||
int ret;
|
||||
|
||||
if (ctx->state < XMP_STATE_PLAYING)
|
||||
return -XMP_ERROR_STATE;
|
||||
|
||||
if (chn < 0 || chn >= XMP_MAX_CHANNELS) {
|
||||
return -XMP_ERROR_INVALID;
|
||||
}
|
||||
|
||||
ret = p->channel_vol[chn];
|
||||
|
||||
if (vol >= 0 && vol <= 100) {
|
||||
p->channel_vol[chn] = vol;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef USE_VERSIONED_SYMBOLS
|
||||
LIBXMP_EXPORT extern int xmp_set_player_v40__(xmp_context, int, int);
|
||||
LIBXMP_EXPORT extern int xmp_set_player_v41__(xmp_context, int, int)
|
||||
__attribute__((alias("xmp_set_player_v40__")));
|
||||
LIBXMP_EXPORT extern int xmp_set_player_v43__(xmp_context, int, int)
|
||||
__attribute__((alias("xmp_set_player_v40__")));
|
||||
LIBXMP_EXPORT extern int xmp_set_player_v44__(xmp_context, int, int)
|
||||
__attribute__((alias("xmp_set_player_v40__")));
|
||||
|
||||
asm(".symver xmp_set_player_v40__, xmp_set_player@XMP_4.0");
|
||||
asm(".symver xmp_set_player_v41__, xmp_set_player@XMP_4.1");
|
||||
asm(".symver xmp_set_player_v43__, xmp_set_player@XMP_4.3");
|
||||
asm(".symver xmp_set_player_v44__, xmp_set_player@@XMP_4.4");
|
||||
|
||||
#define xmp_set_player__ xmp_set_player_v40__
|
||||
#else
|
||||
#define xmp_set_player__ xmp_set_player
|
||||
#endif
|
||||
|
||||
int xmp_set_player__(xmp_context opaque, int parm, int val)
|
||||
{
|
||||
struct context_data *ctx = (struct context_data *)opaque;
|
||||
struct player_data *p = &ctx->p;
|
||||
struct module_data *m = &ctx->m;
|
||||
struct mixer_data *s = &ctx->s;
|
||||
int ret = -XMP_ERROR_INVALID;
|
||||
|
||||
|
||||
if (parm == XMP_PLAYER_SMPCTL || parm == XMP_PLAYER_DEFPAN) {
|
||||
/* these should be set before loading the module */
|
||||
if (ctx->state >= XMP_STATE_LOADED) {
|
||||
return -XMP_ERROR_STATE;
|
||||
}
|
||||
} else if (parm == XMP_PLAYER_VOICES) {
|
||||
/* these should be set before start playing */
|
||||
if (ctx->state >= XMP_STATE_PLAYING) {
|
||||
return -XMP_ERROR_STATE;
|
||||
}
|
||||
} else if (ctx->state < XMP_STATE_PLAYING) {
|
||||
return -XMP_ERROR_STATE;
|
||||
}
|
||||
|
||||
switch (parm) {
|
||||
case XMP_PLAYER_AMP:
|
||||
if (val >= 0 && val <= 3) {
|
||||
s->amplify = val;
|
||||
ret = 0;
|
||||
}
|
||||
break;
|
||||
case XMP_PLAYER_MIX:
|
||||
if (val >= -100 && val <= 100) {
|
||||
s->mix = val;
|
||||
ret = 0;
|
||||
}
|
||||
break;
|
||||
case XMP_PLAYER_INTERP:
|
||||
if (val >= XMP_INTERP_NEAREST && val <= XMP_INTERP_SPLINE) {
|
||||
s->interp = val;
|
||||
ret = 0;
|
||||
}
|
||||
break;
|
||||
case XMP_PLAYER_DSP:
|
||||
s->dsp = val;
|
||||
ret = 0;
|
||||
break;
|
||||
case XMP_PLAYER_FLAGS: {
|
||||
p->player_flags = val;
|
||||
ret = 0;
|
||||
break; }
|
||||
|
||||
/* 4.1 */
|
||||
case XMP_PLAYER_CFLAGS: {
|
||||
int vblank = p->flags & XMP_FLAGS_VBLANK;
|
||||
p->flags = val;
|
||||
if (vblank != (p->flags & XMP_FLAGS_VBLANK))
|
||||
libxmp_scan_sequences(ctx);
|
||||
ret = 0;
|
||||
break; }
|
||||
case XMP_PLAYER_SMPCTL:
|
||||
m->smpctl = val;
|
||||
ret = 0;
|
||||
break;
|
||||
case XMP_PLAYER_VOLUME:
|
||||
if (val >= 0 && val <= 200) {
|
||||
p->master_vol = val;
|
||||
ret = 0;
|
||||
}
|
||||
break;
|
||||
case XMP_PLAYER_SMIX_VOLUME:
|
||||
if (val >= 0 && val <= 200) {
|
||||
p->smix_vol = val;
|
||||
ret = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
/* 4.3 */
|
||||
case XMP_PLAYER_DEFPAN:
|
||||
if (val >= 0 && val <= 100) {
|
||||
m->defpan = val;
|
||||
ret = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
/* 4.4 */
|
||||
case XMP_PLAYER_MODE:
|
||||
p->mode = val;
|
||||
libxmp_set_player_mode(ctx);
|
||||
libxmp_scan_sequences(ctx);
|
||||
ret = 0;
|
||||
break;
|
||||
case XMP_PLAYER_VOICES:
|
||||
s->numvoc = val;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef USE_VERSIONED_SYMBOLS
|
||||
LIBXMP_EXPORT extern int xmp_get_player_v40__(xmp_context, int);
|
||||
LIBXMP_EXPORT extern int xmp_get_player_v41__(xmp_context, int)
|
||||
__attribute__((alias("xmp_get_player_v40__")));
|
||||
LIBXMP_EXPORT extern int xmp_get_player_v42__(xmp_context, int)
|
||||
__attribute__((alias("xmp_get_player_v40__")));
|
||||
LIBXMP_EXPORT extern int xmp_get_player_v43__(xmp_context, int)
|
||||
__attribute__((alias("xmp_get_player_v40__")));
|
||||
LIBXMP_EXPORT extern int xmp_get_player_v44__(xmp_context, int)
|
||||
__attribute__((alias("xmp_get_player_v40__")));
|
||||
|
||||
asm(".symver xmp_get_player_v40__, xmp_get_player@XMP_4.0");
|
||||
asm(".symver xmp_get_player_v41__, xmp_get_player@XMP_4.1");
|
||||
asm(".symver xmp_get_player_v42__, xmp_get_player@XMP_4.2");
|
||||
asm(".symver xmp_get_player_v43__, xmp_get_player@XMP_4.3");
|
||||
asm(".symver xmp_get_player_v44__, xmp_get_player@@XMP_4.4");
|
||||
|
||||
#define xmp_get_player__ xmp_get_player_v40__
|
||||
#else
|
||||
#define xmp_get_player__ xmp_get_player
|
||||
#endif
|
||||
|
||||
int xmp_get_player__(xmp_context opaque, int parm)
|
||||
{
|
||||
struct context_data *ctx = (struct context_data *)opaque;
|
||||
struct player_data *p = &ctx->p;
|
||||
struct module_data *m = &ctx->m;
|
||||
struct mixer_data *s = &ctx->s;
|
||||
int ret = -XMP_ERROR_INVALID;
|
||||
|
||||
if (parm == XMP_PLAYER_SMPCTL || parm == XMP_PLAYER_DEFPAN) {
|
||||
// can read these at any time
|
||||
} else if (parm != XMP_PLAYER_STATE && ctx->state < XMP_STATE_PLAYING) {
|
||||
return -XMP_ERROR_STATE;
|
||||
}
|
||||
|
||||
switch (parm) {
|
||||
case XMP_PLAYER_AMP:
|
||||
ret = s->amplify;
|
||||
break;
|
||||
case XMP_PLAYER_MIX:
|
||||
ret = s->mix;
|
||||
break;
|
||||
case XMP_PLAYER_INTERP:
|
||||
ret = s->interp;
|
||||
break;
|
||||
case XMP_PLAYER_DSP:
|
||||
ret = s->dsp;
|
||||
break;
|
||||
case XMP_PLAYER_FLAGS:
|
||||
ret = p->player_flags;
|
||||
break;
|
||||
|
||||
/* 4.1 */
|
||||
case XMP_PLAYER_CFLAGS:
|
||||
ret = p->flags;
|
||||
break;
|
||||
case XMP_PLAYER_SMPCTL:
|
||||
ret = m->smpctl;
|
||||
break;
|
||||
case XMP_PLAYER_VOLUME:
|
||||
ret = p->master_vol;
|
||||
break;
|
||||
case XMP_PLAYER_SMIX_VOLUME:
|
||||
ret = p->smix_vol;
|
||||
break;
|
||||
|
||||
/* 4.2 */
|
||||
case XMP_PLAYER_STATE:
|
||||
ret = ctx->state;
|
||||
break;
|
||||
|
||||
/* 4.3 */
|
||||
case XMP_PLAYER_DEFPAN:
|
||||
ret = m->defpan;
|
||||
break;
|
||||
|
||||
/* 4.4 */
|
||||
case XMP_PLAYER_MODE:
|
||||
ret = p->mode;
|
||||
break;
|
||||
case XMP_PLAYER_MIXER_TYPE:
|
||||
ret = XMP_MIXER_STANDARD;
|
||||
if (p->flags & XMP_FLAGS_A500) {
|
||||
if (IS_AMIGA_MOD()) {
|
||||
#ifdef LIBXMP_PAULA_SIMULATOR
|
||||
if (p->filter) {
|
||||
ret = XMP_MIXER_A500F;
|
||||
} else {
|
||||
ret = XMP_MIXER_A500;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
break;
|
||||
case XMP_PLAYER_VOICES:
|
||||
ret = s->numvoc;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
const char *const *xmp_get_format_list(void)
|
||||
{
|
||||
return format_list();
|
||||
}
|
||||
|
||||
void xmp_inject_event(xmp_context opaque, int channel, struct xmp_event *e)
|
||||
{
|
||||
struct context_data *ctx = (struct context_data *)opaque;
|
||||
struct player_data *p = &ctx->p;
|
||||
|
||||
if (ctx->state < XMP_STATE_PLAYING)
|
||||
return;
|
||||
|
||||
memcpy(&p->inject_event[channel], e, sizeof(struct xmp_event));
|
||||
p->inject_event[channel]._flag = 1;
|
||||
}
|
||||
|
||||
int xmp_set_instrument_path(xmp_context opaque, const char *path)
|
||||
{
|
||||
struct context_data *ctx = (struct context_data *)opaque;
|
||||
struct module_data *m = &ctx->m;
|
||||
|
||||
if (m->instrument_path != NULL)
|
||||
free(m->instrument_path);
|
||||
|
||||
m->instrument_path = strdup(path);
|
||||
if (m->instrument_path == NULL) {
|
||||
return -XMP_ERROR_SYSTEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int xmp_set_tempo_factor(xmp_context opaque, double val)
|
||||
{
|
||||
struct context_data *ctx = (struct context_data *)opaque;
|
||||
struct player_data *p = &ctx->p;
|
||||
struct module_data *m = &ctx->m;
|
||||
struct mixer_data *s = &ctx->s;
|
||||
int ticksize;
|
||||
|
||||
if (val <= 0.0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
val *= 10;
|
||||
ticksize = s->freq * val * m->rrate / p->bpm / 1000 * sizeof(int);
|
||||
if (ticksize > XMP_MAX_FRAMESIZE) {
|
||||
return -1;
|
||||
}
|
||||
m->time_factor = val;
|
||||
|
||||
return 0;
|
||||
}
|
269
internal/c/parts/audio/extras/libxmp-lite/dataio.c
Normal file
269
internal/c/parts/audio/extras/libxmp-lite/dataio.c
Normal file
|
@ -0,0 +1,269 @@
|
|||
/* Extended Module Player
|
||||
* Copyright (C) 1996-2021 Claudio Matsuoka and Hipolito Carraro Jr
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include "common.h"
|
||||
|
||||
|
||||
#define read_byte(x) do { \
|
||||
(x) = fgetc(f); \
|
||||
if ((x) < 0) goto error; \
|
||||
} while (0)
|
||||
|
||||
#define set_error(x) do { \
|
||||
if (err != NULL) *err = (x); \
|
||||
} while (0)
|
||||
|
||||
|
||||
uint8 read8(FILE *f, int *err)
|
||||
{
|
||||
int a;
|
||||
|
||||
read_byte(a);
|
||||
set_error(0);
|
||||
return a;
|
||||
|
||||
error:
|
||||
set_error(ferror(f) ? errno : EOF);
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
int8 read8s(FILE *f, int *err)
|
||||
{
|
||||
int a;
|
||||
|
||||
read_byte(a);
|
||||
set_error(0);
|
||||
return (int8)a;
|
||||
|
||||
error:
|
||||
set_error(ferror(f) ? errno : EOF);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16 read16l(FILE *f, int *err)
|
||||
{
|
||||
int a, b;
|
||||
|
||||
read_byte(a);
|
||||
read_byte(b);
|
||||
|
||||
set_error(0);
|
||||
return ((uint16)b << 8) | a;
|
||||
|
||||
error:
|
||||
set_error(ferror(f) ? errno : EOF);
|
||||
return 0xffff;
|
||||
}
|
||||
|
||||
uint16 read16b(FILE *f, int *err)
|
||||
{
|
||||
int a, b;
|
||||
|
||||
read_byte(a);
|
||||
read_byte(b);
|
||||
|
||||
set_error(0);
|
||||
return (a << 8) | b;
|
||||
|
||||
error:
|
||||
set_error(ferror(f) ? errno : EOF);
|
||||
return 0xffff;
|
||||
}
|
||||
|
||||
uint32 read24l(FILE *f, int *err)
|
||||
{
|
||||
int a, b, c;
|
||||
|
||||
read_byte(a);
|
||||
read_byte(b);
|
||||
read_byte(c);
|
||||
|
||||
set_error(0);
|
||||
return (c << 16) | (b << 8) | a;
|
||||
|
||||
error:
|
||||
set_error(ferror(f) ? errno : EOF);
|
||||
return 0xffffff;
|
||||
}
|
||||
|
||||
uint32 read24b(FILE *f, int *err)
|
||||
{
|
||||
int a, b, c;
|
||||
|
||||
read_byte(a);
|
||||
read_byte(b);
|
||||
read_byte(c);
|
||||
|
||||
set_error(0);
|
||||
return (a << 16) | (b << 8) | c;
|
||||
|
||||
error:
|
||||
set_error(ferror(f) ? errno : EOF);
|
||||
return 0xffffff;
|
||||
}
|
||||
|
||||
uint32 read32l(FILE *f, int *err)
|
||||
{
|
||||
int a, b, c, d;
|
||||
|
||||
read_byte(a);
|
||||
read_byte(b);
|
||||
read_byte(c);
|
||||
read_byte(d);
|
||||
|
||||
set_error(0);
|
||||
return (d << 24) | (c << 16) | (b << 8) | a;
|
||||
|
||||
error:
|
||||
set_error(ferror(f) ? errno : EOF);
|
||||
return 0xffffffff;
|
||||
}
|
||||
|
||||
uint32 read32b(FILE *f, int *err)
|
||||
{
|
||||
int a, b, c, d;
|
||||
|
||||
read_byte(a);
|
||||
read_byte(b);
|
||||
read_byte(c);
|
||||
read_byte(d);
|
||||
|
||||
set_error(0);
|
||||
return (a << 24) | (b << 16) | (c << 8) | d;
|
||||
|
||||
error:
|
||||
set_error(ferror(f) ? errno : EOF);
|
||||
return 0xffffffff;
|
||||
}
|
||||
|
||||
uint16 readmem16l(const uint8 *m)
|
||||
{
|
||||
uint32 a, b;
|
||||
|
||||
a = m[0];
|
||||
b = m[1];
|
||||
|
||||
return (b << 8) | a;
|
||||
}
|
||||
|
||||
uint16 readmem16b(const uint8 *m)
|
||||
{
|
||||
uint32 a, b;
|
||||
|
||||
a = m[0];
|
||||
b = m[1];
|
||||
|
||||
return (a << 8) | b;
|
||||
}
|
||||
|
||||
uint32 readmem24l(const uint8 *m)
|
||||
{
|
||||
uint32 a, b, c;
|
||||
|
||||
a = m[0];
|
||||
b = m[1];
|
||||
c = m[2];
|
||||
|
||||
return (c << 16) | (b << 8) | a;
|
||||
}
|
||||
|
||||
uint32 readmem24b(const uint8 *m)
|
||||
{
|
||||
uint32 a, b, c;
|
||||
|
||||
a = m[0];
|
||||
b = m[1];
|
||||
c = m[2];
|
||||
|
||||
return (a << 16) | (b << 8) | c;
|
||||
}
|
||||
|
||||
uint32 readmem32l(const uint8 *m)
|
||||
{
|
||||
uint32 a, b, c, d;
|
||||
|
||||
a = m[0];
|
||||
b = m[1];
|
||||
c = m[2];
|
||||
d = m[3];
|
||||
|
||||
return (d << 24) | (c << 16) | (b << 8) | a;
|
||||
}
|
||||
|
||||
uint32 readmem32b(const uint8 *m)
|
||||
{
|
||||
uint32 a, b, c, d;
|
||||
|
||||
a = m[0];
|
||||
b = m[1];
|
||||
c = m[2];
|
||||
d = m[3];
|
||||
|
||||
return (a << 24) | (b << 16) | (c << 8) | d;
|
||||
}
|
||||
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
|
||||
void write16l(FILE *f, uint16 w)
|
||||
{
|
||||
write8(f, w & 0x00ff);
|
||||
write8(f, (w & 0xff00) >> 8);
|
||||
}
|
||||
|
||||
void write16b(FILE *f, uint16 w)
|
||||
{
|
||||
write8(f, (w & 0xff00) >> 8);
|
||||
write8(f, w & 0x00ff);
|
||||
}
|
||||
|
||||
void write32l(FILE *f, uint32 w)
|
||||
{
|
||||
write8(f, w & 0x000000ff);
|
||||
write8(f, (w & 0x0000ff00) >> 8);
|
||||
write8(f, (w & 0x00ff0000) >> 16);
|
||||
write8(f, (w & 0xff000000) >> 24);
|
||||
}
|
||||
|
||||
void write32b(FILE *f, uint32 w)
|
||||
{
|
||||
write8(f, (w & 0xff000000) >> 24);
|
||||
write8(f, (w & 0x00ff0000) >> 16);
|
||||
write8(f, (w & 0x0000ff00) >> 8);
|
||||
write8(f, w & 0x000000ff);
|
||||
}
|
||||
|
||||
int move_data(FILE *out, FILE *in, int len)
|
||||
{
|
||||
uint8 buf[1024];
|
||||
int l;
|
||||
|
||||
do {
|
||||
l = fread(buf, 1, len > 1024 ? 1024 : len, in);
|
||||
fwrite(buf, 1, l, out);
|
||||
len -= l;
|
||||
} while (l > 0 && len > 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
1072
internal/c/parts/audio/extras/libxmp-lite/effects.c
Normal file
1072
internal/c/parts/audio/extras/libxmp-lite/effects.c
Normal file
File diff suppressed because it is too large
Load diff
143
internal/c/parts/audio/extras/libxmp-lite/effects.h
Normal file
143
internal/c/parts/audio/extras/libxmp-lite/effects.h
Normal file
|
@ -0,0 +1,143 @@
|
|||
#ifndef LIBXMP_EFFECTS_H
|
||||
#define LIBXMP_EFFECTS_H
|
||||
|
||||
/* Protracker effects */
|
||||
#define FX_ARPEGGIO 0x00
|
||||
#define FX_PORTA_UP 0x01
|
||||
#define FX_PORTA_DN 0x02
|
||||
#define FX_TONEPORTA 0x03
|
||||
#define FX_VIBRATO 0x04
|
||||
#define FX_TONE_VSLIDE 0x05
|
||||
#define FX_VIBRA_VSLIDE 0x06
|
||||
#define FX_TREMOLO 0x07
|
||||
#define FX_OFFSET 0x09
|
||||
#define FX_VOLSLIDE 0x0a
|
||||
#define FX_JUMP 0x0b
|
||||
#define FX_VOLSET 0x0c
|
||||
#define FX_BREAK 0x0d
|
||||
#define FX_EXTENDED 0x0e
|
||||
#define FX_SPEED 0x0f
|
||||
|
||||
/* Fast tracker effects */
|
||||
#define FX_SETPAN 0x08
|
||||
|
||||
/* Fast Tracker II effects */
|
||||
#define FX_GLOBALVOL 0x10
|
||||
#define FX_GVOL_SLIDE 0x11
|
||||
#define FX_KEYOFF 0x14
|
||||
#define FX_ENVPOS 0x15
|
||||
#define FX_PANSLIDE 0x19
|
||||
#define FX_MULTI_RETRIG 0x1b
|
||||
#define FX_TREMOR 0x1d
|
||||
#define FX_XF_PORTA 0x21
|
||||
|
||||
/* Protracker extended effects */
|
||||
#define EX_FILTER 0x00
|
||||
#define EX_F_PORTA_UP 0x01
|
||||
#define EX_F_PORTA_DN 0x02
|
||||
#define EX_GLISS 0x03
|
||||
#define EX_VIBRATO_WF 0x04
|
||||
#define EX_FINETUNE 0x05
|
||||
#define EX_PATTERN_LOOP 0x06
|
||||
#define EX_TREMOLO_WF 0x07
|
||||
#define EX_SETPAN 0x08
|
||||
#define EX_RETRIG 0x09
|
||||
#define EX_F_VSLIDE_UP 0x0a
|
||||
#define EX_F_VSLIDE_DN 0x0b
|
||||
#define EX_CUT 0x0c
|
||||
#define EX_DELAY 0x0d
|
||||
#define EX_PATT_DELAY 0x0e
|
||||
#define EX_INVLOOP 0x0f
|
||||
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
/* Oktalyzer effects */
|
||||
#define FX_OKT_ARP3 0x70
|
||||
#define FX_OKT_ARP4 0x71
|
||||
#define FX_OKT_ARP5 0x72
|
||||
#define FX_NSLIDE2_DN 0x73
|
||||
#define FX_NSLIDE2_UP 0x74
|
||||
#define FX_F_NSLIDE_DN 0x75
|
||||
#define FX_F_NSLIDE_UP 0x76
|
||||
|
||||
/* Persistent effects -- for FNK and FAR */
|
||||
#define FX_PER_PORTA_DN 0x78
|
||||
#define FX_PER_PORTA_UP 0x79
|
||||
#define FX_PER_TPORTA 0x7a
|
||||
#define FX_PER_VIBRATO 0x7b
|
||||
#define FX_PER_VSLD_UP 0x7c
|
||||
#define FX_PER_VSLD_DN 0x7d
|
||||
#define FX_SPEED_CP 0x7e
|
||||
#define FX_PER_CANCEL 0x7f
|
||||
|
||||
/* 669 frequency based effects */
|
||||
#define FX_669_PORTA_UP 0x60
|
||||
#define FX_669_PORTA_DN 0x61
|
||||
#define FX_669_TPORTA 0x62
|
||||
#define FX_669_FINETUNE 0x63
|
||||
#define FX_669_VIBRATO 0x64
|
||||
#endif
|
||||
|
||||
#ifndef LIBXMP_CORE_DISABLE_IT
|
||||
/* IT effects */
|
||||
#define FX_TRK_VOL 0x80
|
||||
#define FX_TRK_VSLIDE 0x81
|
||||
#define FX_TRK_FVSLIDE 0x82
|
||||
#define FX_IT_INSTFUNC 0x83
|
||||
#define FX_FLT_CUTOFF 0x84
|
||||
#define FX_FLT_RESN 0x85
|
||||
#define FX_IT_BPM 0x87
|
||||
#define FX_IT_ROWDELAY 0x88
|
||||
#define FX_IT_PANSLIDE 0x89
|
||||
#define FX_PANBRELLO 0x8a
|
||||
#define FX_PANBRELLO_WF 0x8b
|
||||
#define FX_HIOFFSET 0x8c
|
||||
#define FX_IT_BREAK 0x8e /* like FX_BREAK with hex parameter */
|
||||
#endif
|
||||
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
/* MED effects */
|
||||
#define FX_HOLD_DECAY 0x90
|
||||
#define FX_SETPITCH 0x91
|
||||
#define FX_VIBRATO2 0x92
|
||||
|
||||
/* PTM effects */
|
||||
#define FX_NSLIDE_DN 0x9c /* IMF/PTM note slide down */
|
||||
#define FX_NSLIDE_UP 0x9d /* IMF/PTM note slide up */
|
||||
#define FX_NSLIDE_R_UP 0x9e /* PTM note slide down with retrigger */
|
||||
#define FX_NSLIDE_R_DN 0x9f /* PTM note slide up with retrigger */
|
||||
|
||||
/* Extra effects */
|
||||
#define FX_VOLSLIDE_UP 0xa0 /* SFX, MDL */
|
||||
#define FX_VOLSLIDE_DN 0xa1
|
||||
#define FX_F_VSLIDE 0xa5 /* IMF/MDL */
|
||||
#define FX_CHORUS 0xa9 /* IMF */
|
||||
#define FX_ICE_SPEED 0xa2
|
||||
#define FX_REVERB 0xaa /* IMF */
|
||||
#define FX_MED_HOLD 0xb1 /* MMD hold/decay */
|
||||
#define FX_MEGAARP 0xb2 /* Smaksak effect 7: MegaArp */
|
||||
#define FX_VOL_ADD 0xb6 /* SFX change volume up */
|
||||
#define FX_VOL_SUB 0xb7 /* SFX change volume down */
|
||||
#define FX_PITCH_ADD 0xb8 /* SFX add steps to current note */
|
||||
#define FX_PITCH_SUB 0xb9 /* SFX add steps to current note */
|
||||
#endif
|
||||
|
||||
#define FX_SURROUND 0x8d /* S3M/IT */
|
||||
#define FX_S3M_SPEED 0xa3 /* S3M */
|
||||
#define FX_VOLSLIDE_2 0xa4
|
||||
#define FX_FINETUNE 0xa6
|
||||
#define FX_S3M_BPM 0xab /* S3M */
|
||||
#define FX_FINE_VIBRATO 0xac /* S3M/PTM/IMF/LIQ */
|
||||
#define FX_F_VSLIDE_UP 0xad /* MMD */
|
||||
#define FX_F_VSLIDE_DN 0xae /* MMD */
|
||||
#define FX_F_PORTA_UP 0xaf /* MMD */
|
||||
#define FX_F_PORTA_DN 0xb0 /* MMD */
|
||||
#define FX_PATT_DELAY 0xb3 /* MMD */
|
||||
#define FX_S3M_ARPEGGIO 0xb4
|
||||
#define FX_PANSL_NOMEM 0xb5 /* XM volume column */
|
||||
|
||||
#define FX_VSLIDE_UP_2 0xc0 /* IT volume column volume slide */
|
||||
#define FX_VSLIDE_DN_2 0xc1
|
||||
#define FX_F_VSLIDE_UP_2 0xc2
|
||||
#define FX_F_VSLIDE_DN_2 0xc3
|
||||
|
||||
#endif /* LIBXMP_EFFECTS_H */
|
107
internal/c/parts/audio/extras/libxmp-lite/filter.c
Normal file
107
internal/c/parts/audio/extras/libxmp-lite/filter.c
Normal file
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
* Based on the public domain version by Olivier Lapicque
|
||||
* Rewritten for libxmp by Claudio Matsuoka
|
||||
*
|
||||
* Copyright (C) 2012 Claudio Matsuoka
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef LIBXMP_CORE_DISABLE_IT
|
||||
#include <math.h>
|
||||
#include "xmp.h"
|
||||
#include "common.h"
|
||||
#include "mixer.h"
|
||||
|
||||
|
||||
/* LUT for 2 * damping factor */
|
||||
static const float resonance_table[128] = {
|
||||
1.0000000000000000f, 0.9786446094512940f, 0.9577452540397644f, 0.9372922182083130f,
|
||||
0.9172759056091309f, 0.8976871371269226f, 0.8785166740417481f, 0.8597555756568909f,
|
||||
0.8413951396942139f, 0.8234267830848694f, 0.8058421611785889f, 0.7886331081390381f,
|
||||
0.7717915177345276f, 0.7553095817565918f, 0.7391796708106995f, 0.7233941555023193f,
|
||||
0.7079457640647888f, 0.6928272843360901f, 0.6780316829681397f, 0.6635520458221436f,
|
||||
0.6493816375732422f, 0.6355138421058655f, 0.6219421625137329f, 0.6086603403091431f,
|
||||
0.5956621170043945f, 0.5829415321350098f, 0.5704925656318665f, 0.5583094954490662f,
|
||||
0.5463865399360657f, 0.5347182154655457f, 0.5232990980148315f, 0.5121238231658936f,
|
||||
0.5011872053146362f, 0.4904841780662537f, 0.4800096750259399f, 0.4697588682174683f,
|
||||
0.4597269892692566f, 0.4499093294143677f, 0.4403013288974762f, 0.4308985173702240f,
|
||||
0.4216965138912201f, 0.4126909971237183f, 0.4038778245449066f, 0.3952528536319733f,
|
||||
0.3868120610713959f, 0.3785515129566193f, 0.3704673945903778f, 0.3625559210777283f,
|
||||
0.3548133969306946f, 0.3472362160682678f, 0.3398208320140839f, 0.3325638175010681f,
|
||||
0.3254617750644684f, 0.3185114264488220f, 0.3117094635963440f, 0.3050527870655060f,
|
||||
0.2985382676124573f, 0.2921628654003143f, 0.2859236001968384f, 0.2798175811767578f,
|
||||
0.2738419771194458f, 0.2679939568042755f, 0.2622708380222321f, 0.2566699385643005f,
|
||||
0.2511886358261108f, 0.2458244115114212f, 0.2405747324228287f, 0.2354371547698975f,
|
||||
0.2304092943668366f, 0.2254888117313385f, 0.2206734120845795f, 0.2159608304500580f,
|
||||
0.2113489061594009f, 0.2068354636430740f, 0.2024184018373489f, 0.1980956792831421f,
|
||||
0.1938652694225311f, 0.1897251904010773f, 0.1856735348701477f, 0.1817083954811096f,
|
||||
0.1778279393911362f, 0.1740303486585617f, 0.1703138649463654f, 0.1666767448186874f,
|
||||
0.1631172895431519f, 0.1596338599920273f, 0.1562248021364212f, 0.1528885662555695f,
|
||||
0.1496235728263855f, 0.1464282870292664f, 0.1433012634515762f, 0.1402409970760346f,
|
||||
0.1372461020946503f, 0.1343151479959488f, 0.1314467936754227f, 0.1286396980285645f,
|
||||
0.1258925348520279f, 0.1232040524482727f, 0.1205729842185974f, 0.1179980933666229f,
|
||||
0.1154781952500343f, 0.1130121126770973f, 0.1105986908078194f, 0.1082368120551109f,
|
||||
0.1059253737330437f, 0.1036632955074310f, 0.1014495193958283f, 0.0992830246686935f,
|
||||
0.0971627980470657f, 0.0950878411531448f, 0.0930572077631950f, 0.0910699293017387f,
|
||||
0.0891250967979431f, 0.0872217938303947f, 0.0853591337800026f, 0.0835362523794174f,
|
||||
0.0817523002624512f, 0.0800064504146576f, 0.0782978758215904f, 0.0766257941722870f,
|
||||
0.0749894231557846f, 0.0733879879117012f, 0.0718207582831383f, 0.0702869966626167f,
|
||||
0.0687859877943993f, 0.0673170387744904f, 0.0658794566988945f, 0.0644725710153580f,
|
||||
};
|
||||
|
||||
|
||||
#if !defined(HAVE_POWF) || defined(__DJGPP__) || defined(__WATCOMC__)
|
||||
#define powf pow /* Watcom doesn't have powf. DJGPP have a C-only implementation in libm. */
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Simple 2-poles resonant filter
|
||||
*/
|
||||
#define FREQ_PARAM_MULT (128.0f / (24.0f * 256.0f))
|
||||
void libxmp_filter_setup(int srate, int cutoff, int res, int *a0, int *b0, int *b1)
|
||||
{
|
||||
float fc, fs = (float)srate;
|
||||
float fg, fb0, fb1;
|
||||
float r, d, e;
|
||||
|
||||
/* [0-255] => [100Hz-8000Hz] */
|
||||
CLAMP(cutoff, 0, 255);
|
||||
CLAMP(res, 0, 255);
|
||||
|
||||
fc = 110.0f * powf(2.0f, (float)cutoff * FREQ_PARAM_MULT + 0.25f);
|
||||
if (fc > fs / 2.0f) {
|
||||
fc = fs / 2.0f;
|
||||
}
|
||||
|
||||
r = fs / (2.0 * 3.14159265358979f * fc);
|
||||
d = resonance_table[res >> 1] * (r + 1.0) - 1.0;
|
||||
e = r * r;
|
||||
|
||||
fg = 1.0 / (1.0 + d + e);
|
||||
fb0 = (d + e + e) / (1.0 + d + e);
|
||||
fb1 = -e / (1.0 + d + e);
|
||||
|
||||
*a0 = (int)(fg * (1 << FILTER_SHIFT));
|
||||
*b0 = (int)(fb0 * (1 << FILTER_SHIFT));
|
||||
*b1 = (int)(fb1 * (1 << FILTER_SHIFT));
|
||||
}
|
||||
|
||||
#endif
|
55
internal/c/parts/audio/extras/libxmp-lite/format.c
Normal file
55
internal/c/parts/audio/extras/libxmp-lite/format.c
Normal file
|
@ -0,0 +1,55 @@
|
|||
/* Extended Module Player
|
||||
* Copyright (C) 1996-2021 Claudio Matsuoka and Hipolito Carraro Jr
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "format.h"
|
||||
|
||||
extern const struct format_loader libxmp_loader_xm;
|
||||
extern const struct format_loader libxmp_loader_mod;
|
||||
extern const struct format_loader libxmp_loader_it;
|
||||
extern const struct format_loader libxmp_loader_s3m;
|
||||
|
||||
const struct format_loader *const format_loaders[5] = {
|
||||
&libxmp_loader_xm,
|
||||
&libxmp_loader_mod,
|
||||
#ifndef LIBXMP_CORE_DISABLE_IT
|
||||
&libxmp_loader_it,
|
||||
#endif
|
||||
&libxmp_loader_s3m,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const char *_farray[5] = { NULL };
|
||||
|
||||
const char *const *format_list(void)
|
||||
{
|
||||
int count, i;
|
||||
|
||||
if (_farray[0] == NULL) {
|
||||
for (count = i = 0; format_loaders[i] != NULL; i++) {
|
||||
_farray[count++] = format_loaders[i]->name;
|
||||
}
|
||||
|
||||
_farray[count] = NULL;
|
||||
}
|
||||
|
||||
return _farray;
|
||||
}
|
26
internal/c/parts/audio/extras/libxmp-lite/format.h
Normal file
26
internal/c/parts/audio/extras/libxmp-lite/format.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
#ifndef LIBXMP_FORMAT_H
|
||||
#define LIBXMP_FORMAT_H
|
||||
|
||||
#include "common.h"
|
||||
#include "hio.h"
|
||||
|
||||
struct format_loader {
|
||||
const char *name;
|
||||
int (*const test)(HIO_HANDLE *, char *, const int);
|
||||
int (*const loader)(struct module_data *, HIO_HANDLE *, const int);
|
||||
};
|
||||
|
||||
const char *const *format_list(void);
|
||||
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
|
||||
#define NUM_FORMATS 53
|
||||
#define NUM_PW_FORMATS 43
|
||||
|
||||
#ifndef LIBXMP_NO_PROWIZARD
|
||||
int pw_test_format(HIO_HANDLE *, char *, const int, struct xmp_test_info *);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
479
internal/c/parts/audio/extras/libxmp-lite/hio.c
Normal file
479
internal/c/parts/audio/extras/libxmp-lite/hio.c
Normal file
|
@ -0,0 +1,479 @@
|
|||
/* Extended Module Player
|
||||
* Copyright (C) 1996-2021 Claudio Matsuoka and Hipolito Carraro Jr
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include "common.h"
|
||||
#include "hio.h"
|
||||
#include "callbackio.h"
|
||||
#include "mdataio.h"
|
||||
|
||||
static long get_size(FILE *f)
|
||||
{
|
||||
long size, pos;
|
||||
|
||||
pos = ftell(f);
|
||||
if (pos >= 0) {
|
||||
if (fseek(f, 0, SEEK_END) < 0) {
|
||||
return -1;
|
||||
}
|
||||
size = ftell(f);
|
||||
if (fseek(f, pos, SEEK_SET) < 0) {
|
||||
return -1;
|
||||
}
|
||||
return size;
|
||||
} else {
|
||||
return pos;
|
||||
}
|
||||
}
|
||||
|
||||
int8 hio_read8s(HIO_HANDLE *h)
|
||||
{
|
||||
int err;
|
||||
int8 ret;
|
||||
|
||||
switch (HIO_HANDLE_TYPE(h)) {
|
||||
case HIO_HANDLE_TYPE_FILE:
|
||||
ret = read8s(h->handle.file, &err);
|
||||
break;
|
||||
case HIO_HANDLE_TYPE_MEMORY:
|
||||
ret = mread8s(h->handle.mem, &err);
|
||||
break;
|
||||
case HIO_HANDLE_TYPE_CBFILE:
|
||||
ret = cbread8s(h->handle.cbfile, &err);
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (err != 0) {
|
||||
h->error = err;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint8 hio_read8(HIO_HANDLE *h)
|
||||
{
|
||||
int err;
|
||||
uint8 ret;
|
||||
|
||||
switch (HIO_HANDLE_TYPE(h)) {
|
||||
case HIO_HANDLE_TYPE_FILE:
|
||||
ret = read8(h->handle.file, &err);
|
||||
break;
|
||||
case HIO_HANDLE_TYPE_MEMORY:
|
||||
ret = mread8(h->handle.mem, &err);
|
||||
break;
|
||||
case HIO_HANDLE_TYPE_CBFILE:
|
||||
ret = cbread8(h->handle.cbfile, &err);
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (err != 0) {
|
||||
h->error = err;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint16 hio_read16l(HIO_HANDLE *h)
|
||||
{
|
||||
int err;
|
||||
uint16 ret;
|
||||
|
||||
switch (HIO_HANDLE_TYPE(h)) {
|
||||
case HIO_HANDLE_TYPE_FILE:
|
||||
ret = read16l(h->handle.file, &err);
|
||||
break;
|
||||
case HIO_HANDLE_TYPE_MEMORY:
|
||||
ret = mread16l(h->handle.mem, &err);
|
||||
break;
|
||||
case HIO_HANDLE_TYPE_CBFILE:
|
||||
ret = cbread16l(h->handle.cbfile, &err);
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (err != 0) {
|
||||
h->error = err;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint16 hio_read16b(HIO_HANDLE *h)
|
||||
{
|
||||
int err;
|
||||
uint16 ret;
|
||||
|
||||
switch (HIO_HANDLE_TYPE(h)) {
|
||||
case HIO_HANDLE_TYPE_FILE:
|
||||
ret = read16b(h->handle.file, &err);
|
||||
break;
|
||||
case HIO_HANDLE_TYPE_MEMORY:
|
||||
ret = mread16b(h->handle.mem, &err);
|
||||
break;
|
||||
case HIO_HANDLE_TYPE_CBFILE:
|
||||
ret = cbread16b(h->handle.cbfile, &err);
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (err != 0) {
|
||||
h->error = err;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32 hio_read24l(HIO_HANDLE *h)
|
||||
{
|
||||
int err;
|
||||
uint32 ret;
|
||||
|
||||
switch (HIO_HANDLE_TYPE(h)) {
|
||||
case HIO_HANDLE_TYPE_FILE:
|
||||
ret = read24l(h->handle.file, &err);
|
||||
break;
|
||||
case HIO_HANDLE_TYPE_MEMORY:
|
||||
ret = mread24l(h->handle.mem, &err);
|
||||
break;
|
||||
case HIO_HANDLE_TYPE_CBFILE:
|
||||
ret = cbread24l(h->handle.cbfile, &err);
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (err != 0) {
|
||||
h->error = err;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32 hio_read24b(HIO_HANDLE *h)
|
||||
{
|
||||
int err;
|
||||
uint32 ret;
|
||||
|
||||
switch (HIO_HANDLE_TYPE(h)) {
|
||||
case HIO_HANDLE_TYPE_FILE:
|
||||
ret = read24b(h->handle.file, &err);
|
||||
break;
|
||||
case HIO_HANDLE_TYPE_MEMORY:
|
||||
ret = mread24b(h->handle.mem, &err);
|
||||
break;
|
||||
case HIO_HANDLE_TYPE_CBFILE:
|
||||
ret = cbread24b(h->handle.cbfile, &err);
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (err != 0) {
|
||||
h->error = err;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32 hio_read32l(HIO_HANDLE *h)
|
||||
{
|
||||
int err;
|
||||
uint32 ret;
|
||||
|
||||
switch (HIO_HANDLE_TYPE(h)) {
|
||||
case HIO_HANDLE_TYPE_FILE:
|
||||
ret = read32l(h->handle.file, &err);
|
||||
break;
|
||||
case HIO_HANDLE_TYPE_MEMORY:
|
||||
ret = mread32l(h->handle.mem, &err);
|
||||
break;
|
||||
case HIO_HANDLE_TYPE_CBFILE:
|
||||
ret = cbread32l(h->handle.cbfile, &err);
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (err != 0) {
|
||||
h->error = err;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32 hio_read32b(HIO_HANDLE *h)
|
||||
{
|
||||
int err;
|
||||
uint32 ret;
|
||||
|
||||
switch (HIO_HANDLE_TYPE(h)) {
|
||||
case HIO_HANDLE_TYPE_FILE:
|
||||
ret = read32b(h->handle.file, &err);
|
||||
break;
|
||||
case HIO_HANDLE_TYPE_MEMORY:
|
||||
ret = mread32b(h->handle.mem, &err);
|
||||
break;
|
||||
case HIO_HANDLE_TYPE_CBFILE:
|
||||
ret = cbread32b(h->handle.cbfile, &err);
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (err != 0) {
|
||||
h->error = err;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
size_t hio_read(void *buf, size_t size, size_t num, HIO_HANDLE *h)
|
||||
{
|
||||
size_t ret = 0;
|
||||
|
||||
switch (HIO_HANDLE_TYPE(h)) {
|
||||
case HIO_HANDLE_TYPE_FILE:
|
||||
ret = fread(buf, size, num, h->handle.file);
|
||||
if (ret != num) {
|
||||
if (ferror(h->handle.file)) {
|
||||
h->error = errno;
|
||||
} else {
|
||||
h->error = feof(h->handle.file) ? EOF : -2;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case HIO_HANDLE_TYPE_MEMORY:
|
||||
ret = mread(buf, size, num, h->handle.mem);
|
||||
if (ret != num) {
|
||||
h->error = EOF;
|
||||
}
|
||||
break;
|
||||
case HIO_HANDLE_TYPE_CBFILE:
|
||||
ret = cbread(buf, size, num, h->handle.cbfile);
|
||||
if (ret != num) {
|
||||
h->error = EOF;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int hio_seek(HIO_HANDLE *h, long offset, int whence)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
switch (HIO_HANDLE_TYPE(h)) {
|
||||
case HIO_HANDLE_TYPE_FILE:
|
||||
ret = fseek(h->handle.file, offset, whence);
|
||||
if (ret < 0) {
|
||||
h->error = errno;
|
||||
}
|
||||
break;
|
||||
case HIO_HANDLE_TYPE_MEMORY:
|
||||
ret = mseek(h->handle.mem, offset, whence);
|
||||
if (ret < 0) {
|
||||
h->error = EINVAL;
|
||||
}
|
||||
break;
|
||||
case HIO_HANDLE_TYPE_CBFILE:
|
||||
ret = cbseek(h->handle.cbfile, offset, whence);
|
||||
if (ret < 0) {
|
||||
h->error = EINVAL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
long hio_tell(HIO_HANDLE *h)
|
||||
{
|
||||
long ret = -1;
|
||||
|
||||
switch (HIO_HANDLE_TYPE(h)) {
|
||||
case HIO_HANDLE_TYPE_FILE:
|
||||
ret = ftell(h->handle.file);
|
||||
if (ret < 0) {
|
||||
h->error = errno;
|
||||
}
|
||||
break;
|
||||
case HIO_HANDLE_TYPE_MEMORY:
|
||||
ret = mtell(h->handle.mem);
|
||||
if (ret < 0) {
|
||||
/* should _not_ happen! */
|
||||
h->error = EINVAL;
|
||||
}
|
||||
break;
|
||||
case HIO_HANDLE_TYPE_CBFILE:
|
||||
ret = cbtell(h->handle.cbfile);
|
||||
if (ret < 0) {
|
||||
h->error = EINVAL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int hio_eof(HIO_HANDLE *h)
|
||||
{
|
||||
switch (HIO_HANDLE_TYPE(h)) {
|
||||
case HIO_HANDLE_TYPE_FILE:
|
||||
return feof(h->handle.file);
|
||||
case HIO_HANDLE_TYPE_MEMORY:
|
||||
return meof(h->handle.mem);
|
||||
case HIO_HANDLE_TYPE_CBFILE:
|
||||
return cbeof(h->handle.cbfile);
|
||||
}
|
||||
return EOF;
|
||||
}
|
||||
|
||||
int hio_error(HIO_HANDLE *h)
|
||||
{
|
||||
int error = h->error;
|
||||
h->error = 0;
|
||||
return error;
|
||||
}
|
||||
|
||||
HIO_HANDLE *hio_open(const char *path, const char *mode)
|
||||
{
|
||||
HIO_HANDLE *h;
|
||||
|
||||
h = (HIO_HANDLE *)calloc(1, sizeof (HIO_HANDLE));
|
||||
if (h == NULL)
|
||||
goto err;
|
||||
|
||||
h->type = HIO_HANDLE_TYPE_FILE;
|
||||
h->handle.file = fopen(path, mode);
|
||||
if (h->handle.file == NULL)
|
||||
goto err2;
|
||||
|
||||
h->size = get_size(h->handle.file);
|
||||
if (h->size < 0)
|
||||
goto err3;
|
||||
|
||||
return h;
|
||||
|
||||
err3:
|
||||
fclose(h->handle.file);
|
||||
err2:
|
||||
free(h);
|
||||
err:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
HIO_HANDLE *hio_open_mem(const void *ptr, long size)
|
||||
{
|
||||
HIO_HANDLE *h;
|
||||
|
||||
if (size <= 0) return NULL;
|
||||
h = (HIO_HANDLE *)calloc(1, sizeof (HIO_HANDLE));
|
||||
if (h == NULL)
|
||||
return NULL;
|
||||
|
||||
h->type = HIO_HANDLE_TYPE_MEMORY;
|
||||
h->handle.mem = mopen(ptr, size);
|
||||
h->size = size;
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
HIO_HANDLE *hio_open_file(FILE *f)
|
||||
{
|
||||
HIO_HANDLE *h;
|
||||
|
||||
h = (HIO_HANDLE *)calloc(1, sizeof (HIO_HANDLE));
|
||||
if (h == NULL)
|
||||
return NULL;
|
||||
|
||||
h->noclose = 1;
|
||||
h->type = HIO_HANDLE_TYPE_FILE;
|
||||
h->handle.file = f;
|
||||
h->size = get_size(f);
|
||||
if (h->size < 0) {
|
||||
free(h);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
HIO_HANDLE *hio_open_file2(FILE *f)
|
||||
{
|
||||
HIO_HANDLE *h = hio_open_file(f);
|
||||
if (h != NULL) {
|
||||
h->noclose = 0;
|
||||
}
|
||||
else {
|
||||
fclose(f);
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
HIO_HANDLE *hio_open_callbacks(void *priv, struct xmp_callbacks callbacks)
|
||||
{
|
||||
HIO_HANDLE *h;
|
||||
CBFILE *f = cbopen(priv, callbacks);
|
||||
if (!f)
|
||||
return NULL;
|
||||
|
||||
h = (HIO_HANDLE *)calloc(1, sizeof(HIO_HANDLE));
|
||||
if (h == NULL) {
|
||||
cbclose(f);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
h->type = HIO_HANDLE_TYPE_CBFILE;
|
||||
h->handle.cbfile = f;
|
||||
h->size = cbfilelength(f);
|
||||
if (h->size < 0) {
|
||||
cbclose(f);
|
||||
free(h);
|
||||
return NULL;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
int hio_close(HIO_HANDLE *h)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
switch (HIO_HANDLE_TYPE(h)) {
|
||||
case HIO_HANDLE_TYPE_FILE:
|
||||
ret = (h->noclose)? 0 : fclose(h->handle.file);
|
||||
break;
|
||||
case HIO_HANDLE_TYPE_MEMORY:
|
||||
ret = mclose(h->handle.mem);
|
||||
break;
|
||||
case HIO_HANDLE_TYPE_CBFILE:
|
||||
ret = cbclose(h->handle.cbfile);
|
||||
break;
|
||||
}
|
||||
|
||||
free(h);
|
||||
return ret;
|
||||
}
|
||||
|
||||
long hio_size(HIO_HANDLE *h)
|
||||
{
|
||||
return h->size;
|
||||
}
|
48
internal/c/parts/audio/extras/libxmp-lite/hio.h
Normal file
48
internal/c/parts/audio/extras/libxmp-lite/hio.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
#ifndef XMP_HIO_H
|
||||
#define XMP_HIO_H
|
||||
|
||||
#include "callbackio.h"
|
||||
#include "memio.h"
|
||||
|
||||
#define HIO_HANDLE_TYPE(x) ((x)->type)
|
||||
|
||||
enum hio_type {
|
||||
HIO_HANDLE_TYPE_FILE,
|
||||
HIO_HANDLE_TYPE_MEMORY,
|
||||
HIO_HANDLE_TYPE_CBFILE
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
enum hio_type type;
|
||||
long size;
|
||||
union {
|
||||
FILE *file;
|
||||
MFILE *mem;
|
||||
CBFILE *cbfile;
|
||||
} handle;
|
||||
int error;
|
||||
int noclose;
|
||||
} HIO_HANDLE;
|
||||
|
||||
int8 hio_read8s (HIO_HANDLE *);
|
||||
uint8 hio_read8 (HIO_HANDLE *);
|
||||
uint16 hio_read16l (HIO_HANDLE *);
|
||||
uint16 hio_read16b (HIO_HANDLE *);
|
||||
uint32 hio_read24l (HIO_HANDLE *);
|
||||
uint32 hio_read24b (HIO_HANDLE *);
|
||||
uint32 hio_read32l (HIO_HANDLE *);
|
||||
uint32 hio_read32b (HIO_HANDLE *);
|
||||
size_t hio_read (void *, size_t, size_t, HIO_HANDLE *);
|
||||
int hio_seek (HIO_HANDLE *, long, int);
|
||||
long hio_tell (HIO_HANDLE *);
|
||||
int hio_eof (HIO_HANDLE *);
|
||||
int hio_error (HIO_HANDLE *);
|
||||
HIO_HANDLE *hio_open (const char *, const char *);
|
||||
HIO_HANDLE *hio_open_mem (const void *, long);
|
||||
HIO_HANDLE *hio_open_file (FILE *);
|
||||
HIO_HANDLE *hio_open_file2 (FILE *);/* allows fclose()ing the file by libxmp */
|
||||
HIO_HANDLE *hio_open_callbacks (void *, struct xmp_callbacks);
|
||||
int hio_close (HIO_HANDLE *);
|
||||
long hio_size (HIO_HANDLE *);
|
||||
|
||||
#endif
|
181
internal/c/parts/audio/extras/libxmp-lite/it.h
Normal file
181
internal/c/parts/audio/extras/libxmp-lite/it.h
Normal file
|
@ -0,0 +1,181 @@
|
|||
/* Extended Module Player
|
||||
* Copyright (C) 1996-2021 Claudio Matsuoka and Hipolito Carraro Jr
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/* IT flags */
|
||||
#define IT_STEREO 0x01
|
||||
#define IT_VOL_OPT 0x02 /* Not recognized */
|
||||
#define IT_USE_INST 0x04
|
||||
#define IT_LINEAR_FREQ 0x08
|
||||
#define IT_OLD_FX 0x10
|
||||
#define IT_LINK_GXX 0x20
|
||||
|
||||
/* IT special */
|
||||
#define IT_HAS_MSG 0x01
|
||||
|
||||
/* IT instrument flags */
|
||||
#define IT_INST_SAMPLE 0x01
|
||||
#define IT_INST_16BIT 0x02
|
||||
#define IT_INST_STEREO 0x04
|
||||
#define IT_INST_LOOP 0x10
|
||||
#define IT_INST_SLOOP 0x20
|
||||
#define IT_INST_BLOOP 0x40
|
||||
#define IT_INST_BSLOOP 0x80
|
||||
|
||||
/* IT sample flags */
|
||||
#define IT_SMP_SAMPLE 0x01
|
||||
#define IT_SMP_16BIT 0x02
|
||||
#define IT_SMP_STEREO 0x04 /* unsupported */
|
||||
#define IT_SMP_COMP 0x08 /* unsupported */
|
||||
#define IT_SMP_LOOP 0x10
|
||||
#define IT_SMP_SLOOP 0x20
|
||||
#define IT_SMP_BLOOP 0x40
|
||||
#define IT_SMP_BSLOOP 0x80
|
||||
|
||||
/* IT sample conversion flags */
|
||||
#define IT_CVT_SIGNED 0x01
|
||||
#define IT_CVT_BIGEND 0x02 /* 'safe to ignore' according to ittech.txt */
|
||||
#define IT_CVT_DIFF 0x04 /* Compressed sample flag */
|
||||
#define IT_CVT_BYTEDIFF 0x08 /* 'safe to ignore' according to ittech.txt */
|
||||
#define IT_CVT_12BIT 0x10 /* 'safe to ignore' according to ittech.txt */
|
||||
|
||||
/* IT envelope flags */
|
||||
#define IT_ENV_ON 0x01
|
||||
#define IT_ENV_LOOP 0x02
|
||||
#define IT_ENV_SLOOP 0x04
|
||||
#define IT_ENV_CARRY 0x08
|
||||
#define IT_ENV_FILTER 0x80
|
||||
|
||||
|
||||
struct it_file_header {
|
||||
uint32 magic; /* 'IMPM' */
|
||||
uint8 name[26]; /* ASCIIZ Song name */
|
||||
uint8 hilite_min; /* Pattern editor highlight */
|
||||
uint8 hilite_maj; /* Pattern editor highlight */
|
||||
uint16 ordnum; /* Number of orders (must be even) */
|
||||
uint16 insnum; /* Number of instruments */
|
||||
uint16 smpnum; /* Number of samples */
|
||||
uint16 patnum; /* Number of patterns */
|
||||
uint16 cwt; /* Tracker ID and version */
|
||||
uint16 cmwt; /* Format version */
|
||||
uint16 flags; /* Flags */
|
||||
uint16 special; /* More flags */
|
||||
uint8 gv; /* Global volume */
|
||||
uint8 mv; /* Master volume */
|
||||
uint8 is; /* Initial speed */
|
||||
uint8 it; /* Initial tempo */
|
||||
uint8 sep; /* Panning separation */
|
||||
uint8 pwd; /* Pitch wheel depth */
|
||||
uint16 msglen; /* Message length */
|
||||
uint32 msgofs; /* Message offset */
|
||||
uint32 rsvd; /* Reserved */
|
||||
uint8 chpan[64]; /* Channel pan settings */
|
||||
uint8 chvol[64]; /* Channel volume settings */
|
||||
};
|
||||
|
||||
struct it_instrument1_header {
|
||||
uint32 magic; /* 'IMPI' */
|
||||
uint8 dosname[12]; /* DOS filename */
|
||||
uint8 zero; /* Always zero */
|
||||
uint8 flags; /* Instrument flags */
|
||||
uint8 vls; /* Volume loop start */
|
||||
uint8 vle; /* Volume loop end */
|
||||
uint8 sls; /* Sustain loop start */
|
||||
uint8 sle; /* Sustain loop end */
|
||||
uint16 rsvd1; /* Reserved */
|
||||
uint16 fadeout; /* Fadeout (release) */
|
||||
uint8 nna; /* New note action */
|
||||
uint8 dnc; /* Duplicate note check */
|
||||
uint16 trkvers; /* Tracker version */
|
||||
uint8 nos; /* Number of samples */
|
||||
uint8 rsvd2; /* Reserved */
|
||||
uint8 name[26]; /* ASCIIZ Instrument name */
|
||||
uint8 rsvd3[6]; /* Reserved */
|
||||
uint8 keys[240];
|
||||
uint8 epoint[200];
|
||||
uint8 enode[50];
|
||||
};
|
||||
|
||||
struct it_instrument2_header {
|
||||
uint32 magic; /* 'IMPI' */
|
||||
uint8 dosname[12]; /* DOS filename */
|
||||
uint8 zero; /* Always zero */
|
||||
uint8 nna; /* New Note Action */
|
||||
uint8 dct; /* Duplicate Check Type */
|
||||
uint8 dca; /* Duplicate Check Action */
|
||||
uint16 fadeout;
|
||||
uint8 pps; /* Pitch-Pan Separation */
|
||||
uint8 ppc; /* Pitch-Pan Center */
|
||||
uint8 gbv; /* Global Volume */
|
||||
uint8 dfp; /* Default pan */
|
||||
uint8 rv; /* Random volume variation */
|
||||
uint8 rp; /* Random pan variation */
|
||||
uint16 trkvers; /* Not used: tracked version */
|
||||
uint8 nos; /* Not used: number of samples */
|
||||
uint8 rsvd1; /* Reserved */
|
||||
uint8 name[26]; /* ASCIIZ Instrument name */
|
||||
uint8 ifc; /* Initial filter cutoff */
|
||||
uint8 ifr; /* Initial filter resonance */
|
||||
uint8 mch; /* MIDI channel */
|
||||
uint8 mpr; /* MIDI program */
|
||||
uint16 mbnk; /* MIDI bank */
|
||||
uint8 keys[240];
|
||||
};
|
||||
|
||||
struct it_envelope_node {
|
||||
int8 y;
|
||||
uint16 x;
|
||||
};
|
||||
|
||||
struct it_envelope {
|
||||
uint8 flg; /* Flags */
|
||||
uint8 num; /* Number of node points */
|
||||
uint8 lpb; /* Loop beginning */
|
||||
uint8 lpe; /* Loop end */
|
||||
uint8 slb; /* Sustain loop beginning */
|
||||
uint8 sle; /* Sustain loop end */
|
||||
struct it_envelope_node node[25];
|
||||
uint8 unused;
|
||||
};
|
||||
|
||||
struct it_sample_header {
|
||||
uint32 magic; /* 'IMPS' */
|
||||
uint8 dosname[12]; /* DOS filename */
|
||||
uint8 zero; /* Always zero */
|
||||
uint8 gvl; /* Global volume for instrument */
|
||||
uint8 flags; /* Sample flags */
|
||||
uint8 vol; /* Volume */
|
||||
uint8 name[26]; /* ASCIIZ sample name */
|
||||
uint8 convert; /* Sample flags */
|
||||
uint8 dfp; /* Default pan */
|
||||
uint32 length; /* Length */
|
||||
uint32 loopbeg; /* Loop begin */
|
||||
uint32 loopend; /* Loop end */
|
||||
uint32 c5spd; /* C 5 speed */
|
||||
uint32 sloopbeg; /* SusLoop begin */
|
||||
uint32 sloopend; /* SusLoop end */
|
||||
uint32 sample_ptr; /* Sample pointer */
|
||||
uint8 vis; /* Vibrato speed */
|
||||
uint8 vid; /* Vibrato depth */
|
||||
uint8 vir; /* Vibrato rate */
|
||||
uint8 vit; /* Vibrato waveform */
|
||||
};
|
||||
|
1418
internal/c/parts/audio/extras/libxmp-lite/it_load.c
Normal file
1418
internal/c/parts/audio/extras/libxmp-lite/it_load.c
Normal file
File diff suppressed because it is too large
Load diff
232
internal/c/parts/audio/extras/libxmp-lite/itsex.c
Normal file
232
internal/c/parts/audio/extras/libxmp-lite/itsex.c
Normal file
|
@ -0,0 +1,232 @@
|
|||
#ifndef LIBXMP_CORE_DISABLE_IT
|
||||
|
||||
/* Public domain IT sample decompressor by Olivier Lapicque */
|
||||
|
||||
#include "loader.h"
|
||||
|
||||
static inline uint32 read_bits(HIO_HANDLE *ibuf, uint32 *bitbuf, int *bitnum, int n)
|
||||
{
|
||||
uint32 retval = 0;
|
||||
int i = n;
|
||||
int bnum = *bitnum, bbuf = *bitbuf;
|
||||
|
||||
if (n > 0) {
|
||||
do {
|
||||
if (bnum == 0) {
|
||||
bbuf = hio_read8(ibuf);
|
||||
bnum = 8;
|
||||
}
|
||||
retval >>= 1;
|
||||
retval |= bbuf << 31;
|
||||
bbuf >>= 1;
|
||||
bnum--;
|
||||
i--;
|
||||
} while (i != 0);
|
||||
|
||||
i = n;
|
||||
|
||||
*bitnum = bnum;
|
||||
*bitbuf = bbuf;
|
||||
}
|
||||
|
||||
return (retval >> (32 - i));
|
||||
}
|
||||
|
||||
|
||||
int itsex_decompress8(HIO_HANDLE *src, uint8 *dst, int len, int it215)
|
||||
{
|
||||
/* uint32 size = 0; */
|
||||
uint32 block_count = 0;
|
||||
uint32 bitbuf = 0;
|
||||
int bitnum = 0;
|
||||
uint8 left = 0, temp = 0, temp2 = 0;
|
||||
uint32 d, pos;
|
||||
|
||||
while (len) {
|
||||
if (!block_count) {
|
||||
block_count = 0x8000;
|
||||
/*size =*/ hio_read16l(src);
|
||||
left = 9;
|
||||
temp = temp2 = 0;
|
||||
bitbuf = bitnum = 0;
|
||||
}
|
||||
|
||||
d = block_count;
|
||||
if (d > len)
|
||||
d = len;
|
||||
|
||||
/* Unpacking */
|
||||
pos = 0;
|
||||
do {
|
||||
uint16 bits = read_bits(src, &bitbuf, &bitnum, left);
|
||||
if (hio_eof(src))
|
||||
return -1;
|
||||
|
||||
if (left < 7) {
|
||||
uint32 i = 1 << (left - 1);
|
||||
uint32 j = bits & 0xffff;
|
||||
if (i != j)
|
||||
goto unpack_byte;
|
||||
bits = (read_bits(src, &bitbuf, &bitnum, 3)
|
||||
+ 1) & 0xff;
|
||||
if (hio_eof(src))
|
||||
return -1;
|
||||
|
||||
left = ((uint8)bits < left) ? (uint8)bits :
|
||||
(uint8)((bits + 1) & 0xff);
|
||||
goto next;
|
||||
}
|
||||
|
||||
if (left < 9) {
|
||||
uint16 i = (0xff >> (9 - left)) + 4;
|
||||
uint16 j = i - 8;
|
||||
|
||||
if ((bits <= j) || (bits > i))
|
||||
goto unpack_byte;
|
||||
|
||||
bits -= j;
|
||||
left = ((uint8)(bits & 0xff) < left) ?
|
||||
(uint8)(bits & 0xff) :
|
||||
(uint8)((bits + 1) & 0xff);
|
||||
goto next;
|
||||
}
|
||||
|
||||
if (left >= 10)
|
||||
goto skip_byte;
|
||||
|
||||
if (bits >= 256) {
|
||||
left = (uint8) (bits + 1) & 0xff;
|
||||
goto next;
|
||||
}
|
||||
|
||||
unpack_byte:
|
||||
if (left < 8) {
|
||||
uint8 shift = 8 - left;
|
||||
signed char c = (signed char)(bits << shift);
|
||||
c >>= shift;
|
||||
bits = (uint16) c;
|
||||
}
|
||||
bits += temp;
|
||||
temp = (uint8)bits;
|
||||
temp2 += temp;
|
||||
dst[pos] = it215 ? temp2 : temp;
|
||||
|
||||
skip_byte:
|
||||
pos++;
|
||||
|
||||
next:
|
||||
/* if (slen <= 0)
|
||||
return -1 */;
|
||||
} while (pos < d);
|
||||
|
||||
/* Move On */
|
||||
block_count -= d;
|
||||
len -= d;
|
||||
dst += d;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int itsex_decompress16(HIO_HANDLE *src, int16 *dst, int len, int it215)
|
||||
{
|
||||
/* uint32 size = 0; */
|
||||
uint32 block_count = 0;
|
||||
uint32 bitbuf = 0;
|
||||
int bitnum = 0;
|
||||
uint8 left = 0;
|
||||
int16 temp = 0, temp2 = 0;
|
||||
uint32 d, pos;
|
||||
|
||||
while (len) {
|
||||
if (!block_count) {
|
||||
block_count = 0x4000;
|
||||
/*size =*/ hio_read16l(src);
|
||||
left = 17;
|
||||
temp = temp2 = 0;
|
||||
bitbuf = bitnum = 0;
|
||||
}
|
||||
|
||||
d = block_count;
|
||||
if (d > len)
|
||||
d = len;
|
||||
|
||||
/* Unpacking */
|
||||
pos = 0;
|
||||
do {
|
||||
uint32 bits = read_bits(src, &bitbuf, &bitnum, left);
|
||||
if (hio_eof(src))
|
||||
return -1;
|
||||
|
||||
if (left < 7) {
|
||||
uint32 i = 1 << (left - 1);
|
||||
uint32 j = bits;
|
||||
|
||||
if (i != j)
|
||||
goto unpack_byte;
|
||||
|
||||
bits = read_bits(src, &bitbuf, &bitnum, 4) + 1;
|
||||
|
||||
if (hio_eof(src))
|
||||
return -1;
|
||||
|
||||
left = ((uint8)(bits & 0xff) < left) ?
|
||||
(uint8)(bits & 0xff) :
|
||||
(uint8)((bits + 1) & 0xff);
|
||||
goto next;
|
||||
}
|
||||
|
||||
if (left < 17) {
|
||||
uint32 i = (0xffff >> (17 - left)) + 8;
|
||||
uint32 j = (i - 16) & 0xffff;
|
||||
|
||||
if ((bits <= j) || (bits > (i & 0xffff)))
|
||||
goto unpack_byte;
|
||||
|
||||
bits -= j;
|
||||
left = ((uint8)(bits & 0xff) < left) ?
|
||||
(uint8)(bits & 0xff) :
|
||||
(uint8)((bits + 1) & 0xff);
|
||||
goto next;
|
||||
}
|
||||
|
||||
if (left >= 18)
|
||||
goto skip_byte;
|
||||
|
||||
if (bits >= 0x10000) {
|
||||
left = (uint8)(bits + 1) & 0xff;
|
||||
goto next;
|
||||
}
|
||||
|
||||
unpack_byte:
|
||||
if (left < 16) {
|
||||
uint8 shift = 16 - left;
|
||||
int16 c = (int16)(bits << shift);
|
||||
c >>= shift;
|
||||
bits = (uint32) c;
|
||||
}
|
||||
bits += temp;
|
||||
temp = (int16)bits;
|
||||
temp2 += temp;
|
||||
dst[pos] = (it215) ? temp2 : temp;
|
||||
|
||||
skip_byte:
|
||||
pos++;
|
||||
|
||||
next:
|
||||
/* if (slen <= 0)
|
||||
return -1 */;
|
||||
} while (pos < d);
|
||||
|
||||
/* Move On */
|
||||
block_count -= d;
|
||||
len -= d;
|
||||
dst += d;
|
||||
if (len <= 0)
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* LIBXMP_CORE_DISABLE_IT */
|
163
internal/c/parts/audio/extras/libxmp-lite/lfo.c
Normal file
163
internal/c/parts/audio/extras/libxmp-lite/lfo.c
Normal file
|
@ -0,0 +1,163 @@
|
|||
/* Extended Module Player
|
||||
* Copyright (C) 1996-2021 Claudio Matsuoka and Hipolito Carraro Jr
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "lfo.h"
|
||||
|
||||
#define WAVEFORM_SIZE 64
|
||||
|
||||
static const int sine_wave[WAVEFORM_SIZE] = {
|
||||
0, 24, 49, 74, 97, 120, 141, 161, 180, 197, 212, 224,
|
||||
235, 244, 250, 253, 255, 253, 250, 244, 235, 224, 212, 197,
|
||||
180, 161, 141, 120, 97, 74, 49, 24, 0, -24, -49, -74,
|
||||
-97,-120,-141,-161,-180,-197,-212,-224,-235,-244,-250,-253,
|
||||
-255,-253,-250,-244,-235,-224,-212,-197,-180,-161,-141,-120,
|
||||
-97, -74, -49, -24
|
||||
};
|
||||
|
||||
/* LFO */
|
||||
|
||||
static int get_lfo_mod(struct lfo *lfo)
|
||||
{
|
||||
int val;
|
||||
|
||||
if (lfo->rate == 0)
|
||||
return 0;
|
||||
|
||||
switch (lfo->type) {
|
||||
case 0: /* sine */
|
||||
val = sine_wave[lfo->phase];
|
||||
break;
|
||||
case 1: /* ramp down */
|
||||
val = 255 - (lfo->phase << 3);
|
||||
break;
|
||||
case 2: /* square */
|
||||
val = lfo->phase < WAVEFORM_SIZE / 2 ? 255 : -255;
|
||||
break;
|
||||
case 3: /* random */
|
||||
val = ((rand() & 0x1ff) - 256);
|
||||
break;
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
case 669: /* 669 vibrato */
|
||||
val = lfo->phase & 1;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return val * lfo->depth;
|
||||
}
|
||||
|
||||
static int get_lfo_st3(struct lfo *lfo)
|
||||
{
|
||||
if (lfo->rate == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* S3M square */
|
||||
if (lfo->type == 2) {
|
||||
int val = lfo->phase < WAVEFORM_SIZE / 2 ? 255 : 0;
|
||||
return val * lfo->depth;
|
||||
}
|
||||
|
||||
return get_lfo_mod(lfo);
|
||||
}
|
||||
|
||||
/* From OpenMPT VibratoWaveforms.xm:
|
||||
* "Generally the vibrato and tremolo tables are identical to those that
|
||||
* ProTracker uses, but the vibrato’s “ramp down” table is upside down."
|
||||
*/
|
||||
static int get_lfo_ft2(struct lfo *lfo)
|
||||
{
|
||||
if (lfo->rate == 0)
|
||||
return 0;
|
||||
|
||||
/* FT2 ramp */
|
||||
if (lfo->type == 1) {
|
||||
int phase = (lfo->phase + (WAVEFORM_SIZE >> 1)) % WAVEFORM_SIZE;
|
||||
int val = (phase << 3) - 255;
|
||||
return val * lfo->depth;
|
||||
}
|
||||
|
||||
return get_lfo_mod(lfo);
|
||||
}
|
||||
|
||||
#ifndef LIBXMP_CORE_DISABLE_IT
|
||||
|
||||
static int get_lfo_it(struct lfo *lfo)
|
||||
{
|
||||
if (lfo->rate == 0)
|
||||
return 0;
|
||||
|
||||
return get_lfo_st3(lfo);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int libxmp_lfo_get(struct context_data *ctx, struct lfo *lfo, int is_vibrato)
|
||||
{
|
||||
struct module_data *m = &ctx->m;
|
||||
|
||||
switch (m->read_event_type) {
|
||||
case READ_EVENT_ST3:
|
||||
return get_lfo_st3(lfo);
|
||||
case READ_EVENT_FT2:
|
||||
if (is_vibrato) {
|
||||
return get_lfo_ft2(lfo);
|
||||
} else {
|
||||
return get_lfo_mod(lfo);
|
||||
}
|
||||
#ifndef LIBXMP_CORE_DISABLE_IT
|
||||
case READ_EVENT_IT:
|
||||
return get_lfo_it(lfo);
|
||||
#endif
|
||||
default:
|
||||
return get_lfo_mod(lfo);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void libxmp_lfo_update(struct lfo *lfo)
|
||||
{
|
||||
lfo->phase += lfo->rate;
|
||||
lfo->phase %= WAVEFORM_SIZE;
|
||||
}
|
||||
|
||||
void libxmp_lfo_set_phase(struct lfo *lfo, int phase)
|
||||
{
|
||||
lfo->phase = phase;
|
||||
}
|
||||
|
||||
void libxmp_lfo_set_depth(struct lfo *lfo, int depth)
|
||||
{
|
||||
lfo->depth = depth;
|
||||
}
|
||||
|
||||
void libxmp_lfo_set_rate(struct lfo *lfo, int rate)
|
||||
{
|
||||
lfo->rate = rate;
|
||||
}
|
||||
|
||||
void libxmp_lfo_set_waveform(struct lfo *lfo, int type)
|
||||
{
|
||||
lfo->type = type;
|
||||
}
|
20
internal/c/parts/audio/extras/libxmp-lite/lfo.h
Normal file
20
internal/c/parts/audio/extras/libxmp-lite/lfo.h
Normal file
|
@ -0,0 +1,20 @@
|
|||
#ifndef LIBXMP_LFO_H
|
||||
#define LIBXMP_LFO_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
struct lfo {
|
||||
int type;
|
||||
int rate;
|
||||
int depth;
|
||||
int phase;
|
||||
};
|
||||
|
||||
int libxmp_lfo_get(struct context_data *, struct lfo *, int);
|
||||
void libxmp_lfo_update(struct lfo *);
|
||||
void libxmp_lfo_set_phase(struct lfo *, int);
|
||||
void libxmp_lfo_set_depth(struct lfo *, int);
|
||||
void libxmp_lfo_set_rate(struct lfo *, int);
|
||||
void libxmp_lfo_set_waveform(struct lfo *, int);
|
||||
|
||||
#endif
|
146
internal/c/parts/audio/extras/libxmp-lite/list.h
Normal file
146
internal/c/parts/audio/extras/libxmp-lite/list.h
Normal file
|
@ -0,0 +1,146 @@
|
|||
#ifndef LIBXMP_LIST_H
|
||||
#define LIBXMP_LIST_H
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define __inline__ __inline
|
||||
#endif
|
||||
#ifdef __WATCOMC__
|
||||
#define __inline__ inline
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Simple doubly linked list implementation.
|
||||
*
|
||||
* Some of the internal functions ("__xxx") are useful when
|
||||
* manipulating whole lists rather than single entries, as
|
||||
* sometimes we already know the next/prev entries and we can
|
||||
* generate better code by using them directly rather than
|
||||
* using the generic single-entry routines.
|
||||
*/
|
||||
|
||||
struct list_head {
|
||||
struct list_head *next, *prev;
|
||||
};
|
||||
|
||||
#define LIST_HEAD_INIT(name) { &(name), &(name) }
|
||||
|
||||
#define LIST_HEAD(name) \
|
||||
struct list_head name = LIST_HEAD_INIT(name)
|
||||
|
||||
#define INIT_LIST_HEAD(ptr) do { \
|
||||
(ptr)->next = (ptr); (ptr)->prev = (ptr); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Insert a new entry between two known consecutive entries.
|
||||
*
|
||||
* This is only for internal list manipulation where we know
|
||||
* the prev/next entries already!
|
||||
*/
|
||||
static __inline__ void __list_add(struct list_head *_new,
|
||||
struct list_head * prev,
|
||||
struct list_head * next)
|
||||
{
|
||||
next->prev = _new;
|
||||
_new->next = next;
|
||||
_new->prev = prev;
|
||||
prev->next = _new;
|
||||
}
|
||||
|
||||
/**
|
||||
* list_add - add a new entry
|
||||
* @_new: new entry to be added
|
||||
* @head: list head to add it after
|
||||
*
|
||||
* Insert a new entry after the specified head.
|
||||
* This is good for implementing stacks.
|
||||
*/
|
||||
static __inline__ void list_add(struct list_head *_new, struct list_head *head)
|
||||
{
|
||||
__list_add(_new, head, head->next);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_add_tail - add a new entry
|
||||
* @_new: new entry to be added
|
||||
* @head: list head to add it before
|
||||
*
|
||||
* Insert a new entry before the specified head.
|
||||
* This is useful for implementing queues.
|
||||
*/
|
||||
static __inline__ void list_add_tail(struct list_head *_new, struct list_head *head)
|
||||
{
|
||||
__list_add(_new, head->prev, head);
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete a list entry by making the prev/next entries
|
||||
* point to each other.
|
||||
*
|
||||
* This is only for internal list manipulation where we know
|
||||
* the prev/next entries already!
|
||||
*/
|
||||
static __inline__ void __list_del(struct list_head * prev,
|
||||
struct list_head * next)
|
||||
{
|
||||
next->prev = prev;
|
||||
prev->next = next;
|
||||
}
|
||||
|
||||
/**
|
||||
* list_del - deletes entry from list.
|
||||
* @entry: the element to delete from the list.
|
||||
*/
|
||||
static __inline__ void list_del(struct list_head *entry)
|
||||
{
|
||||
__list_del(entry->prev, entry->next);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_empty - tests whether a list is empty
|
||||
* @head: the list to test.
|
||||
*/
|
||||
static __inline__ int list_empty(struct list_head *head)
|
||||
{
|
||||
return head->next == head;
|
||||
}
|
||||
|
||||
/**
|
||||
* list_splice - join two lists
|
||||
* @list: the new list to add.
|
||||
* @head: the place to add it in the first list.
|
||||
*/
|
||||
static __inline__ void list_splice(struct list_head *list, struct list_head *head)
|
||||
{
|
||||
struct list_head *first = list->next;
|
||||
|
||||
if (first != list) {
|
||||
struct list_head *last = list->prev;
|
||||
struct list_head *at = head->next;
|
||||
|
||||
first->prev = head;
|
||||
head->next = first;
|
||||
|
||||
last->next = at;
|
||||
at->prev = last;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* list_entry - get the struct for this entry
|
||||
* @ptr: the &struct list_head pointer.
|
||||
* @type: the type of the struct this is embedded in.
|
||||
* @member: the name of the list_struct within the struct.
|
||||
*/
|
||||
#define list_entry(ptr, type, member) \
|
||||
((type *)((char *)(ptr)-(size_t)(&((type *)0)->member)))
|
||||
|
||||
/**
|
||||
* list_for_each - iterate over a list
|
||||
* @pos: the &struct list_head to use as a loop counter.
|
||||
* @head: the head for your list.
|
||||
*/
|
||||
#define list_for_each(pos, head) \
|
||||
for (pos = (head)->next; pos != (head); pos = pos->next)
|
||||
|
||||
#endif
|
614
internal/c/parts/audio/extras/libxmp-lite/load.c
Normal file
614
internal/c/parts/audio/extras/libxmp-lite/load.c
Normal file
|
@ -0,0 +1,614 @@
|
|||
/* Extended Module Player
|
||||
* Copyright (C) 1996-2021 Claudio Matsuoka and Hipolito Carraro Jr
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "format.h"
|
||||
#include "list.h"
|
||||
#include "hio.h"
|
||||
#include "tempfile.h"
|
||||
#include "loader.h"
|
||||
|
||||
#ifndef LIBXMP_NO_DEPACKERS
|
||||
#include "depackers/depacker.h"
|
||||
#endif
|
||||
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
#include "md5.h"
|
||||
#include "extras.h"
|
||||
#endif
|
||||
|
||||
|
||||
extern struct format_loader *format_loaders[];
|
||||
|
||||
void libxmp_load_prologue(struct context_data *);
|
||||
void libxmp_load_epilogue(struct context_data *);
|
||||
int libxmp_prepare_scan(struct context_data *);
|
||||
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
#define BUFLEN 16384
|
||||
#endif
|
||||
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
static void set_md5sum(HIO_HANDLE *f, unsigned char *digest)
|
||||
{
|
||||
unsigned char buf[BUFLEN];
|
||||
MD5_CTX ctx;
|
||||
int bytes_read;
|
||||
|
||||
hio_seek(f, 0, SEEK_SET);
|
||||
|
||||
MD5Init(&ctx);
|
||||
while ((bytes_read = hio_read(buf, 1, BUFLEN, f)) > 0) {
|
||||
MD5Update(&ctx, buf, bytes_read);
|
||||
}
|
||||
MD5Final(digest, &ctx);
|
||||
}
|
||||
|
||||
static char *get_dirname(const char *name)
|
||||
{
|
||||
char *dirname;
|
||||
const char *div;
|
||||
ptrdiff_t len;
|
||||
|
||||
if ((div = strrchr(name, '/')) != NULL) {
|
||||
len = div - name + 1;
|
||||
dirname = malloc(len + 1);
|
||||
if (dirname != NULL) {
|
||||
memcpy(dirname, name, len);
|
||||
dirname[len] = 0;
|
||||
}
|
||||
} else {
|
||||
dirname = strdup("");
|
||||
}
|
||||
|
||||
return dirname;
|
||||
}
|
||||
|
||||
static char *get_basename(const char *name)
|
||||
{
|
||||
const char *div;
|
||||
char *basename;
|
||||
|
||||
if ((div = strrchr(name, '/')) != NULL) {
|
||||
basename = strdup(div + 1);
|
||||
} else {
|
||||
basename = strdup(name);
|
||||
}
|
||||
|
||||
return basename;
|
||||
}
|
||||
#endif /* LIBXMP_CORE_PLAYER */
|
||||
|
||||
static int test_module(struct xmp_test_info *info, HIO_HANDLE *h)
|
||||
{
|
||||
char buf[XMP_NAME_SIZE];
|
||||
int i;
|
||||
|
||||
if (info != NULL) {
|
||||
*info->name = 0; /* reset name prior to testing */
|
||||
*info->type = 0; /* reset type prior to testing */
|
||||
}
|
||||
|
||||
for (i = 0; format_loaders[i] != NULL; i++) {
|
||||
hio_seek(h, 0, SEEK_SET);
|
||||
if (format_loaders[i]->test(h, buf, 0) == 0) {
|
||||
int is_prowizard = 0;
|
||||
|
||||
#if !defined(LIBXMP_CORE_PLAYER) && !defined(LIBXMP_NO_PROWIZARD)
|
||||
if (strcmp(format_loaders[i]->name, "prowizard") == 0) {
|
||||
hio_seek(h, 0, SEEK_SET);
|
||||
pw_test_format(h, buf, 0, info);
|
||||
is_prowizard = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (info != NULL && !is_prowizard) {
|
||||
strncpy(info->name, buf, XMP_NAME_SIZE - 1);
|
||||
info->name[XMP_NAME_SIZE - 1] = '\0';
|
||||
|
||||
strncpy(info->type, format_loaders[i]->name,
|
||||
XMP_NAME_SIZE - 1);
|
||||
info->type[XMP_NAME_SIZE - 1] = '\0';
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -XMP_ERROR_FORMAT;
|
||||
}
|
||||
|
||||
int xmp_test_module(const char *path, struct xmp_test_info *info)
|
||||
{
|
||||
HIO_HANDLE *h;
|
||||
struct stat st;
|
||||
int ret;
|
||||
#ifndef LIBXMP_NO_DEPACKERS
|
||||
char *temp = NULL;
|
||||
#endif
|
||||
|
||||
if (stat(path, &st) < 0)
|
||||
return -XMP_ERROR_SYSTEM;
|
||||
|
||||
if (S_ISDIR(st.st_mode)) {
|
||||
errno = EISDIR;
|
||||
return -XMP_ERROR_SYSTEM;
|
||||
}
|
||||
|
||||
if ((h = hio_open(path, "rb")) == NULL)
|
||||
return -XMP_ERROR_SYSTEM;
|
||||
|
||||
#ifndef LIBXMP_NO_DEPACKERS
|
||||
if (libxmp_decrunch(&h, path, &temp) < 0) {
|
||||
ret = -XMP_ERROR_DEPACK;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* get size after decrunch */
|
||||
if (hio_size(h) < 256) { /* set minimum valid module size */
|
||||
ret = -XMP_ERROR_FORMAT;
|
||||
goto err;
|
||||
}
|
||||
#endif
|
||||
|
||||
ret = test_module(info, h);
|
||||
|
||||
#ifndef LIBXMP_NO_DEPACKERS
|
||||
err:
|
||||
hio_close(h);
|
||||
unlink_temp_file(temp);
|
||||
#else
|
||||
hio_close(h);
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
int xmp_test_module_from_memory(const void *mem, long size, struct xmp_test_info *info)
|
||||
{
|
||||
HIO_HANDLE *h;
|
||||
int ret;
|
||||
|
||||
if (size <= 0) {
|
||||
return -XMP_ERROR_INVALID;
|
||||
}
|
||||
|
||||
if ((h = hio_open_mem(mem, size)) == NULL)
|
||||
return -XMP_ERROR_SYSTEM;
|
||||
|
||||
ret = test_module(info, h);
|
||||
|
||||
hio_close(h);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int xmp_test_module_from_file(void *file, struct xmp_test_info *info)
|
||||
{
|
||||
HIO_HANDLE *h;
|
||||
int ret;
|
||||
#ifndef LIBXMP_NO_DEPACKERS
|
||||
char *temp = NULL;
|
||||
#endif
|
||||
|
||||
if ((h = hio_open_file((FILE *)file)) == NULL)
|
||||
return -XMP_ERROR_SYSTEM;
|
||||
|
||||
#ifndef LIBXMP_NO_DEPACKERS
|
||||
if (libxmp_decrunch(&h, NULL, &temp) < 0) {
|
||||
ret = -XMP_ERROR_DEPACK;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* get size after decrunch */
|
||||
if (hio_size(h) < 256) { /* set minimum valid module size */
|
||||
ret = -XMP_ERROR_FORMAT;
|
||||
goto err;
|
||||
}
|
||||
#endif
|
||||
|
||||
ret = test_module(info, h);
|
||||
|
||||
#ifndef LIBXMP_NO_DEPACKERS
|
||||
err:
|
||||
hio_close(h);
|
||||
unlink_temp_file(temp);
|
||||
#else
|
||||
hio_close(h);
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
int xmp_test_module_from_callbacks(void *priv, struct xmp_callbacks callbacks,
|
||||
struct xmp_test_info *info)
|
||||
{
|
||||
HIO_HANDLE *h;
|
||||
int ret;
|
||||
|
||||
if ((h = hio_open_callbacks(priv, callbacks)) == NULL)
|
||||
return -XMP_ERROR_SYSTEM;
|
||||
|
||||
ret = test_module(info, h);
|
||||
|
||||
hio_close(h);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int load_module(xmp_context opaque, HIO_HANDLE *h)
|
||||
{
|
||||
struct context_data *ctx = (struct context_data *)opaque;
|
||||
struct module_data *m = &ctx->m;
|
||||
struct xmp_module *mod = &m->mod;
|
||||
int i, j, ret;
|
||||
int test_result, load_result;
|
||||
|
||||
libxmp_load_prologue(ctx);
|
||||
|
||||
D_(D_WARN "load");
|
||||
test_result = load_result = -1;
|
||||
for (i = 0; format_loaders[i] != NULL; i++) {
|
||||
hio_seek(h, 0, SEEK_SET);
|
||||
hio_error(h); /* reset error flag */
|
||||
|
||||
D_(D_WARN "test %s", format_loaders[i]->name);
|
||||
test_result = format_loaders[i]->test(h, NULL, 0);
|
||||
if (test_result == 0) {
|
||||
hio_seek(h, 0, SEEK_SET);
|
||||
D_(D_WARN "load format: %s", format_loaders[i]->name);
|
||||
load_result = format_loaders[i]->loader(m, h, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
if (test_result == 0 && load_result == 0)
|
||||
set_md5sum(h, m->md5);
|
||||
#endif
|
||||
|
||||
if (test_result < 0) {
|
||||
xmp_release_module(opaque);
|
||||
return -XMP_ERROR_FORMAT;
|
||||
}
|
||||
|
||||
if (load_result < 0) {
|
||||
goto err_load;
|
||||
}
|
||||
|
||||
/* Sanity check: number of channels, module length */
|
||||
if (mod->chn > XMP_MAX_CHANNELS || mod->len > XMP_MAX_MOD_LENGTH) {
|
||||
goto err_load;
|
||||
}
|
||||
|
||||
/* Sanity check: channel pan */
|
||||
for (i = 0; i < mod->chn; i++) {
|
||||
if (mod->xxc[i].vol < 0 || mod->xxc[i].vol > 0xff) {
|
||||
goto err_load;
|
||||
}
|
||||
if (mod->xxc[i].pan < 0 || mod->xxc[i].pan > 0xff) {
|
||||
goto err_load;
|
||||
}
|
||||
}
|
||||
|
||||
/* Sanity check: patterns */
|
||||
if (mod->xxp == NULL) {
|
||||
goto err_load;
|
||||
}
|
||||
for (i = 0; i < mod->pat; i++) {
|
||||
if (mod->xxp[i] == NULL) {
|
||||
goto err_load;
|
||||
}
|
||||
for (j = 0; j < mod->chn; j++) {
|
||||
int t = mod->xxp[i]->index[j];
|
||||
if (t < 0 || t >= mod->trk || mod->xxt[t] == NULL) {
|
||||
goto err_load;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
libxmp_adjust_string(mod->name);
|
||||
for (i = 0; i < mod->ins; i++) {
|
||||
libxmp_adjust_string(mod->xxi[i].name);
|
||||
}
|
||||
for (i = 0; i < mod->smp; i++) {
|
||||
libxmp_adjust_string(mod->xxs[i].name);
|
||||
}
|
||||
|
||||
libxmp_load_epilogue(ctx);
|
||||
|
||||
ret = libxmp_prepare_scan(ctx);
|
||||
if (ret < 0) {
|
||||
xmp_release_module(opaque);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = libxmp_scan_sequences(ctx);
|
||||
if (ret < 0) {
|
||||
xmp_release_module(opaque);
|
||||
return -XMP_ERROR_LOAD;
|
||||
}
|
||||
|
||||
ctx->state = XMP_STATE_LOADED;
|
||||
|
||||
return 0;
|
||||
|
||||
err_load:
|
||||
xmp_release_module(opaque);
|
||||
return -XMP_ERROR_LOAD;
|
||||
}
|
||||
|
||||
int xmp_load_module(xmp_context opaque, const char *path)
|
||||
{
|
||||
struct context_data *ctx = (struct context_data *)opaque;
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
struct module_data *m = &ctx->m;
|
||||
long size;
|
||||
#endif
|
||||
#ifndef LIBXMP_NO_DEPACKERS
|
||||
char *temp_name;
|
||||
#endif
|
||||
HIO_HANDLE *h;
|
||||
struct stat st;
|
||||
int ret;
|
||||
|
||||
D_(D_WARN "path = %s", path);
|
||||
|
||||
if (stat(path, &st) < 0) {
|
||||
return -XMP_ERROR_SYSTEM;
|
||||
}
|
||||
|
||||
if (S_ISDIR(st.st_mode)) {
|
||||
errno = EISDIR;
|
||||
return -XMP_ERROR_SYSTEM;
|
||||
}
|
||||
|
||||
if ((h = hio_open(path, "rb")) == NULL) {
|
||||
return -XMP_ERROR_SYSTEM;
|
||||
}
|
||||
|
||||
#ifndef LIBXMP_NO_DEPACKERS
|
||||
D_(D_INFO "decrunch");
|
||||
if (libxmp_decrunch(&h, path, &temp_name) < 0) {
|
||||
ret = -XMP_ERROR_DEPACK;
|
||||
goto err;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
size = hio_size(h);
|
||||
if (size < 256) { /* get size after decrunch */
|
||||
ret = -XMP_ERROR_FORMAT;
|
||||
goto err;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ctx->state > XMP_STATE_UNLOADED)
|
||||
xmp_release_module(opaque);
|
||||
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
m->dirname = get_dirname(path);
|
||||
if (m->dirname == NULL) {
|
||||
ret = -XMP_ERROR_SYSTEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
m->basename = get_basename(path);
|
||||
if (m->basename == NULL) {
|
||||
ret = -XMP_ERROR_SYSTEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
m->filename = path; /* For ALM, SSMT, etc */
|
||||
m->size = size;
|
||||
#else
|
||||
ctx->m.filename = NULL;
|
||||
ctx->m.dirname = NULL;
|
||||
ctx->m.basename = NULL;
|
||||
#endif
|
||||
|
||||
ret = load_module(opaque, h);
|
||||
hio_close(h);
|
||||
|
||||
#ifndef LIBXMP_NO_DEPACKERS
|
||||
unlink_temp_file(temp_name);
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
err:
|
||||
hio_close(h);
|
||||
#ifndef LIBXMP_NO_DEPACKERS
|
||||
unlink_temp_file(temp_name);
|
||||
#endif
|
||||
return ret;
|
||||
#endif
|
||||
}
|
||||
|
||||
int xmp_load_module_from_memory(xmp_context opaque, const void *mem, long size)
|
||||
{
|
||||
struct context_data *ctx = (struct context_data *)opaque;
|
||||
struct module_data *m = &ctx->m;
|
||||
HIO_HANDLE *h;
|
||||
int ret;
|
||||
|
||||
if (size <= 0) {
|
||||
return -XMP_ERROR_INVALID;
|
||||
}
|
||||
|
||||
if ((h = hio_open_mem(mem, size)) == NULL)
|
||||
return -XMP_ERROR_SYSTEM;
|
||||
|
||||
if (ctx->state > XMP_STATE_UNLOADED)
|
||||
xmp_release_module(opaque);
|
||||
|
||||
m->filename = NULL;
|
||||
m->basename = NULL;
|
||||
m->dirname = NULL;
|
||||
m->size = size;
|
||||
|
||||
ret = load_module(opaque, h);
|
||||
|
||||
hio_close(h);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int xmp_load_module_from_file(xmp_context opaque, void *file, long size)
|
||||
{
|
||||
struct context_data *ctx = (struct context_data *)opaque;
|
||||
struct module_data *m = &ctx->m;
|
||||
HIO_HANDLE *h;
|
||||
int ret;
|
||||
|
||||
if ((h = hio_open_file((FILE *)file)) == NULL)
|
||||
return -XMP_ERROR_SYSTEM;
|
||||
|
||||
if (ctx->state > XMP_STATE_UNLOADED)
|
||||
xmp_release_module(opaque);
|
||||
|
||||
m->filename = NULL;
|
||||
m->basename = NULL;
|
||||
m->dirname = NULL;
|
||||
m->size = hio_size(h);
|
||||
|
||||
ret = load_module(opaque, h);
|
||||
|
||||
hio_close(h);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int xmp_load_module_from_callbacks(xmp_context opaque, void *priv,
|
||||
struct xmp_callbacks callbacks)
|
||||
{
|
||||
struct context_data *ctx = (struct context_data *)opaque;
|
||||
struct module_data *m = &ctx->m;
|
||||
HIO_HANDLE *h;
|
||||
int ret;
|
||||
|
||||
if ((h = hio_open_callbacks(priv, callbacks)) == NULL)
|
||||
return -XMP_ERROR_SYSTEM;
|
||||
|
||||
if (ctx->state > XMP_STATE_UNLOADED)
|
||||
xmp_release_module(opaque);
|
||||
|
||||
m->filename = NULL;
|
||||
m->basename = NULL;
|
||||
m->dirname = NULL;
|
||||
m->size = hio_size(h);
|
||||
|
||||
ret = load_module(opaque, h);
|
||||
|
||||
hio_close(h);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void xmp_release_module(xmp_context opaque)
|
||||
{
|
||||
struct context_data *ctx = (struct context_data *)opaque;
|
||||
struct module_data *m = &ctx->m;
|
||||
struct xmp_module *mod = &m->mod;
|
||||
int i;
|
||||
|
||||
/* can't test this here, we must call release_module to clean up
|
||||
* load errors
|
||||
if (ctx->state < XMP_STATE_LOADED)
|
||||
return;
|
||||
*/
|
||||
|
||||
if (ctx->state > XMP_STATE_LOADED)
|
||||
xmp_end_player(opaque);
|
||||
|
||||
ctx->state = XMP_STATE_UNLOADED;
|
||||
|
||||
D_(D_INFO "Freeing memory");
|
||||
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
libxmp_release_module_extras(ctx);
|
||||
#endif
|
||||
|
||||
if (mod->xxt != NULL) {
|
||||
for (i = 0; i < mod->trk; i++) {
|
||||
free(mod->xxt[i]);
|
||||
}
|
||||
free(mod->xxt);
|
||||
mod->xxt = NULL;
|
||||
}
|
||||
|
||||
if (mod->xxp != NULL) {
|
||||
for (i = 0; i < mod->pat; i++) {
|
||||
free(mod->xxp[i]);
|
||||
}
|
||||
free(mod->xxp);
|
||||
mod->xxp = NULL;
|
||||
}
|
||||
|
||||
if (mod->xxi != NULL) {
|
||||
for (i = 0; i < mod->ins; i++) {
|
||||
free(mod->xxi[i].sub);
|
||||
free(mod->xxi[i].extra);
|
||||
}
|
||||
free(mod->xxi);
|
||||
mod->xxi = NULL;
|
||||
}
|
||||
|
||||
if (mod->xxs != NULL) {
|
||||
for (i = 0; i < mod->smp; i++) {
|
||||
libxmp_free_sample(&mod->xxs[i]);
|
||||
}
|
||||
free(mod->xxs);
|
||||
mod->xxs = NULL;
|
||||
}
|
||||
|
||||
free(m->xtra);
|
||||
m->xtra = NULL;
|
||||
|
||||
#ifndef LIBXMP_CORE_DISABLE_IT
|
||||
if (m->xsmp != NULL) {
|
||||
for (i = 0; i < mod->smp; i++) {
|
||||
libxmp_free_sample(&m->xsmp[i]);
|
||||
}
|
||||
free(m->xsmp);
|
||||
m->xsmp = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
libxmp_free_scan(ctx);
|
||||
|
||||
free(m->comment);
|
||||
m->comment = NULL;
|
||||
|
||||
D_("free dirname/basename");
|
||||
free(m->dirname);
|
||||
free(m->basename);
|
||||
m->basename = NULL;
|
||||
m->dirname = NULL;
|
||||
}
|
||||
|
||||
void xmp_scan_module(xmp_context opaque)
|
||||
{
|
||||
struct context_data *ctx = (struct context_data *)opaque;
|
||||
|
||||
if (ctx->state < XMP_STATE_LOADED)
|
||||
return;
|
||||
|
||||
libxmp_scan_sequences(ctx);
|
||||
}
|
399
internal/c/parts/audio/extras/libxmp-lite/load_helpers.c
Normal file
399
internal/c/parts/audio/extras/libxmp-lite/load_helpers.c
Normal file
|
@ -0,0 +1,399 @@
|
|||
/* Extended Module Player
|
||||
* Copyright (C) 1996-2021 Claudio Matsuoka and Hipolito Carraro Jr
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include "common.h"
|
||||
#include "loader.h"
|
||||
|
||||
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
|
||||
/*
|
||||
* Handle special "module quirks" that can't be detected automatically
|
||||
* such as Protracker 2.x compatibility, vblank timing, etc.
|
||||
*/
|
||||
|
||||
struct module_quirk {
|
||||
uint8 md5[16];
|
||||
int flags;
|
||||
int mode;
|
||||
};
|
||||
|
||||
const struct module_quirk mq[] = {
|
||||
/* "No Mercy" by Alf/VTL (added by Martin Willers) */
|
||||
{
|
||||
{ 0x36, 0x6e, 0xc0, 0xfa, 0x96, 0x2a, 0xeb, 0xee,
|
||||
0x03, 0x4a, 0xa2, 0xdb, 0xaa, 0x49, 0xaa, 0xea },
|
||||
0, XMP_MODE_PROTRACKER
|
||||
},
|
||||
|
||||
/* mod.souvenir of china */
|
||||
{
|
||||
{ 0x93, 0xf1, 0x46, 0xae, 0xb7, 0x58, 0xc3, 0x9d,
|
||||
0x8b, 0x5f, 0xbc, 0x98, 0xbf, 0x23, 0x7a, 0x43 },
|
||||
XMP_FLAGS_FIXLOOP, XMP_MODE_AUTO
|
||||
},
|
||||
|
||||
/* "siedler ii" (added by Daniel Åkerud) */
|
||||
{
|
||||
{ 0x70, 0xaa, 0x03, 0x4d, 0xfb, 0x2f, 0x1f, 0x73,
|
||||
0xd9, 0xfd, 0xba, 0xfe, 0x13, 0x1b, 0xb7, 0x01 },
|
||||
XMP_FLAGS_VBLANK, XMP_MODE_AUTO
|
||||
},
|
||||
|
||||
/* "Klisje paa klisje" (added by Kjetil Torgrim Homme) */
|
||||
{
|
||||
{ 0xe9, 0x98, 0x01, 0x2c, 0x70, 0x0e, 0xb4, 0x3a,
|
||||
0xf0, 0x32, 0x17, 0x11, 0x30, 0x58, 0x29, 0xb2 },
|
||||
0, XMP_MODE_NOISETRACKER
|
||||
},
|
||||
|
||||
#if 0
|
||||
/* -- Already covered by Noisetracker fingerprinting -- */
|
||||
|
||||
/* Another version of Klisje paa klisje sent by Steve Fernandez */
|
||||
{
|
||||
{ 0x12, 0x19, 0x1c, 0x90, 0x41, 0xe3, 0xfd, 0x70,
|
||||
0xb7, 0xe6, 0xb3, 0x94, 0x8b, 0x21, 0x07, 0x63 },
|
||||
XMP_FLAGS_VBLANK
|
||||
},
|
||||
#endif
|
||||
|
||||
/* "((((( nebulos )))))" sent by Tero Auvinen (AMP version) */
|
||||
{
|
||||
{ 0x51, 0x6e, 0x8d, 0xcc, 0x35, 0x7d, 0x50, 0xde,
|
||||
0xa9, 0x85, 0xbe, 0xbf, 0x90, 0x2e, 0x42, 0xdc },
|
||||
0, XMP_MODE_NOISETRACKER
|
||||
},
|
||||
|
||||
/* Purple Motion's Sundance.mod, Music Channel BBS edit */
|
||||
{
|
||||
{ 0x5d, 0x3e, 0x1e, 0x08, 0x28, 0x52, 0x12, 0xc7,
|
||||
0x17, 0x64, 0x95, 0x75, 0x98, 0xe6, 0x95, 0xc1 },
|
||||
0, XMP_MODE_ST3
|
||||
},
|
||||
|
||||
/* Asle's Ode to Protracker */
|
||||
{
|
||||
{ 0x97, 0xa3, 0x7d, 0x30, 0xd7, 0xae, 0x6d, 0x50,
|
||||
0xc9, 0x62, 0xe9, 0xd8, 0x87, 0x1b, 0x7e, 0x8a },
|
||||
0, XMP_MODE_PROTRACKER
|
||||
},
|
||||
|
||||
{
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
0, 0
|
||||
}
|
||||
};
|
||||
|
||||
static void module_quirks(struct context_data *ctx)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
struct module_data *m = &ctx->m;
|
||||
int i;
|
||||
|
||||
for (i = 0; mq[i].flags != 0 || mq[i].mode != 0; i++) {
|
||||
if (!memcmp(m->md5, mq[i].md5, 16)) {
|
||||
p->flags |= mq[i].flags;
|
||||
p->mode = mq[i].mode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* LIBXMP_CORE_PLAYER */
|
||||
|
||||
char *libxmp_adjust_string(char *s)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < strlen(s); i++) {
|
||||
if (!isprint((int)s[i]) || ((uint8) s[i] > 127))
|
||||
s[i] = ' ';
|
||||
}
|
||||
|
||||
while (*s && (s[strlen(s) - 1] == ' ')) {
|
||||
s[strlen(s) - 1] = 0;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
static void check_envelope(struct xmp_envelope *env)
|
||||
{
|
||||
/* Disable envelope if invalid number of points */
|
||||
if (env->npt <= 0 || env->npt > XMP_MAX_ENV_POINTS) {
|
||||
env->flg &= ~XMP_ENVELOPE_ON;
|
||||
}
|
||||
|
||||
/* Disable envelope loop if invalid loop parameters */
|
||||
if (env->lps >= env->npt || env->lpe >= env->npt) {
|
||||
env->flg &= ~XMP_ENVELOPE_LOOP;
|
||||
}
|
||||
|
||||
/* Disable envelope loop if invalid sustain */
|
||||
if (env->sus >= env->npt) {
|
||||
env->flg &= ~XMP_ENVELOPE_ON;
|
||||
}
|
||||
}
|
||||
|
||||
void libxmp_load_prologue(struct context_data *ctx)
|
||||
{
|
||||
struct module_data *m = &ctx->m;
|
||||
int i;
|
||||
|
||||
/* Reset variables */
|
||||
memset(&m->mod, 0, sizeof (struct xmp_module));
|
||||
m->rrate = PAL_RATE;
|
||||
m->c4rate = C4_PAL_RATE;
|
||||
m->volbase = 0x40;
|
||||
m->gvol = m->gvolbase = 0x40;
|
||||
m->vol_table = NULL;
|
||||
m->quirk = 0;
|
||||
m->read_event_type = READ_EVENT_MOD;
|
||||
m->period_type = PERIOD_AMIGA;
|
||||
m->comment = NULL;
|
||||
m->scan_cnt = NULL;
|
||||
|
||||
/* Set defaults */
|
||||
m->mod.pat = 0;
|
||||
m->mod.trk = 0;
|
||||
m->mod.chn = 4;
|
||||
m->mod.ins = 0;
|
||||
m->mod.smp = 0;
|
||||
m->mod.spd = 6;
|
||||
m->mod.bpm = 125;
|
||||
m->mod.len = 0;
|
||||
m->mod.rst = 0;
|
||||
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
m->extra = NULL;
|
||||
#endif
|
||||
#ifndef LIBXMP_CORE_DISABLE_IT
|
||||
m->xsmp = NULL;
|
||||
#endif
|
||||
|
||||
m->time_factor = DEFAULT_TIME_FACTOR;
|
||||
|
||||
for (i = 0; i < 64; i++) {
|
||||
int pan = (((i + 1) / 2) % 2) * 0xff;
|
||||
m->mod.xxc[i].pan = 0x80 + (pan - 0x80) * m->defpan / 100;
|
||||
m->mod.xxc[i].vol = 0x40;
|
||||
m->mod.xxc[i].flg = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void libxmp_load_epilogue(struct context_data *ctx)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
struct module_data *m = &ctx->m;
|
||||
struct xmp_module *mod = &m->mod;
|
||||
int i, j;
|
||||
|
||||
mod->gvl = m->gvol;
|
||||
|
||||
/* Sanity check for module parameters */
|
||||
CLAMP(mod->len, 0, XMP_MAX_MOD_LENGTH);
|
||||
CLAMP(mod->pat, 0, 257); /* some formats have an extra pattern */
|
||||
CLAMP(mod->ins, 0, 255);
|
||||
CLAMP(mod->smp, 0, MAX_SAMPLES);
|
||||
CLAMP(mod->chn, 0, XMP_MAX_CHANNELS);
|
||||
|
||||
/* Fix cases where the restart value is invalid e.g. kc_fall8.xm
|
||||
* from http://aminet.net/mods/mvp/mvp_0002.lha (reported by
|
||||
* Ralf Hoffmann <ralf@boomerangsworld.de>)
|
||||
*/
|
||||
if (mod->rst >= mod->len) {
|
||||
mod->rst = 0;
|
||||
}
|
||||
|
||||
/* Sanity check for tempo and BPM */
|
||||
if (mod->spd <= 0 || mod->spd > 255) {
|
||||
mod->spd = 6;
|
||||
}
|
||||
CLAMP(mod->bpm, XMP_MIN_BPM, 255);
|
||||
|
||||
/* Set appropriate values for instrument volumes and subinstrument
|
||||
* global volumes when QUIRK_INSVOL is not set, to keep volume values
|
||||
* consistent if the user inspects struct xmp_module. We can later
|
||||
* set volumes in the loaders and eliminate the quirk.
|
||||
*/
|
||||
for (i = 0; i < mod->ins; i++) {
|
||||
if (~m->quirk & QUIRK_INSVOL) {
|
||||
mod->xxi[i].vol = m->volbase;
|
||||
}
|
||||
for (j = 0; j < mod->xxi[i].nsm; j++) {
|
||||
if (~m->quirk & QUIRK_INSVOL) {
|
||||
mod->xxi[i].sub[j].gvl = m->volbase;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Sanity check for envelopes
|
||||
*/
|
||||
for (i = 0; i < mod->ins; i++) {
|
||||
check_envelope(&mod->xxi[i].aei);
|
||||
check_envelope(&mod->xxi[i].fei);
|
||||
check_envelope(&mod->xxi[i].pei);
|
||||
}
|
||||
|
||||
p->filter = 0;
|
||||
p->mode = XMP_MODE_AUTO;
|
||||
p->flags = p->player_flags;
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
module_quirks(ctx);
|
||||
#endif
|
||||
libxmp_set_player_mode(ctx);
|
||||
}
|
||||
|
||||
int libxmp_prepare_scan(struct context_data *ctx)
|
||||
{
|
||||
struct module_data *m = &ctx->m;
|
||||
struct xmp_module *mod = &m->mod;
|
||||
int i, ord;
|
||||
|
||||
if (mod->xxp == NULL || mod->xxt == NULL)
|
||||
return -XMP_ERROR_LOAD;
|
||||
ord = 0;
|
||||
while (ord < mod->len && mod->xxo[ord] >= mod->pat) {
|
||||
ord++;
|
||||
}
|
||||
|
||||
if (ord >= mod->len) {
|
||||
mod->len = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
m->scan_cnt = calloc(sizeof (uint8 *), mod->len);
|
||||
if (m->scan_cnt == NULL)
|
||||
return -XMP_ERROR_SYSTEM;
|
||||
|
||||
for (i = 0; i < mod->len; i++) {
|
||||
int pat_idx = mod->xxo[i];
|
||||
struct xmp_pattern *pat;
|
||||
|
||||
/* Add pattern if referenced in orders */
|
||||
if (pat_idx < mod->pat && !mod->xxp[pat_idx]) {
|
||||
if (libxmp_alloc_pattern(mod, pat_idx) < 0) {
|
||||
return -XMP_ERROR_SYSTEM;
|
||||
}
|
||||
}
|
||||
|
||||
pat = pat_idx >= mod->pat ? NULL : mod->xxp[pat_idx];
|
||||
m->scan_cnt[i] = calloc(1, pat && pat->rows ? pat->rows : 1);
|
||||
if (m->scan_cnt[i] == NULL)
|
||||
return -XMP_ERROR_SYSTEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void libxmp_free_scan(struct context_data *ctx)
|
||||
{
|
||||
struct module_data *m = &ctx->m;
|
||||
struct xmp_module *mod = &m->mod;
|
||||
int i;
|
||||
|
||||
if (m->scan_cnt) {
|
||||
for (i = 0; i < mod->len; i++)
|
||||
free(m->scan_cnt[i]);
|
||||
|
||||
free(m->scan_cnt);
|
||||
m->scan_cnt = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Process player personality flags */
|
||||
int libxmp_set_player_mode(struct context_data *ctx)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
struct module_data *m = &ctx->m;
|
||||
int q;
|
||||
|
||||
switch (p->mode) {
|
||||
case XMP_MODE_AUTO:
|
||||
break;
|
||||
case XMP_MODE_MOD:
|
||||
m->c4rate = C4_PAL_RATE;
|
||||
m->quirk = 0;
|
||||
m->read_event_type = READ_EVENT_MOD;
|
||||
m->period_type = PERIOD_AMIGA;
|
||||
break;
|
||||
case XMP_MODE_NOISETRACKER:
|
||||
m->c4rate = C4_PAL_RATE;
|
||||
m->quirk = QUIRK_NOBPM;
|
||||
m->read_event_type = READ_EVENT_MOD;
|
||||
m->period_type = PERIOD_MODRNG;
|
||||
break;
|
||||
case XMP_MODE_PROTRACKER:
|
||||
m->c4rate = C4_PAL_RATE;
|
||||
m->quirk = QUIRK_PROTRACK;
|
||||
m->read_event_type = READ_EVENT_MOD;
|
||||
m->period_type = PERIOD_MODRNG;
|
||||
break;
|
||||
case XMP_MODE_S3M:
|
||||
q = m->quirk & (QUIRK_VSALL | QUIRK_ARPMEM);
|
||||
m->c4rate = C4_NTSC_RATE;
|
||||
m->quirk = QUIRKS_ST3 | q;
|
||||
m->read_event_type = READ_EVENT_ST3;
|
||||
break;
|
||||
case XMP_MODE_ST3:
|
||||
q = m->quirk & (QUIRK_VSALL | QUIRK_ARPMEM);
|
||||
m->c4rate = C4_NTSC_RATE;
|
||||
m->quirk = QUIRKS_ST3 | QUIRK_ST3BUGS | q;
|
||||
m->read_event_type = READ_EVENT_ST3;
|
||||
break;
|
||||
case XMP_MODE_ST3GUS:
|
||||
q = m->quirk & (QUIRK_VSALL | QUIRK_ARPMEM);
|
||||
m->c4rate = C4_NTSC_RATE;
|
||||
m->quirk = QUIRKS_ST3 | QUIRK_ST3BUGS | q;
|
||||
m->quirk &= ~QUIRK_RSTCHN;
|
||||
m->read_event_type = READ_EVENT_ST3;
|
||||
break;
|
||||
case XMP_MODE_XM:
|
||||
m->c4rate = C4_NTSC_RATE;
|
||||
m->quirk = QUIRKS_FT2;
|
||||
m->read_event_type = READ_EVENT_FT2;
|
||||
break;
|
||||
case XMP_MODE_FT2:
|
||||
m->c4rate = C4_NTSC_RATE;
|
||||
m->quirk = QUIRKS_FT2 | QUIRK_FT2BUGS;
|
||||
m->read_event_type = READ_EVENT_FT2;
|
||||
break;
|
||||
case XMP_MODE_IT:
|
||||
m->c4rate = C4_NTSC_RATE;
|
||||
m->quirk = QUIRKS_IT | QUIRK_VIBHALF | QUIRK_VIBINV;
|
||||
m->read_event_type = READ_EVENT_IT;
|
||||
break;
|
||||
case XMP_MODE_ITSMP:
|
||||
m->c4rate = C4_NTSC_RATE;
|
||||
m->quirk = QUIRKS_IT | QUIRK_VIBHALF | QUIRK_VIBINV;
|
||||
m->quirk &= ~(QUIRK_VIRTUAL | QUIRK_RSTCHN);
|
||||
m->read_event_type = READ_EVENT_IT;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
65
internal/c/parts/audio/extras/libxmp-lite/loader.h
Normal file
65
internal/c/parts/audio/extras/libxmp-lite/loader.h
Normal file
|
@ -0,0 +1,65 @@
|
|||
#ifndef XMP_LOADER_H
|
||||
#define XMP_LOADER_H
|
||||
|
||||
#include "common.h"
|
||||
#include "effects.h"
|
||||
#include "format.h"
|
||||
#include "hio.h"
|
||||
|
||||
/* Sample flags */
|
||||
#define SAMPLE_FLAG_DIFF 0x0001 /* Differential */
|
||||
#define SAMPLE_FLAG_UNS 0x0002 /* Unsigned */
|
||||
#define SAMPLE_FLAG_8BDIFF 0x0004
|
||||
#define SAMPLE_FLAG_7BIT 0x0008
|
||||
#define SAMPLE_FLAG_NOLOAD 0x0010 /* Get from buffer, don't load */
|
||||
#define SAMPLE_FLAG_BIGEND 0x0040 /* Big-endian */
|
||||
#define SAMPLE_FLAG_VIDC 0x0080 /* Archimedes VIDC logarithmic */
|
||||
/*#define SAMPLE_FLAG_STEREO 0x0100 Interleaved stereo sample */
|
||||
#define SAMPLE_FLAG_FULLREP 0x0200 /* Play full sample before looping */
|
||||
#define SAMPLE_FLAG_ADLIB 0x1000 /* Adlib synth instrument */
|
||||
#define SAMPLE_FLAG_HSC 0x2000 /* HSC Adlib synth instrument */
|
||||
#define SAMPLE_FLAG_ADPCM 0x4000 /* ADPCM4 encoded samples */
|
||||
|
||||
#define DEFPAN(x) (0x80 + ((x) - 0x80) * m->defpan / 100)
|
||||
|
||||
int libxmp_init_instrument (struct module_data *);
|
||||
int libxmp_realloc_samples (struct module_data *, int);
|
||||
int libxmp_alloc_subinstrument (struct xmp_module *, int, int);
|
||||
int libxmp_init_pattern (struct xmp_module *);
|
||||
int libxmp_alloc_pattern (struct xmp_module *, int);
|
||||
int libxmp_alloc_track (struct xmp_module *, int, int);
|
||||
int libxmp_alloc_tracks_in_pattern (struct xmp_module *, int);
|
||||
int libxmp_alloc_pattern_tracks (struct xmp_module *, int, int);
|
||||
int libxmp_alloc_pattern_tracks_long(struct xmp_module *, int, int);
|
||||
char *libxmp_instrument_name (struct xmp_module *, int, uint8 *, int);
|
||||
|
||||
char *libxmp_copy_adjust (char *, uint8 *, int);
|
||||
int libxmp_copy_name_for_fopen (char *, const char *, int);
|
||||
int libxmp_test_name (uint8 *, int);
|
||||
void libxmp_read_title (HIO_HANDLE *, char *, int);
|
||||
void libxmp_set_xxh_defaults (struct xmp_module *);
|
||||
void libxmp_decode_protracker_event (struct xmp_event *, uint8 *);
|
||||
void libxmp_decode_noisetracker_event(struct xmp_event *, uint8 *);
|
||||
void libxmp_disable_continue_fx (struct xmp_event *);
|
||||
int libxmp_check_filename_case (const char *, const char *, char *, int);
|
||||
void libxmp_get_instrument_path (struct module_data *, char *, int);
|
||||
void libxmp_set_type (struct module_data *, const char *, ...);
|
||||
int libxmp_load_sample (struct module_data *, HIO_HANDLE *, int,
|
||||
struct xmp_sample *, const void *);
|
||||
void libxmp_free_sample (struct xmp_sample *);
|
||||
void libxmp_schism_tracker_string (char *, size_t, int, int);
|
||||
|
||||
extern uint8 libxmp_ord_xlat[];
|
||||
extern const int libxmp_arch_vol_table[];
|
||||
|
||||
#define MAGIC4(a,b,c,d) \
|
||||
(((uint32)(a)<<24)|((uint32)(b)<<16)|((uint32)(c)<<8)|(d))
|
||||
|
||||
#define LOAD_INIT()
|
||||
|
||||
#define MODULE_INFO() do { \
|
||||
D_(D_WARN "Module title: \"%s\"", m->mod.name); \
|
||||
D_(D_WARN "Module type: %s", m->mod.type); \
|
||||
} while (0)
|
||||
|
||||
#endif
|
240
internal/c/parts/audio/extras/libxmp-lite/md5.c
Normal file
240
internal/c/parts/audio/extras/libxmp-lite/md5.c
Normal file
|
@ -0,0 +1,240 @@
|
|||
/*
|
||||
* This code implements the MD5 message-digest algorithm.
|
||||
* The algorithm is due to Ron Rivest. This code was
|
||||
* written by Colin Plumb in 1993, no copyright is claimed.
|
||||
* This code is in the public domain; do with it what you wish.
|
||||
*
|
||||
* Equivalent code is available from RSA Data Security, Inc.
|
||||
* This code has been tested against that, and is equivalent,
|
||||
* except that you don't need to include two pages of legalese
|
||||
* with every copy.
|
||||
*
|
||||
* To compute the message digest of a chunk of bytes, declare an
|
||||
* MD5Context structure, pass it to MD5Init, call MD5Update as
|
||||
* needed on buffers full of bytes, and then call MD5Final, which
|
||||
* will fill a supplied 16-byte array with the digest.
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "md5.h"
|
||||
|
||||
#define PUT_64BIT_LE(cp, value) do { \
|
||||
(cp)[7] = (value) >> 56; \
|
||||
(cp)[6] = (value) >> 48; \
|
||||
(cp)[5] = (value) >> 40; \
|
||||
(cp)[4] = (value) >> 32; \
|
||||
(cp)[3] = (value) >> 24; \
|
||||
(cp)[2] = (value) >> 16; \
|
||||
(cp)[1] = (value) >> 8; \
|
||||
(cp)[0] = (value); } while (0)
|
||||
|
||||
#define PUT_32BIT_LE(cp, value) do { \
|
||||
(cp)[3] = (value) >> 24; \
|
||||
(cp)[2] = (value) >> 16; \
|
||||
(cp)[1] = (value) >> 8; \
|
||||
(cp)[0] = (value); } while (0)
|
||||
|
||||
static uint8 PADDING[MD5_BLOCK_LENGTH] = {
|
||||
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
/* The four core functions - F1 is optimized somewhat */
|
||||
|
||||
/* #define F1(x, y, z) (x & y | ~x & z) */
|
||||
#define F1(x, y, z) (z ^ (x & (y ^ z)))
|
||||
#define F2(x, y, z) F1(z, x, y)
|
||||
#define F3(x, y, z) (x ^ y ^ z)
|
||||
#define F4(x, y, z) (y ^ (x | ~z))
|
||||
|
||||
/* This is the central step in the MD5 algorithm. */
|
||||
#define MD5STEP(f, w, x, y, z, data, s) \
|
||||
( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
|
||||
|
||||
/*
|
||||
* The core of the MD5 algorithm, this alters an existing MD5 hash to
|
||||
* reflect the addition of 16 longwords of new data. MD5Update blocks
|
||||
* the data and converts bytes into longwords for this routine.
|
||||
*/
|
||||
static void MD5Transform(uint32 state[4], const uint8 block[MD5_BLOCK_LENGTH])
|
||||
{
|
||||
uint32 a, b, c, d, in[MD5_BLOCK_LENGTH / 4];
|
||||
|
||||
#ifndef WORDS_BIGENDIAN
|
||||
memcpy(in, block, sizeof(in));
|
||||
#else
|
||||
for (a = 0; a < MD5_BLOCK_LENGTH / 4; a++) {
|
||||
in[a] = (uint32)(
|
||||
(uint32)(block[a * 4 + 0]) |
|
||||
(uint32)(block[a * 4 + 1]) << 8 |
|
||||
(uint32)(block[a * 4 + 2]) << 16 |
|
||||
(uint32)(block[a * 4 + 3]) << 24);
|
||||
}
|
||||
#endif
|
||||
|
||||
a = state[0];
|
||||
b = state[1];
|
||||
c = state[2];
|
||||
d = state[3];
|
||||
|
||||
MD5STEP(F1, a, b, c, d, in[ 0] + 0xd76aa478, 7);
|
||||
MD5STEP(F1, d, a, b, c, in[ 1] + 0xe8c7b756, 12);
|
||||
MD5STEP(F1, c, d, a, b, in[ 2] + 0x242070db, 17);
|
||||
MD5STEP(F1, b, c, d, a, in[ 3] + 0xc1bdceee, 22);
|
||||
MD5STEP(F1, a, b, c, d, in[ 4] + 0xf57c0faf, 7);
|
||||
MD5STEP(F1, d, a, b, c, in[ 5] + 0x4787c62a, 12);
|
||||
MD5STEP(F1, c, d, a, b, in[ 6] + 0xa8304613, 17);
|
||||
MD5STEP(F1, b, c, d, a, in[ 7] + 0xfd469501, 22);
|
||||
MD5STEP(F1, a, b, c, d, in[ 8] + 0x698098d8, 7);
|
||||
MD5STEP(F1, d, a, b, c, in[ 9] + 0x8b44f7af, 12);
|
||||
MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
|
||||
MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
|
||||
MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
|
||||
MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
|
||||
MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
|
||||
MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
|
||||
|
||||
MD5STEP(F2, a, b, c, d, in[ 1] + 0xf61e2562, 5);
|
||||
MD5STEP(F2, d, a, b, c, in[ 6] + 0xc040b340, 9);
|
||||
MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
|
||||
MD5STEP(F2, b, c, d, a, in[ 0] + 0xe9b6c7aa, 20);
|
||||
MD5STEP(F2, a, b, c, d, in[ 5] + 0xd62f105d, 5);
|
||||
MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
|
||||
MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
|
||||
MD5STEP(F2, b, c, d, a, in[ 4] + 0xe7d3fbc8, 20);
|
||||
MD5STEP(F2, a, b, c, d, in[ 9] + 0x21e1cde6, 5);
|
||||
MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
|
||||
MD5STEP(F2, c, d, a, b, in[ 3] + 0xf4d50d87, 14);
|
||||
MD5STEP(F2, b, c, d, a, in[ 8] + 0x455a14ed, 20);
|
||||
MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
|
||||
MD5STEP(F2, d, a, b, c, in[ 2] + 0xfcefa3f8, 9);
|
||||
MD5STEP(F2, c, d, a, b, in[ 7] + 0x676f02d9, 14);
|
||||
MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
|
||||
|
||||
MD5STEP(F3, a, b, c, d, in[ 5] + 0xfffa3942, 4);
|
||||
MD5STEP(F3, d, a, b, c, in[ 8] + 0x8771f681, 11);
|
||||
MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
|
||||
MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
|
||||
MD5STEP(F3, a, b, c, d, in[ 1] + 0xa4beea44, 4);
|
||||
MD5STEP(F3, d, a, b, c, in[ 4] + 0x4bdecfa9, 11);
|
||||
MD5STEP(F3, c, d, a, b, in[ 7] + 0xf6bb4b60, 16);
|
||||
MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
|
||||
MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
|
||||
MD5STEP(F3, d, a, b, c, in[ 0] + 0xeaa127fa, 11);
|
||||
MD5STEP(F3, c, d, a, b, in[ 3] + 0xd4ef3085, 16);
|
||||
MD5STEP(F3, b, c, d, a, in[ 6] + 0x04881d05, 23);
|
||||
MD5STEP(F3, a, b, c, d, in[ 9] + 0xd9d4d039, 4);
|
||||
MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
|
||||
MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
|
||||
MD5STEP(F3, b, c, d, a, in[2 ] + 0xc4ac5665, 23);
|
||||
|
||||
MD5STEP(F4, a, b, c, d, in[ 0] + 0xf4292244, 6);
|
||||
MD5STEP(F4, d, a, b, c, in[7 ] + 0x432aff97, 10);
|
||||
MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
|
||||
MD5STEP(F4, b, c, d, a, in[5 ] + 0xfc93a039, 21);
|
||||
MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
|
||||
MD5STEP(F4, d, a, b, c, in[3 ] + 0x8f0ccc92, 10);
|
||||
MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
|
||||
MD5STEP(F4, b, c, d, a, in[1 ] + 0x85845dd1, 21);
|
||||
MD5STEP(F4, a, b, c, d, in[8 ] + 0x6fa87e4f, 6);
|
||||
MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
|
||||
MD5STEP(F4, c, d, a, b, in[6 ] + 0xa3014314, 15);
|
||||
MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
|
||||
MD5STEP(F4, a, b, c, d, in[4 ] + 0xf7537e82, 6);
|
||||
MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
|
||||
MD5STEP(F4, c, d, a, b, in[2 ] + 0x2ad7d2bb, 15);
|
||||
MD5STEP(F4, b, c, d, a, in[9 ] + 0xeb86d391, 21);
|
||||
|
||||
state[0] += a;
|
||||
state[1] += b;
|
||||
state[2] += c;
|
||||
state[3] += d;
|
||||
}
|
||||
|
||||
/*
|
||||
* Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
|
||||
* initialization constants.
|
||||
*/
|
||||
void MD5Init(MD5_CTX *ctx)
|
||||
{
|
||||
ctx->count = 0;
|
||||
ctx->state[0] = 0x67452301;
|
||||
ctx->state[1] = 0xefcdab89;
|
||||
ctx->state[2] = 0x98badcfe;
|
||||
ctx->state[3] = 0x10325476;
|
||||
}
|
||||
|
||||
/*
|
||||
* Update context to reflect the concatenation of another buffer full
|
||||
* of bytes.
|
||||
*/
|
||||
void MD5Update(MD5_CTX *ctx, const unsigned char *input, size_t len)
|
||||
{
|
||||
size_t have, need;
|
||||
|
||||
/* Check how many bytes we already have and how many more we need. */
|
||||
have = (size_t)((ctx->count >> 3) & (MD5_BLOCK_LENGTH - 1));
|
||||
need = MD5_BLOCK_LENGTH - have;
|
||||
|
||||
/* Update bitcount */
|
||||
ctx->count += (uint64)len << 3;
|
||||
|
||||
if (len >= need) {
|
||||
if (have != 0) {
|
||||
memcpy(ctx->buffer + have, input, need);
|
||||
MD5Transform(ctx->state, ctx->buffer);
|
||||
input += need;
|
||||
len -= need;
|
||||
have = 0;
|
||||
}
|
||||
|
||||
/* Process data in MD5_BLOCK_LENGTH-byte chunks. */
|
||||
while (len >= MD5_BLOCK_LENGTH) {
|
||||
MD5Transform(ctx->state, input);
|
||||
input += MD5_BLOCK_LENGTH;
|
||||
len -= MD5_BLOCK_LENGTH;
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle any remaining bytes of data. */
|
||||
if (len != 0)
|
||||
memcpy(ctx->buffer + have, input, len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Pad pad to 64-byte boundary with the bit pattern
|
||||
* 1 0* (64-bit count of bits processed, MSB-first)
|
||||
*/
|
||||
static void MD5Pad(MD5_CTX *ctx)
|
||||
{
|
||||
uint8 count[8];
|
||||
size_t padlen;
|
||||
|
||||
/* Convert count to 8 bytes in little endian order. */
|
||||
PUT_64BIT_LE(count, ctx->count);
|
||||
|
||||
/* Pad out to 56 mod 64. */
|
||||
padlen = MD5_BLOCK_LENGTH -
|
||||
((ctx->count >> 3) & (MD5_BLOCK_LENGTH - 1));
|
||||
if (padlen < 1 + 8)
|
||||
padlen += MD5_BLOCK_LENGTH;
|
||||
MD5Update(ctx, PADDING, padlen - 8); /* padlen - 8 <= 64 */
|
||||
MD5Update(ctx, count, 8);
|
||||
}
|
||||
|
||||
/*
|
||||
* Final wrapup--call MD5Pad, fill in digest and zero out ctx.
|
||||
*/
|
||||
void MD5Final(unsigned char digest[MD5_DIGEST_LENGTH], MD5_CTX *ctx)
|
||||
{
|
||||
int i;
|
||||
|
||||
MD5Pad(ctx);
|
||||
if (digest != NULL) {
|
||||
for (i = 0; i < 4; i++)
|
||||
PUT_32BIT_LE(digest + i * 4, ctx->state[i]);
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
}
|
||||
}
|
||||
|
39
internal/c/parts/audio/extras/libxmp-lite/md5.h
Normal file
39
internal/c/parts/audio/extras/libxmp-lite/md5.h
Normal file
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* This code implements the MD5 message-digest algorithm.
|
||||
* The algorithm is due to Ron Rivest. This code was
|
||||
* written by Colin Plumb in 1993, no copyright is claimed.
|
||||
* This code is in the public domain; do with it what you wish.
|
||||
*
|
||||
* Equivalent code is available from RSA Data Security, Inc.
|
||||
* This code has been tested against that, and is equivalent,
|
||||
* except that you don't need to include two pages of legalese
|
||||
* with every copy.
|
||||
*/
|
||||
|
||||
#ifndef LIBXMP_MD5_H
|
||||
#define LIBXMP_MD5_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#define MD5_BLOCK_LENGTH 64
|
||||
#define MD5_DIGEST_LENGTH 16
|
||||
#define MD5_DIGEST_STRING_LENGTH (MD5_DIGEST_LENGTH * 2 + 1)
|
||||
|
||||
typedef struct MD5Context {
|
||||
uint32 state[4]; /* state */
|
||||
uint64 count; /* number of bits, mod 2^64 */
|
||||
uint8 buffer[MD5_BLOCK_LENGTH]; /* input buffer */
|
||||
} MD5_CTX;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void MD5Init(MD5_CTX *);
|
||||
void MD5Update(MD5_CTX *, const unsigned char *, size_t);
|
||||
void MD5Final(uint8[MD5_DIGEST_LENGTH], MD5_CTX *);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* LIBXMP_MD5_H */
|
||||
|
125
internal/c/parts/audio/extras/libxmp-lite/mdataio.h
Normal file
125
internal/c/parts/audio/extras/libxmp-lite/mdataio.h
Normal file
|
@ -0,0 +1,125 @@
|
|||
#ifndef LIBXMP_MDATAIO_H
|
||||
#define LIBXMP_MDATAIO_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <limits.h>
|
||||
#include "common.h"
|
||||
|
||||
static inline ptrdiff_t CAN_READ(MFILE *m)
|
||||
{
|
||||
if (m->size >= 0)
|
||||
return m->pos >= 0 ? m->size - m->pos : 0;
|
||||
|
||||
return INT_MAX;
|
||||
}
|
||||
|
||||
static inline uint8 mread8(MFILE *m, int *err)
|
||||
{
|
||||
uint8 x = 0xff;
|
||||
size_t r = mread(&x, 1, 1, m);
|
||||
if (err) {
|
||||
*err = (r == 1) ? 0 : EOF;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
static inline int8 mread8s(MFILE *m, int *err)
|
||||
{
|
||||
int r = mgetc(m);
|
||||
if (err) {
|
||||
*err = (r < 0) ? EOF : 0;
|
||||
}
|
||||
return (int8)r;
|
||||
}
|
||||
|
||||
static inline uint16 mread16l(MFILE *m, int *err)
|
||||
{
|
||||
ptrdiff_t can_read = CAN_READ(m);
|
||||
if (can_read >= 2) {
|
||||
uint16 n = readmem16l(m->start + m->pos);
|
||||
m->pos += 2;
|
||||
if(err) *err = 0;
|
||||
return n;
|
||||
} else {
|
||||
m->pos += can_read;
|
||||
if(err) *err = EOF;
|
||||
return EOF;
|
||||
}
|
||||
}
|
||||
|
||||
static inline uint16 mread16b(MFILE *m, int *err)
|
||||
{
|
||||
ptrdiff_t can_read = CAN_READ(m);
|
||||
if (can_read >= 2) {
|
||||
uint16 n = readmem16b(m->start + m->pos);
|
||||
m->pos += 2;
|
||||
if(err) *err = 0;
|
||||
return n;
|
||||
} else {
|
||||
m->pos += can_read;
|
||||
if(err) *err = EOF;
|
||||
return EOF;
|
||||
}
|
||||
}
|
||||
|
||||
static inline uint32 mread24l(MFILE *m, int *err)
|
||||
{
|
||||
ptrdiff_t can_read = CAN_READ(m);
|
||||
if (can_read >= 3) {
|
||||
uint32 n = readmem24l(m->start + m->pos);
|
||||
m->pos += 3;
|
||||
if(err) *err = 0;
|
||||
return n;
|
||||
} else {
|
||||
m->pos += can_read;
|
||||
if(err) *err = EOF;
|
||||
return EOF;
|
||||
}
|
||||
}
|
||||
|
||||
static inline uint32 mread24b(MFILE *m, int *err)
|
||||
{
|
||||
ptrdiff_t can_read = CAN_READ(m);
|
||||
if (can_read >= 3) {
|
||||
uint32 n = readmem24b(m->start + m->pos);
|
||||
m->pos += 3;
|
||||
if(err) *err = 0;
|
||||
return n;
|
||||
} else {
|
||||
m->pos += can_read;
|
||||
if(err) *err = EOF;
|
||||
return EOF;
|
||||
}
|
||||
}
|
||||
|
||||
static inline uint32 mread32l(MFILE *m, int *err)
|
||||
{
|
||||
ptrdiff_t can_read = CAN_READ(m);
|
||||
if (can_read >= 4) {
|
||||
uint32 n = readmem32l(m->start + m->pos);
|
||||
m->pos += 4;
|
||||
if(err) *err = 0;
|
||||
return n;
|
||||
} else {
|
||||
m->pos += can_read;
|
||||
if(err) *err = EOF;
|
||||
return EOF;
|
||||
}
|
||||
}
|
||||
|
||||
static inline uint32 mread32b(MFILE *m, int *err)
|
||||
{
|
||||
ptrdiff_t can_read = CAN_READ(m);
|
||||
if (can_read >= 4) {
|
||||
uint32 n = readmem32b(m->start + m->pos);
|
||||
m->pos += 4;
|
||||
if(err) *err = 0;
|
||||
return n;
|
||||
} else {
|
||||
m->pos += can_read;
|
||||
if(err) *err = EOF;
|
||||
return EOF;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
112
internal/c/parts/audio/extras/libxmp-lite/memio.c
Normal file
112
internal/c/parts/audio/extras/libxmp-lite/memio.c
Normal file
|
@ -0,0 +1,112 @@
|
|||
/* Extended Module Player
|
||||
* Copyright (C) 1996-2021 Claudio Matsuoka and Hipolito Carraro Jr
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "memio.h"
|
||||
|
||||
static inline ptrdiff_t CAN_READ(MFILE *m)
|
||||
{
|
||||
return m->pos >= 0 ? m->size - m->pos : 0;
|
||||
}
|
||||
|
||||
|
||||
int mgetc(MFILE *m)
|
||||
{
|
||||
if (CAN_READ(m) >= 1)
|
||||
return *(uint8 *)(m->start + m->pos++);
|
||||
return EOF;
|
||||
}
|
||||
|
||||
size_t mread(void *buf, size_t size, size_t num, MFILE *m)
|
||||
{
|
||||
size_t should_read = size * num;
|
||||
ptrdiff_t can_read = CAN_READ(m);
|
||||
|
||||
if (!size || !num || can_read <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (should_read > can_read) {
|
||||
should_read = can_read;
|
||||
}
|
||||
|
||||
memcpy(buf, m->start + m->pos, should_read);
|
||||
m->pos += should_read;
|
||||
|
||||
return should_read / size;
|
||||
}
|
||||
|
||||
|
||||
int mseek(MFILE *m, long offset, int whence)
|
||||
{
|
||||
ptrdiff_t ofs = offset;
|
||||
|
||||
switch (whence) {
|
||||
case SEEK_SET:
|
||||
break;
|
||||
case SEEK_CUR:
|
||||
ofs += m->pos;
|
||||
break;
|
||||
case SEEK_END:
|
||||
ofs += m->size;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
if (ofs < 0) return -1;
|
||||
if (ofs > m->size)
|
||||
ofs = m->size;
|
||||
m->pos = ofs;
|
||||
return 0;
|
||||
}
|
||||
|
||||
long mtell(MFILE *m)
|
||||
{
|
||||
return (long)m->pos;
|
||||
}
|
||||
|
||||
int meof(MFILE *m)
|
||||
{
|
||||
return CAN_READ(m) <= 0;
|
||||
}
|
||||
|
||||
MFILE *mopen(const void *ptr, long size)
|
||||
{
|
||||
MFILE *m;
|
||||
|
||||
m = (MFILE *)malloc(sizeof (MFILE));
|
||||
if (m == NULL)
|
||||
return NULL;
|
||||
|
||||
m->start = ptr;
|
||||
m->pos = 0;
|
||||
m->size = size;
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
int mclose(MFILE *m)
|
||||
{
|
||||
free(m);
|
||||
return 0;
|
||||
}
|
||||
|
28
internal/c/parts/audio/extras/libxmp-lite/memio.h
Normal file
28
internal/c/parts/audio/extras/libxmp-lite/memio.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
#ifndef LIBXMP_MEMIO_H
|
||||
#define LIBXMP_MEMIO_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
typedef struct {
|
||||
const unsigned char *start;
|
||||
ptrdiff_t pos;
|
||||
ptrdiff_t size;
|
||||
} MFILE;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
MFILE *mopen(const void *, long);
|
||||
int mgetc(MFILE *stream);
|
||||
size_t mread(void *, size_t, size_t, MFILE *);
|
||||
int mseek(MFILE *, long, int);
|
||||
long mtell(MFILE *);
|
||||
int mclose(MFILE *);
|
||||
int meof(MFILE *);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
30
internal/c/parts/audio/extras/libxmp-lite/misc.c
Normal file
30
internal/c/parts/audio/extras/libxmp-lite/misc.c
Normal file
|
@ -0,0 +1,30 @@
|
|||
/* Extended Module Player
|
||||
* Copyright (C) 1996-2021 Claudio Matsuoka and Hipolito Carraro Jr
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include "xmp.h"
|
||||
|
||||
int xmp_syserrno (void)
|
||||
{
|
||||
return errno;
|
||||
}
|
||||
|
439
internal/c/parts/audio/extras/libxmp-lite/mix_all.c
Normal file
439
internal/c/parts/audio/extras/libxmp-lite/mix_all.c
Normal file
|
@ -0,0 +1,439 @@
|
|||
/* Extended Module Player
|
||||
* Copyright (C) 1996-2021 Claudio Matsuoka and Hipolito Carraro Jr
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "virtual.h"
|
||||
#include "mixer.h"
|
||||
#include "precomp_lut.h"
|
||||
|
||||
/* Mixers
|
||||
*
|
||||
* To increase performance eight mixers are defined, one for each
|
||||
* combination of the following parameters: interpolation, resolution
|
||||
* and number of channels.
|
||||
*/
|
||||
#define NEAREST_NEIGHBOR() do { \
|
||||
smp_in = ((int16)sptr[pos] << 8); \
|
||||
} while (0)
|
||||
|
||||
#define NEAREST_NEIGHBOR_16BIT() do { \
|
||||
smp_in = sptr[pos]; \
|
||||
} while (0)
|
||||
|
||||
#define LINEAR_INTERP() do { \
|
||||
smp_l1 = ((int16)sptr[pos] << 8); \
|
||||
smp_dt = ((int16)sptr[pos + 1] << 8) - smp_l1; \
|
||||
smp_in = smp_l1 + (((frac >> 1) * smp_dt) >> (SMIX_SHIFT - 1)); \
|
||||
} while (0)
|
||||
|
||||
#define LINEAR_INTERP_16BIT() do { \
|
||||
smp_l1 = sptr[pos]; \
|
||||
smp_dt = sptr[pos + 1] - smp_l1; \
|
||||
smp_in = smp_l1 + (((frac >> 1) * smp_dt) >> (SMIX_SHIFT - 1)); \
|
||||
} while (0)
|
||||
|
||||
/* The following lut settings are PRECOMPUTED. If you plan on changing these
|
||||
* settings, you MUST also regenerate the arrays.
|
||||
*/
|
||||
/* number of bits used to scale spline coefs */
|
||||
#define SPLINE_QUANTBITS 14
|
||||
#define SPLINE_SHIFT (SPLINE_QUANTBITS)
|
||||
|
||||
/* log2(number) of precalculated splines (range is [4..14]) */
|
||||
#define SPLINE_FRACBITS 10
|
||||
#define SPLINE_LUTLEN (1L<<SPLINE_FRACBITS)
|
||||
|
||||
#define SPLINE_FRACSHIFT ((16 - SPLINE_FRACBITS) - 2)
|
||||
#define SPLINE_FRACMASK (((1L << (16 - SPLINE_FRACSHIFT)) - 1) & ~3)
|
||||
|
||||
#define SPLINE_INTERP() do { \
|
||||
int f = frac >> 6; \
|
||||
smp_in = (cubic_spline_lut0[f] * sptr[(int)pos - 1] + \
|
||||
cubic_spline_lut1[f] * sptr[pos ] + \
|
||||
cubic_spline_lut3[f] * sptr[pos + 2] + \
|
||||
cubic_spline_lut2[f] * sptr[pos + 1]) >> (SPLINE_SHIFT - 8); \
|
||||
} while (0)
|
||||
|
||||
#define SPLINE_INTERP_16BIT() do { \
|
||||
int f = frac >> 6; \
|
||||
smp_in = (cubic_spline_lut0[f] * sptr[(int)pos - 1] + \
|
||||
cubic_spline_lut1[f] * sptr[pos ] + \
|
||||
cubic_spline_lut3[f] * sptr[pos + 2] + \
|
||||
cubic_spline_lut2[f] * sptr[pos + 1]) >> SPLINE_SHIFT; \
|
||||
} while (0)
|
||||
|
||||
#define LOOP_AC for (; count > ramp; count--)
|
||||
|
||||
#define LOOP for (; count; count--)
|
||||
|
||||
#define UPDATE_POS() do { \
|
||||
frac += step; \
|
||||
pos += frac >> SMIX_SHIFT; \
|
||||
frac &= SMIX_MASK; \
|
||||
} while (0)
|
||||
|
||||
#define MIX_MONO() do { \
|
||||
*(buffer++) += smp_in * vl; \
|
||||
} while (0)
|
||||
|
||||
#define MIX_MONO_AC() do { \
|
||||
*(buffer++) += smp_in * (old_vl >> 8); old_vl += delta_l; \
|
||||
} while (0)
|
||||
|
||||
#define MIX_MONO_FILTER() do { \
|
||||
sl = (a0 * smp_in * vl + b0 * fl1 + b1 * fl2) >> FILTER_SHIFT; \
|
||||
fl2 = fl1; fl1 = sl; \
|
||||
*(buffer++) += sl; \
|
||||
} while (0)
|
||||
|
||||
#define MIX_MONO_FILTER_AC() do { \
|
||||
int vl = old_vl >> 8; \
|
||||
MIX_MONO_FILTER(); \
|
||||
old_vl += delta_l; \
|
||||
} while (0)
|
||||
|
||||
#define MIX_STEREO() do { \
|
||||
*(buffer++) += smp_in * vr; \
|
||||
*(buffer++) += smp_in * vl; \
|
||||
} while (0)
|
||||
|
||||
#define MIX_STEREO_AC() do { \
|
||||
*(buffer++) += smp_in * (old_vr >> 8); old_vr += delta_r; \
|
||||
*(buffer++) += smp_in * (old_vl >> 8); old_vl += delta_l; \
|
||||
} while (0)
|
||||
|
||||
#define MIX_STEREO_FILTER() do { \
|
||||
sr = (a0 * smp_in * vr + b0 * fr1 + b1 * fr2) >> FILTER_SHIFT; \
|
||||
fr2 = fr1; fr1 = sr; \
|
||||
sl = (a0 * smp_in * vl + b0 * fl1 + b1 * fl2) >> FILTER_SHIFT; \
|
||||
fl2 = fl1; fl1 = sl; \
|
||||
*(buffer++) += sr; \
|
||||
*(buffer++) += sl; \
|
||||
} while (0)
|
||||
|
||||
#define MIX_STEREO_FILTER_AC() do { \
|
||||
int vr = old_vr >> 8; \
|
||||
int vl = old_vl >> 8; \
|
||||
MIX_STEREO_FILTER(); \
|
||||
old_vr += delta_r; \
|
||||
old_vl += delta_l; \
|
||||
} while (0)
|
||||
|
||||
#define MIX_STEREO_FILTER_AC() do { \
|
||||
int vr = old_vr >> 8; \
|
||||
int vl = old_vl >> 8; \
|
||||
MIX_STEREO_FILTER(); \
|
||||
old_vr += delta_r; \
|
||||
old_vl += delta_l; \
|
||||
} while (0)
|
||||
|
||||
#define VAR_NORM(x) \
|
||||
register int smp_in; \
|
||||
x *sptr = vi->sptr; \
|
||||
unsigned int pos = vi->pos; \
|
||||
int frac = (1 << SMIX_SHIFT) * (vi->pos - (int)vi->pos)
|
||||
|
||||
#define VAR_LINEAR_MONO(x) \
|
||||
VAR_NORM(x); \
|
||||
int old_vl = vi->old_vl; \
|
||||
int smp_l1, smp_dt
|
||||
|
||||
#define VAR_LINEAR_STEREO(x) \
|
||||
VAR_LINEAR_MONO(x); \
|
||||
int old_vr = vi->old_vr
|
||||
|
||||
#define VAR_SPLINE_MONO(x) \
|
||||
int old_vl = vi->old_vl; \
|
||||
VAR_NORM(x)
|
||||
|
||||
#define VAR_SPLINE_STEREO(x) \
|
||||
VAR_SPLINE_MONO(x); \
|
||||
int old_vr = vi->old_vr
|
||||
|
||||
#ifndef LIBXMP_CORE_DISABLE_IT
|
||||
|
||||
#define VAR_FILTER_MONO \
|
||||
int fl1 = vi->filter.l1, fl2 = vi->filter.l2; \
|
||||
int64 a0 = vi->filter.a0, b0 = vi->filter.b0, b1 = vi->filter.b1; \
|
||||
int sl
|
||||
|
||||
#define VAR_FILTER_STEREO \
|
||||
VAR_FILTER_MONO; \
|
||||
int fr1 = vi->filter.r1, fr2 = vi->filter.r2; \
|
||||
int sr
|
||||
|
||||
#define SAVE_FILTER_MONO() do { \
|
||||
vi->filter.l1 = fl1; \
|
||||
vi->filter.l2 = fl2; \
|
||||
} while (0)
|
||||
|
||||
#define SAVE_FILTER_STEREO() do { \
|
||||
SAVE_FILTER_MONO(); \
|
||||
vi->filter.r1 = fr1; \
|
||||
vi->filter.r2 = fr2; \
|
||||
} while (0)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Nearest neighbor mixers
|
||||
*/
|
||||
|
||||
/* Handler for 8 bit samples, nearest neighbor mono output
|
||||
*/
|
||||
MIXER(mono_8bit_nearest)
|
||||
{
|
||||
VAR_NORM(int8);
|
||||
|
||||
LOOP { NEAREST_NEIGHBOR(); MIX_MONO(); UPDATE_POS(); }
|
||||
}
|
||||
|
||||
|
||||
/* Handler for 16 bit samples, nearest neighbor mono output
|
||||
*/
|
||||
MIXER(mono_16bit_nearest)
|
||||
{
|
||||
VAR_NORM(int16);
|
||||
|
||||
LOOP { NEAREST_NEIGHBOR_16BIT(); MIX_MONO(); UPDATE_POS(); }
|
||||
}
|
||||
|
||||
/* Handler for 8 bit samples, nearest neighbor stereo output
|
||||
*/
|
||||
MIXER(stereo_8bit_nearest)
|
||||
{
|
||||
VAR_NORM(int8);
|
||||
|
||||
LOOP { NEAREST_NEIGHBOR(); MIX_STEREO(); UPDATE_POS(); }
|
||||
}
|
||||
|
||||
/* Handler for 16 bit samples, nearest neighbor stereo output
|
||||
*/
|
||||
MIXER(stereo_16bit_nearest)
|
||||
{
|
||||
VAR_NORM(int16);
|
||||
|
||||
LOOP { NEAREST_NEIGHBOR_16BIT(); MIX_STEREO(); UPDATE_POS(); }
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Linear mixers
|
||||
*/
|
||||
|
||||
/* Handler for 8 bit samples, linear interpolated mono output
|
||||
*/
|
||||
MIXER(mono_8bit_linear)
|
||||
{
|
||||
VAR_LINEAR_MONO(int8);
|
||||
|
||||
LOOP_AC { LINEAR_INTERP(); MIX_MONO_AC(); UPDATE_POS(); }
|
||||
LOOP { LINEAR_INTERP(); MIX_MONO(); UPDATE_POS(); }
|
||||
}
|
||||
|
||||
/* Handler for 16 bit samples, linear interpolated mono output
|
||||
*/
|
||||
MIXER(mono_16bit_linear)
|
||||
{
|
||||
VAR_LINEAR_MONO(int16);
|
||||
|
||||
LOOP_AC { LINEAR_INTERP_16BIT(); MIX_MONO_AC(); UPDATE_POS(); }
|
||||
LOOP { LINEAR_INTERP_16BIT(); MIX_MONO(); UPDATE_POS(); }
|
||||
}
|
||||
|
||||
/* Handler for 8 bit samples, linear interpolated stereo output
|
||||
*/
|
||||
MIXER(stereo_8bit_linear)
|
||||
{
|
||||
VAR_LINEAR_STEREO(int8);
|
||||
|
||||
LOOP_AC { LINEAR_INTERP(); MIX_STEREO_AC(); UPDATE_POS(); }
|
||||
LOOP { LINEAR_INTERP(); MIX_STEREO(); UPDATE_POS(); }
|
||||
}
|
||||
|
||||
/* Handler for 16 bit samples, linear interpolated stereo output
|
||||
*/
|
||||
MIXER(stereo_16bit_linear)
|
||||
{
|
||||
VAR_LINEAR_STEREO(int16);
|
||||
|
||||
LOOP_AC { LINEAR_INTERP_16BIT(); MIX_STEREO_AC(); UPDATE_POS(); }
|
||||
LOOP { LINEAR_INTERP_16BIT(); MIX_STEREO(); UPDATE_POS(); }
|
||||
}
|
||||
|
||||
|
||||
#ifndef LIBXMP_CORE_DISABLE_IT
|
||||
|
||||
/* Handler for 8 bit samples, filtered linear interpolated mono output
|
||||
*/
|
||||
MIXER(mono_8bit_linear_filter)
|
||||
{
|
||||
VAR_LINEAR_MONO(int8);
|
||||
VAR_FILTER_MONO;
|
||||
|
||||
LOOP_AC { LINEAR_INTERP(); MIX_MONO_FILTER_AC(); UPDATE_POS(); }
|
||||
LOOP { LINEAR_INTERP(); MIX_MONO_FILTER(); UPDATE_POS(); }
|
||||
|
||||
SAVE_FILTER_MONO();
|
||||
}
|
||||
|
||||
/* Handler for 16 bit samples, filtered linear interpolated mono output
|
||||
*/
|
||||
MIXER(mono_16bit_linear_filter)
|
||||
{
|
||||
VAR_LINEAR_MONO(int16);
|
||||
VAR_FILTER_MONO;
|
||||
|
||||
LOOP_AC { LINEAR_INTERP_16BIT(); MIX_MONO_FILTER_AC(); UPDATE_POS(); }
|
||||
LOOP { LINEAR_INTERP_16BIT(); MIX_MONO_FILTER(); UPDATE_POS(); }
|
||||
|
||||
SAVE_FILTER_MONO();
|
||||
}
|
||||
|
||||
/* Handler for 8 bit samples, filtered linear interpolated stereo output
|
||||
*/
|
||||
MIXER(stereo_8bit_linear_filter)
|
||||
{
|
||||
VAR_LINEAR_STEREO(int8);
|
||||
VAR_FILTER_STEREO;
|
||||
|
||||
LOOP_AC { LINEAR_INTERP(); MIX_STEREO_FILTER_AC(); UPDATE_POS(); }
|
||||
LOOP { LINEAR_INTERP(); MIX_STEREO_FILTER(); UPDATE_POS(); }
|
||||
|
||||
SAVE_FILTER_STEREO();
|
||||
}
|
||||
|
||||
/* Handler for 16 bit samples, filtered linear interpolated stereo output
|
||||
*/
|
||||
MIXER(stereo_16bit_linear_filter)
|
||||
{
|
||||
VAR_LINEAR_STEREO(int16);
|
||||
VAR_FILTER_STEREO;
|
||||
|
||||
LOOP_AC { LINEAR_INTERP_16BIT(); MIX_STEREO_FILTER_AC(); UPDATE_POS(); }
|
||||
LOOP { LINEAR_INTERP_16BIT(); MIX_STEREO_FILTER(); UPDATE_POS(); }
|
||||
|
||||
SAVE_FILTER_STEREO();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Spline mixers
|
||||
*/
|
||||
|
||||
/* Handler for 8 bit samples, spline interpolated mono output
|
||||
*/
|
||||
MIXER(mono_8bit_spline)
|
||||
{
|
||||
VAR_SPLINE_MONO(int8);
|
||||
|
||||
LOOP_AC { SPLINE_INTERP(); MIX_MONO_AC(); UPDATE_POS(); }
|
||||
LOOP { SPLINE_INTERP(); MIX_MONO(); UPDATE_POS(); }
|
||||
}
|
||||
|
||||
/* Handler for 16 bit samples, spline interpolated mono output
|
||||
*/
|
||||
MIXER(mono_16bit_spline)
|
||||
{
|
||||
VAR_SPLINE_MONO(int16);
|
||||
|
||||
LOOP_AC { SPLINE_INTERP_16BIT(); MIX_MONO_AC(); UPDATE_POS(); }
|
||||
LOOP { SPLINE_INTERP_16BIT(); MIX_MONO(); UPDATE_POS(); }
|
||||
}
|
||||
|
||||
/* Handler for 8 bit samples, spline interpolated stereo output
|
||||
*/
|
||||
MIXER(stereo_8bit_spline)
|
||||
{
|
||||
VAR_SPLINE_STEREO(int8);
|
||||
|
||||
LOOP_AC { SPLINE_INTERP(); MIX_STEREO_AC(); UPDATE_POS(); }
|
||||
LOOP { SPLINE_INTERP(); MIX_STEREO(); UPDATE_POS(); }
|
||||
}
|
||||
|
||||
/* Handler for 16 bit samples, spline interpolated stereo output
|
||||
*/
|
||||
MIXER(stereo_16bit_spline)
|
||||
{
|
||||
VAR_SPLINE_STEREO(int16);
|
||||
|
||||
LOOP_AC { SPLINE_INTERP_16BIT(); MIX_STEREO_AC(); UPDATE_POS(); }
|
||||
LOOP { SPLINE_INTERP_16BIT(); MIX_STEREO(); UPDATE_POS(); }
|
||||
}
|
||||
|
||||
#ifndef LIBXMP_CORE_DISABLE_IT
|
||||
|
||||
/* Handler for 8 bit samples, filtered spline interpolated mono output
|
||||
*/
|
||||
MIXER(mono_8bit_spline_filter)
|
||||
{
|
||||
VAR_SPLINE_MONO(int8);
|
||||
VAR_FILTER_MONO;
|
||||
|
||||
LOOP_AC { SPLINE_INTERP(); MIX_MONO_FILTER_AC(); UPDATE_POS(); }
|
||||
LOOP { SPLINE_INTERP(); MIX_MONO_FILTER(); UPDATE_POS(); }
|
||||
|
||||
SAVE_FILTER_MONO();
|
||||
}
|
||||
|
||||
/* Handler for 16 bit samples, filtered spline interpolated mono output
|
||||
*/
|
||||
MIXER(mono_16bit_spline_filter)
|
||||
{
|
||||
VAR_SPLINE_MONO(int16);
|
||||
VAR_FILTER_MONO;
|
||||
|
||||
LOOP_AC { SPLINE_INTERP_16BIT(); MIX_MONO_FILTER_AC(); UPDATE_POS(); }
|
||||
LOOP { SPLINE_INTERP_16BIT(); MIX_MONO_FILTER(); UPDATE_POS(); }
|
||||
|
||||
SAVE_FILTER_MONO();
|
||||
}
|
||||
|
||||
/* Handler for 8 bit samples, filtered spline interpolated stereo output
|
||||
*/
|
||||
MIXER(stereo_8bit_spline_filter)
|
||||
{
|
||||
VAR_SPLINE_STEREO(int8);
|
||||
VAR_FILTER_STEREO;
|
||||
|
||||
LOOP_AC { SPLINE_INTERP(); MIX_STEREO_FILTER_AC(); UPDATE_POS(); }
|
||||
LOOP { SPLINE_INTERP(); MIX_STEREO_FILTER(); UPDATE_POS(); }
|
||||
|
||||
SAVE_FILTER_STEREO();
|
||||
}
|
||||
|
||||
/* Handler for 16 bit samples, filtered spline interpolated stereo output
|
||||
*/
|
||||
MIXER(stereo_16bit_spline_filter)
|
||||
{
|
||||
VAR_SPLINE_STEREO(int16);
|
||||
VAR_FILTER_STEREO;
|
||||
|
||||
LOOP_AC { SPLINE_INTERP_16BIT(); MIX_STEREO_FILTER_AC(); UPDATE_POS(); }
|
||||
LOOP { SPLINE_INTERP_16BIT(); MIX_STEREO_FILTER(); UPDATE_POS(); }
|
||||
|
||||
SAVE_FILTER_STEREO();
|
||||
}
|
||||
|
||||
#endif
|
839
internal/c/parts/audio/extras/libxmp-lite/mixer.c
Normal file
839
internal/c/parts/audio/extras/libxmp-lite/mixer.c
Normal file
|
@ -0,0 +1,839 @@
|
|||
/* Extended Module Player
|
||||
* Copyright (C) 1996-2021 Claudio Matsuoka and Hipolito Carraro Jr
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include "common.h"
|
||||
#include "virtual.h"
|
||||
#include "mixer.h"
|
||||
#include "period.h"
|
||||
#include "player.h" /* for set_sample_end() */
|
||||
|
||||
#ifdef LIBXMP_PAULA_SIMULATOR
|
||||
#include "paula.h"
|
||||
#endif
|
||||
|
||||
|
||||
#define FLAG_16_BITS 0x01
|
||||
#define FLAG_STEREO 0x02
|
||||
#define FLAG_FILTER 0x04
|
||||
#define FLAG_ACTIVE 0x10
|
||||
/* #define FLAG_SYNTH 0x20 */
|
||||
#define FIDX_FLAGMASK (FLAG_16_BITS | FLAG_STEREO | FLAG_FILTER)
|
||||
|
||||
#define DOWNMIX_SHIFT 12
|
||||
#define LIM8_HI 127
|
||||
#define LIM8_LO -128
|
||||
#define LIM16_HI 32767
|
||||
#define LIM16_LO -32768
|
||||
|
||||
#define MIX_FN(x) void libxmp_mix_##x(struct mixer_voice *, int32 *, int, int, int, int, int, int, int)
|
||||
|
||||
MIX_FN(mono_8bit_nearest);
|
||||
MIX_FN(mono_8bit_linear);
|
||||
MIX_FN(mono_16bit_nearest);
|
||||
MIX_FN(mono_16bit_linear);
|
||||
MIX_FN(stereo_8bit_nearest);
|
||||
MIX_FN(stereo_8bit_linear);
|
||||
MIX_FN(stereo_16bit_nearest);
|
||||
MIX_FN(stereo_16bit_linear);
|
||||
MIX_FN(mono_8bit_spline);
|
||||
MIX_FN(mono_16bit_spline);
|
||||
MIX_FN(stereo_8bit_spline);
|
||||
MIX_FN(stereo_16bit_spline);
|
||||
|
||||
#ifndef LIBXMP_CORE_DISABLE_IT
|
||||
MIX_FN(mono_8bit_linear_filter);
|
||||
MIX_FN(mono_16bit_linear_filter);
|
||||
MIX_FN(stereo_8bit_linear_filter);
|
||||
MIX_FN(stereo_16bit_linear_filter);
|
||||
MIX_FN(mono_8bit_spline_filter);
|
||||
MIX_FN(mono_16bit_spline_filter);
|
||||
MIX_FN(stereo_8bit_spline_filter);
|
||||
MIX_FN(stereo_16bit_spline_filter);
|
||||
#endif
|
||||
|
||||
#ifdef LIBXMP_PAULA_SIMULATOR
|
||||
MIX_FN(mono_a500);
|
||||
MIX_FN(mono_a500_filter);
|
||||
MIX_FN(stereo_a500);
|
||||
MIX_FN(stereo_a500_filter);
|
||||
#endif
|
||||
|
||||
/* Mixers array index:
|
||||
*
|
||||
* bit 0: 0=8 bit sample, 1=16 bit sample
|
||||
* bit 1: 0=mono output, 1=stereo output
|
||||
* bit 2: 0=unfiltered, 1=filtered
|
||||
*/
|
||||
|
||||
typedef void (*MIX_FP) (struct mixer_voice *, int32 *, int, int, int, int, int, int, int);
|
||||
|
||||
static MIX_FP nearest_mixers[] = {
|
||||
libxmp_mix_mono_8bit_nearest,
|
||||
libxmp_mix_mono_16bit_nearest,
|
||||
libxmp_mix_stereo_8bit_nearest,
|
||||
libxmp_mix_stereo_16bit_nearest,
|
||||
|
||||
#ifndef LIBXMP_CORE_DISABLE_IT
|
||||
libxmp_mix_mono_8bit_nearest,
|
||||
libxmp_mix_mono_16bit_nearest,
|
||||
libxmp_mix_stereo_8bit_nearest,
|
||||
libxmp_mix_stereo_16bit_nearest,
|
||||
#endif
|
||||
};
|
||||
|
||||
static MIX_FP linear_mixers[] = {
|
||||
libxmp_mix_mono_8bit_linear,
|
||||
libxmp_mix_mono_16bit_linear,
|
||||
libxmp_mix_stereo_8bit_linear,
|
||||
libxmp_mix_stereo_16bit_linear,
|
||||
|
||||
#ifndef LIBXMP_CORE_DISABLE_IT
|
||||
libxmp_mix_mono_8bit_linear_filter,
|
||||
libxmp_mix_mono_16bit_linear_filter,
|
||||
libxmp_mix_stereo_8bit_linear_filter,
|
||||
libxmp_mix_stereo_16bit_linear_filter
|
||||
#endif
|
||||
};
|
||||
|
||||
static MIX_FP spline_mixers[] = {
|
||||
libxmp_mix_mono_8bit_spline,
|
||||
libxmp_mix_mono_16bit_spline,
|
||||
libxmp_mix_stereo_8bit_spline,
|
||||
libxmp_mix_stereo_16bit_spline,
|
||||
|
||||
#ifndef LIBXMP_CORE_DISABLE_IT
|
||||
libxmp_mix_mono_8bit_spline_filter,
|
||||
libxmp_mix_mono_16bit_spline_filter,
|
||||
libxmp_mix_stereo_8bit_spline_filter,
|
||||
libxmp_mix_stereo_16bit_spline_filter
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef LIBXMP_PAULA_SIMULATOR
|
||||
static MIX_FP a500_mixers[] = {
|
||||
libxmp_mix_mono_a500,
|
||||
NULL,
|
||||
libxmp_mix_stereo_a500,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
static MIX_FP a500led_mixers[] = {
|
||||
libxmp_mix_mono_a500_filter,
|
||||
NULL,
|
||||
libxmp_mix_stereo_a500_filter,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
/* Downmix 32bit samples to 8bit, signed or unsigned, mono or stereo output */
|
||||
static void downmix_int_8bit(char *dest, int32 *src, int num, int amp, int offs)
|
||||
{
|
||||
int smp;
|
||||
int shift = DOWNMIX_SHIFT + 8 - amp;
|
||||
|
||||
for (; num--; src++, dest++) {
|
||||
smp = *src >> shift;
|
||||
if (smp > LIM8_HI) {
|
||||
*dest = LIM8_HI;
|
||||
} else if (smp < LIM8_LO) {
|
||||
*dest = LIM8_LO;
|
||||
} else {
|
||||
*dest = smp;
|
||||
}
|
||||
|
||||
if (offs) *dest += offs;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Downmix 32bit samples to 16bit, signed or unsigned, mono or stereo output */
|
||||
static void downmix_int_16bit(int16 *dest, int32 *src, int num, int amp, int offs)
|
||||
{
|
||||
int smp;
|
||||
int shift = DOWNMIX_SHIFT - amp;
|
||||
|
||||
for (; num--; src++, dest++) {
|
||||
smp = *src >> shift;
|
||||
if (smp > LIM16_HI) {
|
||||
*dest = LIM16_HI;
|
||||
} else if (smp < LIM16_LO) {
|
||||
*dest = LIM16_LO;
|
||||
} else {
|
||||
*dest = smp;
|
||||
}
|
||||
|
||||
if (offs) *dest += offs;
|
||||
}
|
||||
}
|
||||
|
||||
static void anticlick(struct mixer_voice *vi)
|
||||
{
|
||||
vi->flags |= ANTICLICK;
|
||||
vi->old_vl = 0;
|
||||
vi->old_vr = 0;
|
||||
}
|
||||
|
||||
/* Ok, it's messy, but it works :-) Hipolito */
|
||||
static void do_anticlick(struct context_data *ctx, int voc, int32 *buf, int count)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
struct mixer_data *s = &ctx->s;
|
||||
struct mixer_voice *vi = &p->virt.voice_array[voc];
|
||||
int smp_l, smp_r, max_x2;
|
||||
int discharge = s->ticksize >> ANTICLICK_SHIFT;
|
||||
|
||||
smp_r = vi->sright;
|
||||
smp_l = vi->sleft;
|
||||
vi->sright = vi->sleft = 0;
|
||||
|
||||
if (smp_l == 0 && smp_r == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (buf == NULL) {
|
||||
buf = s->buf32;
|
||||
count = discharge;
|
||||
} else if (count > discharge) {
|
||||
count = discharge;
|
||||
}
|
||||
|
||||
if (count <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
max_x2 = count * count;
|
||||
|
||||
while (count--) {
|
||||
if (~s->format & XMP_FORMAT_MONO) {
|
||||
*buf++ += (count * (smp_r >> 10) / max_x2 * count) << 10;
|
||||
}
|
||||
|
||||
*buf++ += (count * (smp_l >> 10) / max_x2 * count) << 10;
|
||||
}
|
||||
}
|
||||
|
||||
static void set_sample_end(struct context_data *ctx, int voc, int end)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
struct module_data *m = &ctx->m;
|
||||
struct mixer_voice *vi = &p->virt.voice_array[voc];
|
||||
struct channel_data *xc;
|
||||
|
||||
if ((uint32)voc >= p->virt.maxvoc)
|
||||
return;
|
||||
|
||||
xc = &p->xc_data[vi->chn];
|
||||
|
||||
if (end) {
|
||||
SET_NOTE(NOTE_SAMPLE_END);
|
||||
if (HAS_QUIRK(QUIRK_RSTCHN)) {
|
||||
libxmp_virt_resetvoice(ctx, voc, 0);
|
||||
}
|
||||
} else {
|
||||
RESET_NOTE(NOTE_SAMPLE_END);
|
||||
}
|
||||
}
|
||||
|
||||
static void adjust_voice_end(struct mixer_voice *vi, struct xmp_sample *xxs)
|
||||
{
|
||||
if (xxs->flg & XMP_SAMPLE_LOOP) {
|
||||
if ((xxs->flg & XMP_SAMPLE_LOOP_FULL) && (~vi->flags & SAMPLE_LOOP)) {
|
||||
vi->end = xxs->len;
|
||||
} else {
|
||||
vi->end = xxs->lpe;
|
||||
}
|
||||
} else {
|
||||
vi->end = xxs->len;
|
||||
}
|
||||
}
|
||||
|
||||
static void loop_reposition(struct context_data *ctx, struct mixer_voice *vi, struct xmp_sample *xxs)
|
||||
{
|
||||
#ifndef LIBXMP_CORE_DISABLE_IT
|
||||
struct module_data *m = &ctx->m;
|
||||
#endif
|
||||
int loop_size = xxs->lpe - xxs->lps;
|
||||
|
||||
/* Reposition for next loop */
|
||||
vi->pos -= loop_size; /* forward loop */
|
||||
vi->end = xxs->lpe;
|
||||
vi->flags |= SAMPLE_LOOP;
|
||||
|
||||
if (xxs->flg & XMP_SAMPLE_LOOP_BIDIR) {
|
||||
vi->end += loop_size; /* unrolled loop */
|
||||
vi->pos -= loop_size; /* forward loop */
|
||||
|
||||
#ifndef LIBXMP_CORE_DISABLE_IT
|
||||
/* OpenMPT Bidi-Loops.it: "In Impulse Tracker’s software mixer,
|
||||
* ping-pong loops are shortened by one sample.
|
||||
*/
|
||||
if (IS_PLAYER_MODE_IT()) {
|
||||
vi->end--;
|
||||
vi->pos++;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Prepare the mixer for the next tick */
|
||||
void libxmp_mixer_prepare(struct context_data *ctx)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
struct module_data *m = &ctx->m;
|
||||
struct mixer_data *s = &ctx->s;
|
||||
int bytelen;
|
||||
|
||||
s->ticksize = s->freq * m->time_factor * m->rrate / p->bpm / 1000;
|
||||
|
||||
bytelen = s->ticksize * sizeof(int);
|
||||
if (~s->format & XMP_FORMAT_MONO) {
|
||||
bytelen *= 2;
|
||||
}
|
||||
memset(s->buf32, 0, bytelen);
|
||||
}
|
||||
/* Fill the output buffer calling one of the handlers. The buffer contains
|
||||
* sound for one tick (a PAL frame or 1/50s for standard vblank-timed mods)
|
||||
*/
|
||||
void libxmp_mixer_softmixer(struct context_data *ctx)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
struct mixer_data *s = &ctx->s;
|
||||
struct module_data *m = &ctx->m;
|
||||
struct xmp_module *mod = &m->mod;
|
||||
struct xmp_sample *xxs;
|
||||
struct mixer_voice *vi;
|
||||
double step;
|
||||
int samples, size;
|
||||
int vol_l, vol_r, voc, usmp;
|
||||
int prev_l, prev_r = 0;
|
||||
int lps, lpe;
|
||||
int32 *buf_pos;
|
||||
MIX_FP mix_fn;
|
||||
MIX_FP *mixerset;
|
||||
|
||||
switch (s->interp) {
|
||||
case XMP_INTERP_NEAREST:
|
||||
mixerset = nearest_mixers;
|
||||
break;
|
||||
case XMP_INTERP_LINEAR:
|
||||
mixerset = linear_mixers;
|
||||
break;
|
||||
case XMP_INTERP_SPLINE:
|
||||
mixerset = spline_mixers;
|
||||
break;
|
||||
default:
|
||||
mixerset = linear_mixers;
|
||||
}
|
||||
|
||||
#ifdef LIBXMP_PAULA_SIMULATOR
|
||||
if (p->flags & XMP_FLAGS_A500) {
|
||||
if (IS_AMIGA_MOD()) {
|
||||
if (p->filter) {
|
||||
mixerset = a500led_mixers;
|
||||
} else {
|
||||
mixerset = a500_mixers;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
libxmp_mixer_prepare(ctx);
|
||||
|
||||
for (voc = 0; voc < p->virt.maxvoc; voc++) {
|
||||
int c5spd, rampsize, delta_l, delta_r;
|
||||
|
||||
vi = &p->virt.voice_array[voc];
|
||||
|
||||
if (vi->flags & ANTICLICK) {
|
||||
if (s->interp > XMP_INTERP_NEAREST) {
|
||||
do_anticlick(ctx, voc, NULL, 0);
|
||||
}
|
||||
vi->flags &= ~ANTICLICK;
|
||||
}
|
||||
|
||||
if (vi->chn < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (vi->period < 1) {
|
||||
libxmp_virt_resetvoice(ctx, voc, 1);
|
||||
continue;
|
||||
}
|
||||
|
||||
vi->pos0 = vi->pos;
|
||||
|
||||
buf_pos = s->buf32;
|
||||
if (vi->pan == PAN_SURROUND) {
|
||||
vol_r = vi->vol * 0x80;
|
||||
vol_l = -vi->vol * 0x80;
|
||||
} else {
|
||||
vol_r = vi->vol * (0x80 - vi->pan);
|
||||
vol_l = vi->vol * (0x80 + vi->pan);
|
||||
}
|
||||
|
||||
if (vi->smp < mod->smp) {
|
||||
xxs = &mod->xxs[vi->smp];
|
||||
c5spd = m->xtra[vi->smp].c5spd;
|
||||
} else {
|
||||
xxs = &ctx->smix.xxs[vi->smp - mod->smp];
|
||||
c5spd = m->c4rate;
|
||||
}
|
||||
|
||||
step = C4_PERIOD * c5spd / s->freq / vi->period;
|
||||
|
||||
if (step < 0.001) { /* otherwise m5v-nwlf.it crashes */
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifndef LIBXMP_CORE_DISABLE_IT
|
||||
if (xxs->flg & XMP_SAMPLE_SLOOP && vi->smp < mod->smp) {
|
||||
if (~vi->flags & VOICE_RELEASE) {
|
||||
if (vi->pos < m->xsmp[vi->smp].lpe) {
|
||||
xxs = &m->xsmp[vi->smp];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
adjust_voice_end(vi, xxs);
|
||||
#endif
|
||||
|
||||
lps = xxs->lps;
|
||||
lpe = xxs->lpe;
|
||||
|
||||
if (p->flags & XMP_FLAGS_FIXLOOP) {
|
||||
lps >>= 1;
|
||||
}
|
||||
|
||||
if (xxs->flg & XMP_SAMPLE_LOOP_BIDIR) {
|
||||
vi->end += lpe - lps;
|
||||
|
||||
#ifndef LIBXMP_CORE_DISABLE_IT
|
||||
if (IS_PLAYER_MODE_IT()) {
|
||||
vi->end--;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
rampsize = s->ticksize >> ANTICLICK_SHIFT;
|
||||
delta_l = (vol_l - vi->old_vl) / rampsize;
|
||||
delta_r = (vol_r - vi->old_vr) / rampsize;
|
||||
|
||||
usmp = 0;
|
||||
for (size = s->ticksize; size > 0; ) {
|
||||
int split_noloop = 0;
|
||||
|
||||
if (p->xc_data[vi->chn].split) {
|
||||
split_noloop = 1;
|
||||
}
|
||||
|
||||
/* How many samples we can write before the loop break
|
||||
* or sample end... */
|
||||
if (vi->pos >= vi->end) {
|
||||
samples = 0;
|
||||
usmp = 1;
|
||||
} else {
|
||||
int s = ceil(((double)vi->end - vi->pos) / step);
|
||||
/* ...inside the tick boundaries */
|
||||
if (s > size) {
|
||||
s = size;
|
||||
}
|
||||
|
||||
samples = s;
|
||||
if (samples > 0) {
|
||||
usmp = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (vi->vol) {
|
||||
int mix_size = samples;
|
||||
int mixer_id = vi->fidx & FIDX_FLAGMASK;
|
||||
|
||||
if (~s->format & XMP_FORMAT_MONO) {
|
||||
mix_size *= 2;
|
||||
}
|
||||
|
||||
/* For Hipolito's anticlick routine */
|
||||
if (samples > 0) {
|
||||
if (~s->format & XMP_FORMAT_MONO) {
|
||||
prev_r = buf_pos[mix_size - 2];
|
||||
}
|
||||
prev_l = buf_pos[mix_size - 1];
|
||||
} else {
|
||||
prev_r = prev_l = 0;
|
||||
}
|
||||
|
||||
#ifndef LIBXMP_CORE_DISABLE_IT
|
||||
/* See OpenMPT env-flt-max.it */
|
||||
if (vi->filter.cutoff >= 0xfe &&
|
||||
vi->filter.resonance == 0) {
|
||||
mixer_id &= ~FLAG_FILTER;
|
||||
}
|
||||
#endif
|
||||
|
||||
mix_fn = mixerset[mixer_id];
|
||||
|
||||
/* Call the output handler */
|
||||
if (samples > 0 && vi->sptr != NULL) {
|
||||
int rsize = 0;
|
||||
|
||||
if (rampsize > samples) {
|
||||
rampsize -= samples;
|
||||
} else {
|
||||
rsize = samples - rampsize;
|
||||
rampsize = 0;
|
||||
}
|
||||
|
||||
if (delta_l == 0 && delta_r == 0) {
|
||||
/* no need to ramp */
|
||||
rsize = samples;
|
||||
}
|
||||
|
||||
if (mix_fn != NULL) {
|
||||
mix_fn(vi, buf_pos, samples,
|
||||
vol_l >> 8, vol_r >> 8, step * (1 << SMIX_SHIFT), rsize, delta_l, delta_r);
|
||||
}
|
||||
|
||||
buf_pos += mix_size;
|
||||
vi->old_vl += samples * delta_l;
|
||||
vi->old_vr += samples * delta_r;
|
||||
|
||||
|
||||
/* For Hipolito's anticlick routine */
|
||||
if (~s->format & XMP_FORMAT_MONO) {
|
||||
vi->sright = buf_pos[-2] - prev_r;
|
||||
}
|
||||
vi->sleft = buf_pos[-1] - prev_l;
|
||||
}
|
||||
}
|
||||
|
||||
vi->pos += step * samples;
|
||||
|
||||
/* No more samples in this tick */
|
||||
size -= samples + usmp;
|
||||
if (size <= 0) {
|
||||
if (xxs->flg & XMP_SAMPLE_LOOP) {
|
||||
if (vi->pos + step > vi->end) {
|
||||
vi->pos += step;
|
||||
loop_reposition(ctx, vi, xxs);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/* First sample loop run */
|
||||
if ((~xxs->flg & XMP_SAMPLE_LOOP) || split_noloop) {
|
||||
do_anticlick(ctx, voc, buf_pos, size);
|
||||
set_sample_end(ctx, voc, 1);
|
||||
size = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
loop_reposition(ctx, vi, xxs);
|
||||
}
|
||||
|
||||
vi->old_vl = vol_l;
|
||||
vi->old_vr = vol_r;
|
||||
}
|
||||
|
||||
/* Render final frame */
|
||||
|
||||
size = s->ticksize;
|
||||
if (~s->format & XMP_FORMAT_MONO) {
|
||||
size *= 2;
|
||||
}
|
||||
|
||||
if (size > XMP_MAX_FRAMESIZE) {
|
||||
size = XMP_MAX_FRAMESIZE;
|
||||
}
|
||||
|
||||
if (s->format & XMP_FORMAT_8BIT) {
|
||||
downmix_int_8bit(s->buffer, s->buf32, size, s->amplify,
|
||||
s->format & XMP_FORMAT_UNSIGNED ? 0x80 : 0);
|
||||
} else {
|
||||
downmix_int_16bit((int16 *)s->buffer, s->buf32, size,s->amplify,
|
||||
s->format & XMP_FORMAT_UNSIGNED ? 0x8000 : 0);
|
||||
}
|
||||
|
||||
s->dtright = s->dtleft = 0;
|
||||
}
|
||||
|
||||
void libxmp_mixer_voicepos(struct context_data *ctx, int voc, double pos, int ac)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
struct module_data *m = &ctx->m;
|
||||
struct mixer_voice *vi = &p->virt.voice_array[voc];
|
||||
struct xmp_sample *xxs;
|
||||
int lps;
|
||||
|
||||
if (vi->smp < m->mod.smp) {
|
||||
xxs = &m->mod.xxs[vi->smp];
|
||||
} else {
|
||||
xxs = &ctx->smix.xxs[vi->smp - m->mod.smp];
|
||||
}
|
||||
|
||||
if (xxs->flg & XMP_SAMPLE_SYNTH) {
|
||||
return;
|
||||
}
|
||||
|
||||
vi->pos = pos;
|
||||
|
||||
adjust_voice_end(vi, xxs);
|
||||
|
||||
if (vi->pos >= vi->end) {
|
||||
if (xxs->flg & XMP_SAMPLE_LOOP) {
|
||||
vi->pos = xxs->lps;
|
||||
} else {
|
||||
vi->pos = xxs->len;
|
||||
}
|
||||
}
|
||||
|
||||
lps = xxs->lps;
|
||||
if (p->flags & XMP_FLAGS_FIXLOOP) {
|
||||
lps >>= 1;
|
||||
}
|
||||
|
||||
if (xxs->flg & XMP_SAMPLE_LOOP_BIDIR) {
|
||||
vi->end += (xxs->lpe - lps);
|
||||
|
||||
#ifndef LIBXMP_CORE_DISABLE_IT
|
||||
if (IS_PLAYER_MODE_IT()) {
|
||||
vi->end--;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (ac) {
|
||||
anticlick(vi);
|
||||
}
|
||||
}
|
||||
|
||||
double libxmp_mixer_getvoicepos(struct context_data *ctx, int voc)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
struct mixer_voice *vi = &p->virt.voice_array[voc];
|
||||
struct xmp_sample *xxs;
|
||||
|
||||
xxs = libxmp_get_sample(ctx, vi->smp);
|
||||
|
||||
if (xxs->flg & XMP_SAMPLE_SYNTH) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (xxs->flg & XMP_SAMPLE_LOOP_BIDIR) {
|
||||
if (vi->pos >= xxs->lpe) {
|
||||
return xxs->lpe - (vi->pos - xxs->lpe) - 1;
|
||||
}
|
||||
}
|
||||
|
||||
return vi->pos;
|
||||
}
|
||||
|
||||
void libxmp_mixer_setpatch(struct context_data *ctx, int voc, int smp, int ac)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
#ifndef LIBXMP_CORE_DISABLE_IT
|
||||
struct module_data *m = &ctx->m;
|
||||
#endif
|
||||
struct mixer_data *s = &ctx->s;
|
||||
struct mixer_voice *vi = &p->virt.voice_array[voc];
|
||||
struct xmp_sample *xxs;
|
||||
|
||||
xxs = libxmp_get_sample(ctx, smp);
|
||||
|
||||
vi->smp = smp;
|
||||
vi->vol = 0;
|
||||
vi->pan = 0;
|
||||
vi->flags &= ~SAMPLE_LOOP;
|
||||
|
||||
vi->fidx = 0;
|
||||
|
||||
if (~s->format & XMP_FORMAT_MONO) {
|
||||
vi->fidx |= FLAG_STEREO;
|
||||
}
|
||||
|
||||
set_sample_end(ctx, voc, 0);
|
||||
|
||||
/*mixer_setvol(ctx, voc, 0);*/
|
||||
|
||||
vi->sptr = xxs->data;
|
||||
vi->fidx |= FLAG_ACTIVE;
|
||||
|
||||
#ifndef LIBXMP_CORE_DISABLE_IT
|
||||
if (HAS_QUIRK(QUIRK_FILTER) && s->dsp & XMP_DSP_LOWPASS) {
|
||||
vi->fidx |= FLAG_FILTER;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (xxs->flg & XMP_SAMPLE_16BIT) {
|
||||
vi->fidx |= FLAG_16_BITS;
|
||||
}
|
||||
|
||||
libxmp_mixer_voicepos(ctx, voc, 0, ac);
|
||||
}
|
||||
|
||||
void libxmp_mixer_setnote(struct context_data *ctx, int voc, int note)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
struct mixer_voice *vi = &p->virt.voice_array[voc];
|
||||
|
||||
/* FIXME: Workaround for crash on notes that are too high
|
||||
* see 6nations.it (+114 transposition on instrument 16)
|
||||
*/
|
||||
if (note > 149) {
|
||||
note = 149;
|
||||
}
|
||||
|
||||
vi->note = note;
|
||||
vi->period = libxmp_note_to_period_mix(note, 0);
|
||||
|
||||
anticlick(vi);
|
||||
}
|
||||
|
||||
void libxmp_mixer_setperiod(struct context_data *ctx, int voc, double period)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
struct mixer_voice *vi = &p->virt.voice_array[voc];
|
||||
|
||||
vi->period = period;
|
||||
}
|
||||
|
||||
void libxmp_mixer_setvol(struct context_data *ctx, int voc, int vol)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
struct mixer_voice *vi = &p->virt.voice_array[voc];
|
||||
|
||||
if (vol == 0) {
|
||||
anticlick(vi);
|
||||
}
|
||||
|
||||
vi->vol = vol;
|
||||
}
|
||||
|
||||
void libxmp_mixer_release(struct context_data *ctx, int voc, int rel)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
struct mixer_voice *vi = &p->virt.voice_array[voc];
|
||||
|
||||
if (rel) {
|
||||
vi->flags |= VOICE_RELEASE;
|
||||
} else {
|
||||
vi->flags &= ~VOICE_RELEASE;
|
||||
}
|
||||
}
|
||||
|
||||
void libxmp_mixer_seteffect(struct context_data *ctx, int voc, int type, int val)
|
||||
{
|
||||
#ifndef LIBXMP_CORE_DISABLE_IT
|
||||
struct player_data *p = &ctx->p;
|
||||
struct mixer_voice *vi = &p->virt.voice_array[voc];
|
||||
|
||||
switch (type) {
|
||||
case DSP_EFFECT_CUTOFF:
|
||||
vi->filter.cutoff = val;
|
||||
break;
|
||||
case DSP_EFFECT_RESONANCE:
|
||||
vi->filter.resonance = val;
|
||||
break;
|
||||
case DSP_EFFECT_FILTER_A0:
|
||||
vi->filter.a0 = val;
|
||||
break;
|
||||
case DSP_EFFECT_FILTER_B0:
|
||||
vi->filter.b0 = val;
|
||||
break;
|
||||
case DSP_EFFECT_FILTER_B1:
|
||||
vi->filter.b1 = val;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void libxmp_mixer_setpan(struct context_data *ctx, int voc, int pan)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
struct mixer_voice *vi = &p->virt.voice_array[voc];
|
||||
|
||||
vi->pan = pan;
|
||||
}
|
||||
|
||||
int libxmp_mixer_numvoices(struct context_data *ctx, int num)
|
||||
{
|
||||
struct mixer_data *s = &ctx->s;
|
||||
|
||||
if (num > s->numvoc || num < 0) {
|
||||
return s->numvoc;
|
||||
} else {
|
||||
return num;
|
||||
}
|
||||
}
|
||||
|
||||
int libxmp_mixer_on(struct context_data *ctx, int rate, int format, int c4rate)
|
||||
{
|
||||
struct mixer_data *s = &ctx->s;
|
||||
|
||||
s->buffer = (char *) calloc(2, XMP_MAX_FRAMESIZE);
|
||||
if (s->buffer == NULL)
|
||||
goto err;
|
||||
|
||||
s->buf32 = (int32 *) calloc(sizeof(int32), XMP_MAX_FRAMESIZE);
|
||||
if (s->buf32 == NULL)
|
||||
goto err1;
|
||||
|
||||
s->freq = rate;
|
||||
s->format = format;
|
||||
s->amplify = DEFAULT_AMPLIFY;
|
||||
s->mix = DEFAULT_MIX;
|
||||
/* s->pbase = C4_PERIOD * c4rate / s->freq; */(void) c4rate;
|
||||
s->interp = XMP_INTERP_LINEAR; /* default interpolation type */
|
||||
s->dsp = XMP_DSP_LOWPASS; /* enable filters by default */
|
||||
/* s->numvoc = SMIX_NUMVOC; */
|
||||
s->dtright = s->dtleft = 0;
|
||||
|
||||
return 0;
|
||||
|
||||
err1:
|
||||
free(s->buffer);
|
||||
s->buffer = NULL;
|
||||
err:
|
||||
return -1;
|
||||
}
|
||||
|
||||
void libxmp_mixer_off(struct context_data *ctx)
|
||||
{
|
||||
struct mixer_data *s = &ctx->s;
|
||||
|
||||
free(s->buffer);
|
||||
free(s->buf32);
|
||||
s->buf32 = NULL;
|
||||
s->buffer = NULL;
|
||||
}
|
78
internal/c/parts/audio/extras/libxmp-lite/mixer.h
Normal file
78
internal/c/parts/audio/extras/libxmp-lite/mixer.h
Normal file
|
@ -0,0 +1,78 @@
|
|||
#ifndef LIBXMP_MIXER_H
|
||||
#define LIBXMP_MIXER_H
|
||||
|
||||
#define C4_PERIOD 428.0
|
||||
|
||||
#define SMIX_NUMVOC 128 /* default number of softmixer voices */
|
||||
#define SMIX_SHIFT 16
|
||||
#define SMIX_MASK 0xffff
|
||||
|
||||
#define FILTER_SHIFT 16
|
||||
#define ANTICLICK_SHIFT 3
|
||||
|
||||
#ifdef LIBXMP_PAULA_SIMULATOR
|
||||
#include "paula.h"
|
||||
#endif
|
||||
|
||||
#define MIXER(f) void libxmp_mix_##f(struct mixer_voice *vi, int *buffer, \
|
||||
int count, int vl, int vr, int step, int ramp, int delta_l, int delta_r)
|
||||
|
||||
struct mixer_voice {
|
||||
int chn; /* channel number */
|
||||
int root; /* */
|
||||
int note; /* */
|
||||
#define PAN_SURROUND 0x8000
|
||||
int pan; /* */
|
||||
int vol; /* */
|
||||
double period; /* current period */
|
||||
double pos; /* position in sample */
|
||||
int pos0; /* position in sample before mixing */
|
||||
int fidx; /* mixer function index */
|
||||
int ins; /* instrument number */
|
||||
int smp; /* sample number */
|
||||
int end; /* loop end */
|
||||
int act; /* nna info & status of voice */
|
||||
int old_vl; /* previous volume, left channel */
|
||||
int old_vr; /* previous volume, right channel */
|
||||
int sleft; /* last left sample output, in 32bit */
|
||||
int sright; /* last right sample output, in 32bit */
|
||||
#define VOICE_RELEASE (1 << 0)
|
||||
#define ANTICLICK (1 << 1)
|
||||
#define SAMPLE_LOOP (1 << 2)
|
||||
int flags; /* flags */
|
||||
void *sptr; /* sample pointer */
|
||||
#ifdef LIBXMP_PAULA_SIMULATOR
|
||||
struct paula_state *paula; /* paula simulation state */
|
||||
#endif
|
||||
|
||||
#ifndef LIBXMP_CORE_DISABLE_IT
|
||||
struct {
|
||||
int r1; /* filter variables */
|
||||
int r2;
|
||||
int l1;
|
||||
int l2;
|
||||
int a0;
|
||||
int b0;
|
||||
int b1;
|
||||
int cutoff;
|
||||
int resonance;
|
||||
} filter;
|
||||
#endif
|
||||
};
|
||||
|
||||
int libxmp_mixer_on (struct context_data *, int, int, int);
|
||||
void libxmp_mixer_off (struct context_data *);
|
||||
void libxmp_mixer_setvol (struct context_data *, int, int);
|
||||
void libxmp_mixer_seteffect (struct context_data *, int, int, int);
|
||||
void libxmp_mixer_setpan (struct context_data *, int, int);
|
||||
int libxmp_mixer_numvoices (struct context_data *, int);
|
||||
void libxmp_mixer_softmixer (struct context_data *);
|
||||
void libxmp_mixer_reset (struct context_data *);
|
||||
void libxmp_mixer_setpatch (struct context_data *, int, int, int);
|
||||
void libxmp_mixer_voicepos (struct context_data *, int, double, int);
|
||||
double libxmp_mixer_getvoicepos(struct context_data *, int);
|
||||
void libxmp_mixer_setnote (struct context_data *, int, int);
|
||||
void libxmp_mixer_setperiod (struct context_data *, int, double);
|
||||
void libxmp_mixer_release (struct context_data *, int, int);
|
||||
|
||||
#endif /* LIBXMP_MIXER_H */
|
55
internal/c/parts/audio/extras/libxmp-lite/mod.h
Normal file
55
internal/c/parts/audio/extras/libxmp-lite/mod.h
Normal file
|
@ -0,0 +1,55 @@
|
|||
/* Extended Module Player
|
||||
* Copyright (C) 1996-2021 Claudio Matsuoka and Hipolito Carraro Jr
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
struct mod_instrument {
|
||||
uint8 name[22]; /* Instrument name */
|
||||
uint16 size; /* Sample length in 16-bit words */
|
||||
int8 finetune; /* Finetune (signed nibble) */
|
||||
int8 volume; /* Linear playback volume */
|
||||
uint16 loop_start; /* Loop start in 16-bit words */
|
||||
uint16 loop_size; /* Loop length in 16-bit words */
|
||||
};
|
||||
|
||||
struct mod_header {
|
||||
uint8 name[20];
|
||||
struct mod_instrument ins[31];
|
||||
uint8 len;
|
||||
uint8 restart; /* Number of patterns in Soundtracker,
|
||||
* Restart in Noisetracker/Startrekker,
|
||||
* 0x7F in Protracker
|
||||
*/
|
||||
uint8 order[128];
|
||||
uint8 magic[4];
|
||||
};
|
||||
|
||||
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
/* Soundtracker 15-instrument module header */
|
||||
|
||||
struct st_header {
|
||||
uint8 name[20];
|
||||
struct mod_instrument ins[15];
|
||||
uint8 len;
|
||||
uint8 restart;
|
||||
uint8 order[128];
|
||||
};
|
||||
#endif
|
234
internal/c/parts/audio/extras/libxmp-lite/mod_load.c
Normal file
234
internal/c/parts/audio/extras/libxmp-lite/mod_load.c
Normal file
|
@ -0,0 +1,234 @@
|
|||
/* Extended Module Player
|
||||
* Copyright (C) 1996-2021 Claudio Matsuoka and Hipolito Carraro Jr
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/* This loader recognizes the following variants of the Protracker
|
||||
* module format:
|
||||
*
|
||||
* - Protracker M.K.
|
||||
* - Fasttracker ?CHN and ??CH
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <limits.h>
|
||||
#include "loader.h"
|
||||
#include "mod.h"
|
||||
|
||||
static int mod_test(HIO_HANDLE *, char *, const int);
|
||||
static int mod_load(struct module_data *, HIO_HANDLE *, const int);
|
||||
|
||||
const struct format_loader libxmp_loader_mod = {
|
||||
"Protracker",
|
||||
mod_test,
|
||||
mod_load
|
||||
};
|
||||
|
||||
static int mod_test(HIO_HANDLE *f, char *t, const int start)
|
||||
{
|
||||
int i;
|
||||
char buf[4];
|
||||
|
||||
hio_seek(f, start + 1080, SEEK_SET);
|
||||
if (hio_read(buf, 1, 4, f) < 4)
|
||||
return -1;
|
||||
|
||||
if (!strncmp(buf + 2, "CH", 2) && isdigit((int)buf[0])
|
||||
&& isdigit((int)buf[1])) {
|
||||
i = (buf[0] - '0') * 10 + buf[1] - '0';
|
||||
if (i > 0 && i <= 32) {
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
|
||||
if (!strncmp(buf + 1, "CHN", 3) && isdigit((int)*buf)) {
|
||||
if (*buf >= '0' && *buf <= '9') {
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
|
||||
if (memcmp(buf, "M.K.", 4))
|
||||
return -1;
|
||||
|
||||
found:
|
||||
hio_seek(f, start + 0, SEEK_SET);
|
||||
libxmp_read_title(f, t, 20);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mod_load(struct module_data *m, HIO_HANDLE *f, const int start)
|
||||
{
|
||||
struct xmp_module *mod = &m->mod;
|
||||
int i, j;
|
||||
struct xmp_event *event;
|
||||
struct mod_header mh;
|
||||
uint8 mod_event[4];
|
||||
char magic[8];
|
||||
int ptkloop = 0; /* Protracker loop */
|
||||
|
||||
LOAD_INIT();
|
||||
|
||||
mod->ins = 31;
|
||||
mod->smp = mod->ins;
|
||||
mod->chn = 0;
|
||||
|
||||
m->quirk |= QUIRK_PROTRACK;
|
||||
m->period_type = PERIOD_MODRNG;
|
||||
|
||||
hio_read(mh.name, 20, 1, f);
|
||||
for (i = 0; i < 31; i++) {
|
||||
hio_read(mh.ins[i].name, 22, 1, f); /* Instrument name */
|
||||
mh.ins[i].size = hio_read16b(f); /* Length in 16-bit words */
|
||||
mh.ins[i].finetune = hio_read8(f); /* Finetune (signed nibble) */
|
||||
mh.ins[i].volume = hio_read8(f); /* Linear playback volume */
|
||||
mh.ins[i].loop_start = hio_read16b(f); /* Loop start in 16-bit words */
|
||||
mh.ins[i].loop_size = hio_read16b(f); /* Loop size in 16-bit words */
|
||||
}
|
||||
mh.len = hio_read8(f);
|
||||
mh.restart = hio_read8(f);
|
||||
hio_read(mh.order, 128, 1, f);
|
||||
memset(magic, 0, 8);
|
||||
hio_read(magic, 4, 1, f);
|
||||
|
||||
if (!memcmp(magic, "M.K.", 4)) {
|
||||
mod->chn = 4;
|
||||
} else if (!strncmp(magic + 2, "CH", 2) &&
|
||||
isdigit((int)magic[0]) && isdigit((int)magic[1])) {
|
||||
mod->chn = (*magic - '0') * 10 + magic[1] - '0';
|
||||
} else if (!strncmp(magic + 1, "CHN", 3) && isdigit((int)*magic)) {
|
||||
mod->chn = *magic - '0';
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
strncpy(mod->name, (char *) mh.name, 20);
|
||||
|
||||
mod->len = mh.len;
|
||||
/* mod->rst = mh.restart; */
|
||||
|
||||
if (mod->rst >= mod->len)
|
||||
mod->rst = 0;
|
||||
memcpy(mod->xxo, mh.order, 128);
|
||||
|
||||
for (i = 0; i < 128; i++) {
|
||||
/* This fixes dragnet.mod (garbage in the order list) */
|
||||
if (mod->xxo[i] > 0x7f)
|
||||
break;
|
||||
if (mod->xxo[i] > mod->pat)
|
||||
mod->pat = mod->xxo[i];
|
||||
}
|
||||
mod->pat++;
|
||||
|
||||
if (libxmp_init_instrument(m) < 0)
|
||||
return -1;
|
||||
|
||||
for (i = 0; i < mod->ins; i++) {
|
||||
struct xmp_instrument *xxi;
|
||||
struct xmp_subinstrument *sub;
|
||||
struct xmp_sample *xxs;
|
||||
|
||||
if (libxmp_alloc_subinstrument(mod, i, 1) < 0)
|
||||
return -1;
|
||||
|
||||
xxi = &mod->xxi[i];
|
||||
sub = &xxi->sub[0];
|
||||
xxs = &mod->xxs[i];
|
||||
|
||||
xxs->len = 2 * mh.ins[i].size;
|
||||
xxs->lps = 2 * mh.ins[i].loop_start;
|
||||
xxs->lpe = xxs->lps + 2 * mh.ins[i].loop_size;
|
||||
if (xxs->lpe > xxs->len) {
|
||||
xxs->lpe = xxs->len;
|
||||
}
|
||||
xxs->flg = (mh.ins[i].loop_size > 1 && xxs->lpe >= 4) ?
|
||||
XMP_SAMPLE_LOOP : 0;
|
||||
sub->fin = (int8) (mh.ins[i].finetune << 4);
|
||||
sub->vol = mh.ins[i].volume;
|
||||
sub->pan = 0x80;
|
||||
sub->sid = i;
|
||||
libxmp_instrument_name(mod, i, mh.ins[i].name, 22);
|
||||
|
||||
if (xxs->len > 0) {
|
||||
xxi->nsm = 1;
|
||||
}
|
||||
}
|
||||
|
||||
mod->trk = mod->chn * mod->pat;
|
||||
|
||||
libxmp_set_type(m, (mod->chn == 4) ? "Protracker" : "Fasttracker");
|
||||
|
||||
MODULE_INFO();
|
||||
|
||||
for (i = 0; i < mod->ins; i++) {
|
||||
D_(D_INFO "[%2X] %-22.22s %04x %04x %04x %c V%02x %+d %c\n",
|
||||
i, mod->xxi[i].name,
|
||||
mod->xxs[i].len, mod->xxs[i].lps, mod->xxs[i].lpe,
|
||||
(mh.ins[i].loop_size > 1 && mod->xxs[i].lpe > 8) ?
|
||||
'L' : ' ', mod->xxi[i].sub[0].vol,
|
||||
mod->xxi[i].sub[0].fin >> 4,
|
||||
ptkloop && mod->xxs[i].lps == 0 && mh.ins[i].loop_size > 1 &&
|
||||
mod->xxs[i].len > mod->xxs[i].lpe ? '!' : ' ');
|
||||
}
|
||||
|
||||
if (libxmp_init_pattern(mod) < 0)
|
||||
return -1;
|
||||
|
||||
/* Load and convert patterns */
|
||||
D_(D_INFO "Stored patterns: %d", mod->pat);
|
||||
|
||||
for (i = 0; i < mod->pat; i++) {
|
||||
if (libxmp_alloc_pattern_tracks(mod, i, 64) < 0)
|
||||
return -1;
|
||||
|
||||
for (j = 0; j < (64 * mod->chn); j++) {
|
||||
event = &EVENT(i, j % mod->chn, j / mod->chn);
|
||||
if (hio_read(mod_event, 1, 4, f) < 4) {
|
||||
return -1;
|
||||
}
|
||||
libxmp_decode_protracker_event(event, mod_event);
|
||||
}
|
||||
}
|
||||
|
||||
/* Load samples */
|
||||
|
||||
D_(D_INFO "Stored samples: %d", mod->smp);
|
||||
|
||||
for (i = 0; i < mod->smp; i++) {
|
||||
int flags;
|
||||
|
||||
if (!mod->xxs[i].len)
|
||||
continue;
|
||||
|
||||
flags = ptkloop ? SAMPLE_FLAG_FULLREP : 0;
|
||||
|
||||
if (libxmp_load_sample(m, f, flags, &mod->xxs[i], NULL) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (mod->chn > 4) {
|
||||
m->quirk &= ~QUIRK_PROTRACK;
|
||||
m->quirk |= QUIRKS_FT2 | QUIRK_FTMOD;
|
||||
m->read_event_type = READ_EVENT_FT2;
|
||||
m->period_type = PERIOD_AMIGA;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
266
internal/c/parts/audio/extras/libxmp-lite/period.c
Normal file
266
internal/c/parts/audio/extras/libxmp-lite/period.c
Normal file
|
@ -0,0 +1,266 @@
|
|||
/* Extended Module Player
|
||||
* Copyright (C) 1996-2021 Claudio Matsuoka and Hipolito Carraro Jr
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
#include "common.h"
|
||||
#include "period.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#ifdef LIBXMP_PAULA_SIMULATOR
|
||||
/*
|
||||
* Period table from the Protracker V2.1A play routine
|
||||
*/
|
||||
static uint16 pt_period_table[16][36] = {
|
||||
/* Tuning 0, Normal */
|
||||
{
|
||||
856,808,762,720,678,640,604,570,538,508,480,453,
|
||||
428,404,381,360,339,320,302,285,269,254,240,226,
|
||||
214,202,190,180,170,160,151,143,135,127,120,113
|
||||
},
|
||||
/* Tuning 1 */
|
||||
{
|
||||
850,802,757,715,674,637,601,567,535,505,477,450,
|
||||
425,401,379,357,337,318,300,284,268,253,239,225,
|
||||
213,201,189,179,169,159,150,142,134,126,119,113
|
||||
},
|
||||
/* Tuning 2 */
|
||||
{
|
||||
844,796,752,709,670,632,597,563,532,502,474,447,
|
||||
422,398,376,355,335,316,298,282,266,251,237,224,
|
||||
211,199,188,177,167,158,149,141,133,125,118,112
|
||||
},
|
||||
/* Tuning 3 */
|
||||
{
|
||||
838,791,746,704,665,628,592,559,528,498,470,444,
|
||||
419,395,373,352,332,314,296,280,264,249,235,222,
|
||||
209,198,187,176,166,157,148,140,132,125,118,111
|
||||
},
|
||||
/* Tuning 4 */
|
||||
{
|
||||
832,785,741,699,660,623,588,555,524,495,467,441,
|
||||
416,392,370,350,330,312,294,278,262,247,233,220,
|
||||
208,196,185,175,165,156,147,139,131,124,117,110
|
||||
},
|
||||
/* Tuning 5 */
|
||||
{
|
||||
826,779,736,694,655,619,584,551,520,491,463,437,
|
||||
413,390,368,347,328,309,292,276,260,245,232,219,
|
||||
206,195,184,174,164,155,146,138,130,123,116,109
|
||||
},
|
||||
/* Tuning 6 */
|
||||
{
|
||||
820,774,730,689,651,614,580,547,516,487,460,434,
|
||||
410,387,365,345,325,307,290,274,258,244,230,217,
|
||||
205,193,183,172,163,154,145,137,129,122,115,109
|
||||
},
|
||||
/* Tuning 7 */
|
||||
{
|
||||
814,768,725,684,646,610,575,543,513,484,457,431,
|
||||
407,384,363,342,323,305,288,272,256,242,228,216,
|
||||
204,192,181,171,161,152,144,136,128,121,114,108
|
||||
},
|
||||
/* Tuning -8 */
|
||||
{
|
||||
907,856,808,762,720,678,640,604,570,538,508,480,
|
||||
453,428,404,381,360,339,320,302,285,269,254,240,
|
||||
226,214,202,190,180,170,160,151,143,135,127,120
|
||||
},
|
||||
/* Tuning -7 */
|
||||
{
|
||||
900,850,802,757,715,675,636,601,567,535,505,477,
|
||||
450,425,401,379,357,337,318,300,284,268,253,238,
|
||||
225,212,200,189,179,169,159,150,142,134,126,119
|
||||
},
|
||||
/* Tuning -6 */
|
||||
{
|
||||
894,844,796,752,709,670,632,597,563,532,502,474,
|
||||
447,422,398,376,355,335,316,298,282,266,251,237,
|
||||
223,211,199,188,177,167,158,149,141,133,125,118
|
||||
},
|
||||
/* Tuning -5 */
|
||||
{
|
||||
887,838,791,746,704,665,628,592,559,528,498,470,
|
||||
444,419,395,373,352,332,314,296,280,264,249,235,
|
||||
222,209,198,187,176,166,157,148,140,132,125,118
|
||||
},
|
||||
/* Tuning -4 */
|
||||
{
|
||||
881,832,785,741,699,660,623,588,555,524,494,467,
|
||||
441,416,392,370,350,330,312,294,278,262,247,233,
|
||||
220,208,196,185,175,165,156,147,139,131,123,117
|
||||
},
|
||||
/* Tuning -3 */
|
||||
{
|
||||
875,826,779,736,694,655,619,584,551,520,491,463,
|
||||
437,413,390,368,347,328,309,292,276,260,245,232,
|
||||
219,206,195,184,174,164,155,146,138,130,123,116
|
||||
},
|
||||
/* Tuning -2 */
|
||||
{
|
||||
868,820,774,730,689,651,614,580,547,516,487,460,
|
||||
434,410,387,365,345,325,307,290,274,258,244,230,
|
||||
217,205,193,183,172,163,154,145,137,129,122,115
|
||||
},
|
||||
/* Tuning -1 */
|
||||
{
|
||||
862,814,768,725,684,646,610,575,543,513,484,457,
|
||||
431,407,384,363,342,323,305,288,272,256,242,228,
|
||||
216,203,192,181,171,161,152,144,136,128,121,114
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifndef M_LN2
|
||||
#define M_LN2 0.69314718055994530942
|
||||
#endif
|
||||
#if !defined(HAVE_ROUND) || defined(_MSC_VER) || defined(__WATCOMC__) || defined(__DJGPP__)
|
||||
static inline double libxmp_round(double val)
|
||||
{
|
||||
return (val >= 0.0)? floor(val + 0.5) : ceil(val - 0.5);
|
||||
}
|
||||
#else
|
||||
#define libxmp_round round
|
||||
#endif
|
||||
|
||||
#ifdef LIBXMP_PAULA_SIMULATOR
|
||||
/* Get period from note using Protracker tuning */
|
||||
static inline int libxmp_note_to_period_pt(int n, int f)
|
||||
{
|
||||
if (n < MIN_NOTE_MOD || n > MAX_NOTE_MOD) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
n -= 48;
|
||||
f >>= 4;
|
||||
if (f < -8 || f > 7) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (f < 0) {
|
||||
f += 16;
|
||||
}
|
||||
|
||||
return (int)pt_period_table[f][n];
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Get period from note */
|
||||
double libxmp_note_to_period(struct context_data *ctx, int n, int f, double adj)
|
||||
{
|
||||
double d, per;
|
||||
struct module_data *m = &ctx->m;
|
||||
#ifdef LIBXMP_PAULA_SIMULATOR
|
||||
struct player_data *p = &ctx->p;
|
||||
|
||||
/* If mod replayer, modrng and Amiga mixing are active */
|
||||
if (p->flags & XMP_FLAGS_A500) {
|
||||
if (IS_AMIGA_MOD()) {
|
||||
return libxmp_note_to_period_pt(n, f);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
d = (double)n + (double)f / 128;
|
||||
|
||||
switch (m->period_type) {
|
||||
case PERIOD_LINEAR:
|
||||
per = (240.0 - d) * 16; /* Linear */
|
||||
break;
|
||||
case PERIOD_CSPD:
|
||||
per = 8363.0 * pow(2, n / 12) / 32 + f; /* Hz */
|
||||
break;
|
||||
default:
|
||||
per = PERIOD_BASE / pow(2, d / 12); /* Amiga */
|
||||
}
|
||||
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
if (adj > 0.1) {
|
||||
per *= adj;
|
||||
}
|
||||
#endif
|
||||
|
||||
return per;
|
||||
}
|
||||
|
||||
/* For the software mixer */
|
||||
double libxmp_note_to_period_mix(int n, int b)
|
||||
{
|
||||
double d = (double)n + (double)b / 12800;
|
||||
return PERIOD_BASE / pow(2, d / 12);
|
||||
}
|
||||
|
||||
/* Get note from period */
|
||||
/* This function is used only by the MOD loader */
|
||||
int libxmp_period_to_note(int p)
|
||||
{
|
||||
if (p <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return libxmp_round(12.0 * log(PERIOD_BASE / p) / M_LN2) + 1;
|
||||
}
|
||||
|
||||
/* Get pitchbend from base note and amiga period */
|
||||
int libxmp_period_to_bend(struct context_data *ctx, double p, int n, double adj)
|
||||
{
|
||||
struct module_data *m = &ctx->m;
|
||||
double d;
|
||||
|
||||
if (n == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (m->period_type) {
|
||||
case PERIOD_LINEAR:
|
||||
return 100 * (8 * (((240 - n) << 4) - p));
|
||||
case PERIOD_CSPD:
|
||||
d = libxmp_note_to_period(ctx, n, 0, adj);
|
||||
return libxmp_round(100.0 * (1536.0 / M_LN2) * log(p / d));
|
||||
default:
|
||||
/* Amiga */
|
||||
d = libxmp_note_to_period(ctx, n, 0, adj);
|
||||
return libxmp_round(100.0 * (1536.0 / M_LN2) * log(d / p));
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert finetune = 1200 * log2(C2SPD/8363))
|
||||
*
|
||||
* c = (1200.0 * log(c2spd) - 1200.0 * log(c4_rate)) / M_LN2;
|
||||
* xpo = c/100;
|
||||
* fin = 128 * (c%100) / 100;
|
||||
*/
|
||||
void libxmp_c2spd_to_note(int c2spd, int *n, int *f)
|
||||
{
|
||||
int c;
|
||||
|
||||
if (c2spd == 0) {
|
||||
*n = *f = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
c = (int)(1536.0 * log((double)c2spd / 8363) / M_LN2);
|
||||
*n = c / 128;
|
||||
*f = c % 128;
|
||||
}
|
24
internal/c/parts/audio/extras/libxmp-lite/period.h
Normal file
24
internal/c/parts/audio/extras/libxmp-lite/period.h
Normal file
|
@ -0,0 +1,24 @@
|
|||
#ifndef LIBXMP_PERIOD_H
|
||||
#define LIBXMP_PERIOD_H
|
||||
|
||||
#define PERIOD_BASE 13696.0 /* C0 period */
|
||||
|
||||
/* Macros for period conversion */
|
||||
#define NOTE_B0 11
|
||||
#define NOTE_Bb0 (NOTE_B0 + 1)
|
||||
#define MAX_NOTE (NOTE_B0 * 8)
|
||||
#define MAX_PERIOD 0x1c56
|
||||
#define MIN_PERIOD_A 0x0071
|
||||
#define MAX_PERIOD_A 0x0358
|
||||
#define MIN_PERIOD_L 0x0000
|
||||
#define MAX_PERIOD_L 0x1e00
|
||||
#define MIN_NOTE_MOD 48
|
||||
#define MAX_NOTE_MOD 83
|
||||
|
||||
double libxmp_note_to_period (struct context_data *, int, int, double);
|
||||
double libxmp_note_to_period_mix (int, int);
|
||||
int libxmp_period_to_note (int);
|
||||
int libxmp_period_to_bend (struct context_data *, double, int, double);
|
||||
void libxmp_c2spd_to_note (int, int *, int *);
|
||||
|
||||
#endif /* LIBXMP_PERIOD_H */
|
1928
internal/c/parts/audio/extras/libxmp-lite/player.c
Normal file
1928
internal/c/parts/audio/extras/libxmp-lite/player.c
Normal file
File diff suppressed because it is too large
Load diff
258
internal/c/parts/audio/extras/libxmp-lite/player.h
Normal file
258
internal/c/parts/audio/extras/libxmp-lite/player.h
Normal file
|
@ -0,0 +1,258 @@
|
|||
#ifndef LIBXMP_PLAYER_H
|
||||
#define LIBXMP_PLAYER_H
|
||||
|
||||
#include "lfo.h"
|
||||
|
||||
/* Quirk control */
|
||||
#define HAS_QUIRK(x) (m->quirk & (x))
|
||||
|
||||
/* Channel flag control */
|
||||
#define SET(f) SET_FLAG(xc->flags,(f))
|
||||
#define RESET(f) RESET_FLAG(xc->flags,(f))
|
||||
#define TEST(f) TEST_FLAG(xc->flags,(f))
|
||||
|
||||
/* Persistent effect flag control */
|
||||
#define SET_PER(f) SET_FLAG(xc->per_flags,(f))
|
||||
#define RESET_PER(f) RESET_FLAG(xc->per_flags,(f))
|
||||
#define TEST_PER(f) TEST_FLAG(xc->per_flags,(f))
|
||||
|
||||
/* Note flag control */
|
||||
#define SET_NOTE(f) SET_FLAG(xc->note_flags,(f))
|
||||
#define RESET_NOTE(f) RESET_FLAG(xc->note_flags,(f))
|
||||
#define TEST_NOTE(f) TEST_FLAG(xc->note_flags,(f))
|
||||
|
||||
struct retrig_control {
|
||||
int s;
|
||||
int m;
|
||||
int d;
|
||||
};
|
||||
|
||||
/* The following macros are used to set the flags for each channel */
|
||||
#define VOL_SLIDE (1 << 0)
|
||||
#define PAN_SLIDE (1 << 1)
|
||||
#define TONEPORTA (1 << 2)
|
||||
#define PITCHBEND (1 << 3)
|
||||
#define VIBRATO (1 << 4)
|
||||
#define TREMOLO (1 << 5)
|
||||
#define FINE_VOLS (1 << 6)
|
||||
#define FINE_BEND (1 << 7)
|
||||
#define OFFSET (1 << 8)
|
||||
#define TRK_VSLIDE (1 << 9)
|
||||
#define TRK_FVSLIDE (1 << 10)
|
||||
#define NEW_INS (1 << 11)
|
||||
#define NEW_VOL (1 << 12)
|
||||
#define VOL_SLIDE_2 (1 << 13)
|
||||
#define NOTE_SLIDE (1 << 14)
|
||||
#define FINE_NSLIDE (1 << 15)
|
||||
#define NEW_NOTE (1 << 16)
|
||||
#define FINE_TPORTA (1 << 17)
|
||||
#define RETRIG (1 << 18)
|
||||
#define PANBRELLO (1 << 19)
|
||||
#define GVOL_SLIDE (1 << 20)
|
||||
#define TEMPO_SLIDE (1 << 21)
|
||||
#define VENV_PAUSE (1 << 22)
|
||||
#define PENV_PAUSE (1 << 23)
|
||||
#define FENV_PAUSE (1 << 24)
|
||||
#define FINE_VOLS_2 (1 << 25)
|
||||
#define KEY_OFF (1 << 26) /* for IT release on envloop end */
|
||||
#define TREMOR (1 << 27) /* for XM tremor */
|
||||
|
||||
#define NOTE_FADEOUT (1 << 0)
|
||||
#define NOTE_RELEASE (1 << 1)
|
||||
#define NOTE_END (1 << 2)
|
||||
#define NOTE_CUT (1 << 3)
|
||||
#define NOTE_ENV_END (1 << 4)
|
||||
#define NOTE_SAMPLE_END (1 << 5)
|
||||
#define NOTE_SET (1 << 6) /* for IT portamento after keyoff */
|
||||
#define NOTE_SUSEXIT (1 << 7) /* for delayed note release */
|
||||
#define NOTE_KEY_CUT (1 << 8) /* note cut with XMP_KEY_CUT event */
|
||||
#define NOTE_GLISSANDO (1 << 9)
|
||||
|
||||
#define IS_VALID_INSTRUMENT(x) ((uint32)(x) < mod->ins && mod->xxi[(x)].nsm > 0)
|
||||
#define IS_VALID_INSTRUMENT_OR_SFX(x) (((uint32)(x) < mod->ins && mod->xxi[(x)].nsm > 0) || (smix->ins > 0 && (uint32)(x) < mod->ins + smix->ins))
|
||||
|
||||
struct instrument_vibrato {
|
||||
int phase;
|
||||
int sweep;
|
||||
};
|
||||
|
||||
struct channel_data {
|
||||
int flags; /* Channel flags */
|
||||
int per_flags; /* Persistent effect channel flags */
|
||||
int note_flags; /* Note release, fadeout or end */
|
||||
int note; /* Note number */
|
||||
int key; /* Key number */
|
||||
double period; /* Amiga or linear period */
|
||||
double per_adj; /* MED period/pitch adjustment factor hack */
|
||||
int finetune; /* Guess what */
|
||||
int ins; /* Instrument number */
|
||||
int old_ins; /* Last instruemnt */
|
||||
int smp; /* Sample number */
|
||||
int mastervol; /* Master vol -- for IT track vol effect */
|
||||
int delay; /* Note delay in frames */
|
||||
int keyoff; /* Key off counter */
|
||||
int fadeout; /* Current fadeout (release) value */
|
||||
int ins_fade; /* Instrument fadeout value */
|
||||
int volume; /* Current volume */
|
||||
int gvl; /* Global volume for instrument for IT */
|
||||
|
||||
int rvv; /* Random volume variation */
|
||||
int rpv; /* Random pan variation */
|
||||
|
||||
uint8 split; /* Split channel */
|
||||
uint8 pair; /* Split channel pair */
|
||||
|
||||
int v_idx; /* Volume envelope index */
|
||||
int p_idx; /* Pan envelope index */
|
||||
int f_idx; /* Freq envelope index */
|
||||
|
||||
int key_porta; /* Key number for portamento target
|
||||
* -- needed to handle IT portamento xpo */
|
||||
struct {
|
||||
struct lfo lfo;
|
||||
int memory;
|
||||
} vibrato;
|
||||
|
||||
struct {
|
||||
struct lfo lfo;
|
||||
int memory;
|
||||
} tremolo;
|
||||
|
||||
#ifndef LIBXMP_CORE_DISABLE_IT
|
||||
struct {
|
||||
struct lfo lfo;
|
||||
int memory;
|
||||
} panbrello;
|
||||
#endif
|
||||
|
||||
struct {
|
||||
int8 val[16]; /* 16 for Smaksak MegaArps */
|
||||
int size;
|
||||
int count;
|
||||
int memory;
|
||||
} arpeggio;
|
||||
|
||||
struct {
|
||||
struct lfo lfo;
|
||||
int sweep;
|
||||
} insvib;
|
||||
|
||||
struct {
|
||||
int val;
|
||||
int val2; /* For fx9 bug emulation */
|
||||
int memory;
|
||||
} offset;
|
||||
|
||||
struct {
|
||||
int val; /* Retrig value */
|
||||
int count; /* Retrig counter */
|
||||
int type; /* Retrig type */
|
||||
} retrig;
|
||||
|
||||
struct {
|
||||
uint8 up,down; /* Tremor value */
|
||||
uint8 count; /* Tremor counter */
|
||||
uint8 memory; /* Tremor memory */
|
||||
} tremor;
|
||||
|
||||
struct {
|
||||
int slide; /* Volume slide value */
|
||||
int fslide; /* Fine volume slide value */
|
||||
int slide2; /* Volume slide value */
|
||||
int memory; /* Volume slide effect memory */
|
||||
#ifndef LIBXMP_CORE_DISABLE_IT
|
||||
int fslide2;
|
||||
int memory2; /* Volume slide effect memory */
|
||||
#endif
|
||||
} vol;
|
||||
|
||||
struct {
|
||||
int up_memory; /* Fine volume slide up memory (XM) */
|
||||
int down_memory;/* Fine volume slide up memory (XM) */
|
||||
} fine_vol;
|
||||
|
||||
struct {
|
||||
int slide; /* Global volume slide value */
|
||||
int fslide; /* Fine global volume slide value */
|
||||
int memory; /* Global volume memory is saved per channel */
|
||||
} gvol;
|
||||
|
||||
struct {
|
||||
int slide; /* Track volume slide value */
|
||||
int fslide; /* Track fine volume slide value */
|
||||
int memory; /* Track volume slide effect memory */
|
||||
} trackvol;
|
||||
|
||||
struct {
|
||||
int slide; /* Frequency slide value */
|
||||
double fslide; /* Fine frequency slide value */
|
||||
int memory; /* Portamento effect memory */
|
||||
} freq;
|
||||
|
||||
struct {
|
||||
double target; /* Target period for tone portamento */
|
||||
int dir; /* Tone portamento up/down directionh */
|
||||
int slide; /* Delta for tone portamento */
|
||||
int memory; /* Tone portamento effect memory */
|
||||
} porta;
|
||||
|
||||
struct {
|
||||
int up_memory; /* FT2 has separate memories for these */
|
||||
int down_memory;/* cases (see Porta-LinkMem.xm) */
|
||||
} fine_porta;
|
||||
|
||||
struct {
|
||||
int val; /* Current pan value */
|
||||
int slide; /* Pan slide value */
|
||||
int fslide; /* Pan fine slide value */
|
||||
int memory; /* Pan slide effect memory */
|
||||
int surround; /* Surround channel flag */
|
||||
} pan;
|
||||
|
||||
struct {
|
||||
int speed;
|
||||
int count;
|
||||
int pos;
|
||||
} invloop;
|
||||
|
||||
#ifndef LIBXMP_CORE_DISABLE_IT
|
||||
struct {
|
||||
int slide; /* IT tempo slide */
|
||||
} tempo;
|
||||
|
||||
struct {
|
||||
int cutoff; /* IT filter cutoff frequency */
|
||||
int resonance; /* IT filter resonance */
|
||||
int envelope; /* IT filter envelope */
|
||||
} filter;
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
struct {
|
||||
int slide; /* PTM note slide amount */
|
||||
int fslide; /* OKT fine note slide amount */
|
||||
int speed; /* PTM note slide speed */
|
||||
int count; /* PTM note slide counter */
|
||||
} noteslide;
|
||||
|
||||
void *extra;
|
||||
#endif
|
||||
|
||||
struct xmp_event delayed_event;
|
||||
int delayed_ins; /* IT save instrument emulation */
|
||||
|
||||
int info_period; /* Period */
|
||||
int info_pitchbend; /* Linear pitchbend */
|
||||
int info_position; /* Position before mixing */
|
||||
int info_finalvol; /* Final volume including envelopes */
|
||||
int info_finalpan; /* Final pan including envelopes */
|
||||
};
|
||||
|
||||
|
||||
void libxmp_process_fx (struct context_data *, struct channel_data *,
|
||||
int, struct xmp_event *, int);
|
||||
void libxmp_filter_setup (int, int, int, int*, int*, int *);
|
||||
int libxmp_read_event (struct context_data *, struct xmp_event *, int);
|
||||
|
||||
#endif /* LIBXMP_PLAYER_H */
|
524
internal/c/parts/audio/extras/libxmp-lite/precomp_lut.h
Normal file
524
internal/c/parts/audio/extras/libxmp-lite/precomp_lut.h
Normal file
|
@ -0,0 +1,524 @@
|
|||
static int16 cubic_spline_lut0[1024] = {
|
||||
0, -8, -16, -24, -32, -40, -47, -55,
|
||||
-63, -71, -78, -86, -94, -101, -109, -117,
|
||||
-124, -132, -139, -146, -154, -161, -169, -176,
|
||||
-183, -190, -198, -205, -212, -219, -226, -233,
|
||||
-240, -247, -254, -261, -268, -275, -282, -289,
|
||||
-295, -302, -309, -316, -322, -329, -336, -342,
|
||||
-349, -355, -362, -368, -375, -381, -388, -394,
|
||||
-400, -407, -413, -419, -425, -432, -438, -444,
|
||||
-450, -456, -462, -468, -474, -480, -486, -492,
|
||||
-498, -504, -510, -515, -521, -527, -533, -538,
|
||||
-544, -550, -555, -561, -566, -572, -577, -583,
|
||||
-588, -594, -599, -604, -610, -615, -620, -626,
|
||||
-631, -636, -641, -646, -651, -656, -662, -667,
|
||||
-672, -677, -682, -686, -691, -696, -701, -706,
|
||||
-711, -715, -720, -725, -730, -734, -739, -744,
|
||||
-748, -753, -757, -762, -766, -771, -775, -780,
|
||||
-784, -788, -793, -797, -801, -806, -810, -814,
|
||||
-818, -822, -826, -831, -835, -839, -843, -847,
|
||||
-851, -855, -859, -863, -866, -870, -874, -878,
|
||||
-882, -886, -889, -893, -897, -900, -904, -908,
|
||||
-911, -915, -918, -922, -925, -929, -932, -936,
|
||||
-939, -943, -946, -949, -953, -956, -959, -962,
|
||||
-966, -969, -972, -975, -978, -981, -984, -987,
|
||||
-991, -994, -997, -999, -1002, -1005, -1008, -1011,
|
||||
-1014, -1017, -1020, -1022, -1025, -1028, -1031, -1033,
|
||||
-1036, -1039, -1041, -1044, -1047, -1049, -1052, -1054,
|
||||
-1057, -1059, -1062, -1064, -1066, -1069, -1071, -1074,
|
||||
-1076, -1078, -1080, -1083, -1085, -1087, -1089, -1092,
|
||||
-1094, -1096, -1098, -1100, -1102, -1104, -1106, -1108,
|
||||
-1110, -1112, -1114, -1116, -1118, -1120, -1122, -1124,
|
||||
-1125, -1127, -1129, -1131, -1133, -1134, -1136, -1138,
|
||||
-1139, -1141, -1143, -1144, -1146, -1147, -1149, -1150,
|
||||
-1152, -1153, -1155, -1156, -1158, -1159, -1161, -1162,
|
||||
-1163, -1165, -1166, -1167, -1169, -1170, -1171, -1172,
|
||||
-1174, -1175, -1176, -1177, -1178, -1179, -1180, -1181,
|
||||
-1182, -1184, -1185, -1186, -1187, -1187, -1188, -1189,
|
||||
-1190, -1191, -1192, -1193, -1194, -1195, -1195, -1196,
|
||||
-1197, -1198, -1198, -1199, -1200, -1200, -1201, -1202,
|
||||
-1202, -1203, -1204, -1204, -1205, -1205, -1206, -1206,
|
||||
-1207, -1207, -1208, -1208, -1208, -1209, -1209, -1210,
|
||||
-1210, -1210, -1211, -1211, -1211, -1212, -1212, -1212,
|
||||
-1212, -1212, -1213, -1213, -1213, -1213, -1213, -1213,
|
||||
-1213, -1213, -1214, -1214, -1214, -1214, -1214, -1214,
|
||||
-1214, -1214, -1213, -1213, -1213, -1213, -1213, -1213,
|
||||
-1213, -1213, -1212, -1212, -1212, -1212, -1211, -1211,
|
||||
-1211, -1211, -1210, -1210, -1210, -1209, -1209, -1209,
|
||||
-1208, -1208, -1207, -1207, -1207, -1206, -1206, -1205,
|
||||
-1205, -1204, -1204, -1203, -1202, -1202, -1201, -1201,
|
||||
-1200, -1199, -1199, -1198, -1197, -1197, -1196, -1195,
|
||||
-1195, -1194, -1193, -1192, -1192, -1191, -1190, -1189,
|
||||
-1188, -1187, -1187, -1186, -1185, -1184, -1183, -1182,
|
||||
-1181, -1180, -1179, -1178, -1177, -1176, -1175, -1174,
|
||||
-1173, -1172, -1171, -1170, -1169, -1168, -1167, -1166,
|
||||
-1165, -1163, -1162, -1161, -1160, -1159, -1158, -1156,
|
||||
-1155, -1154, -1153, -1151, -1150, -1149, -1148, -1146,
|
||||
-1145, -1144, -1142, -1141, -1140, -1138, -1137, -1135,
|
||||
-1134, -1133, -1131, -1130, -1128, -1127, -1125, -1124,
|
||||
-1122, -1121, -1119, -1118, -1116, -1115, -1113, -1112,
|
||||
-1110, -1109, -1107, -1105, -1104, -1102, -1101, -1099,
|
||||
-1097, -1096, -1094, -1092, -1091, -1089, -1087, -1085,
|
||||
-1084, -1082, -1080, -1079, -1077, -1075, -1073, -1071,
|
||||
-1070, -1068, -1066, -1064, -1062, -1061, -1059, -1057,
|
||||
-1055, -1053, -1051, -1049, -1047, -1046, -1044, -1042,
|
||||
-1040, -1038, -1036, -1034, -1032, -1030, -1028, -1026,
|
||||
-1024, -1022, -1020, -1018, -1016, -1014, -1012, -1010,
|
||||
-1008, -1006, -1004, -1002, -999, -997, -995, -993,
|
||||
-991, -989, -987, -985, -982, -980, -978, -976,
|
||||
-974, -972, -969, -967, -965, -963, -961, -958,
|
||||
-956, -954, -952, -950, -947, -945, -943, -941,
|
||||
-938, -936, -934, -931, -929, -927, -924, -922,
|
||||
-920, -918, -915, -913, -911, -908, -906, -903,
|
||||
-901, -899, -896, -894, -892, -889, -887, -884,
|
||||
-882, -880, -877, -875, -872, -870, -867, -865,
|
||||
-863, -860, -858, -855, -853, -850, -848, -845,
|
||||
-843, -840, -838, -835, -833, -830, -828, -825,
|
||||
-823, -820, -818, -815, -813, -810, -808, -805,
|
||||
-803, -800, -798, -795, -793, -790, -787, -785,
|
||||
-782, -780, -777, -775, -772, -769, -767, -764,
|
||||
-762, -759, -757, -754, -751, -749, -746, -744,
|
||||
-741, -738, -736, -733, -730, -728, -725, -723,
|
||||
-720, -717, -715, -712, -709, -707, -704, -702,
|
||||
-699, -696, -694, -691, -688, -686, -683, -680,
|
||||
-678, -675, -672, -670, -667, -665, -662, -659,
|
||||
-657, -654, -651, -649, -646, -643, -641, -638,
|
||||
-635, -633, -630, -627, -625, -622, -619, -617,
|
||||
-614, -611, -609, -606, -603, -601, -598, -595,
|
||||
-593, -590, -587, -585, -582, -579, -577, -574,
|
||||
-571, -569, -566, -563, -561, -558, -555, -553,
|
||||
-550, -547, -545, -542, -539, -537, -534, -531,
|
||||
-529, -526, -523, -521, -518, -516, -513, -510,
|
||||
-508, -505, -502, -500, -497, -495, -492, -489,
|
||||
-487, -484, -481, -479, -476, -474, -471, -468,
|
||||
-466, -463, -461, -458, -455, -453, -450, -448,
|
||||
-445, -442, -440, -437, -435, -432, -430, -427,
|
||||
-424, -422, -419, -417, -414, -412, -409, -407,
|
||||
-404, -402, -399, -397, -394, -392, -389, -387,
|
||||
-384, -382, -379, -377, -374, -372, -369, -367,
|
||||
-364, -362, -359, -357, -354, -352, -349, -347,
|
||||
-345, -342, -340, -337, -335, -332, -330, -328,
|
||||
-325, -323, -320, -318, -316, -313, -311, -309,
|
||||
-306, -304, -302, -299, -297, -295, -292, -290,
|
||||
-288, -285, -283, -281, -278, -276, -274, -272,
|
||||
-269, -267, -265, -263, -260, -258, -256, -254,
|
||||
-251, -249, -247, -245, -243, -240, -238, -236,
|
||||
-234, -232, -230, -228, -225, -223, -221, -219,
|
||||
-217, -215, -213, -211, -209, -207, -205, -202,
|
||||
-200, -198, -196, -194, -192, -190, -188, -186,
|
||||
-184, -182, -180, -178, -176, -175, -173, -171,
|
||||
-169, -167, -165, -163, -161, -159, -157, -156,
|
||||
-154, -152, -150, -148, -146, -145, -143, -141,
|
||||
-139, -137, -136, -134, -132, -130, -129, -127,
|
||||
-125, -124, -122, -120, -119, -117, -115, -114,
|
||||
-112, -110, -109, -107, -106, -104, -102, -101,
|
||||
-99, -98, -96, -95, -93, -92, -90, -89,
|
||||
-87, -86, -84, -83, -82, -80, -79, -77,
|
||||
-76, -75, -73, -72, -70, -69, -68, -67,
|
||||
-65, -64, -63, -61, -60, -59, -58, -57,
|
||||
-55, -54, -53, -52, -51, -49, -48, -47,
|
||||
-46, -45, -44, -43, -42, -41, -40, -39,
|
||||
-38, -37, -36, -35, -34, -33, -32, -31,
|
||||
-30, -29, -28, -27, -26, -26, -25, -24,
|
||||
-23, -22, -22, -21, -20, -19, -19, -18,
|
||||
-17, -16, -16, -15, -14, -14, -13, -13,
|
||||
-12, -11, -11, -10, -10, -9, -9, -8,
|
||||
-8, -7, -7, -6, -6, -6, -5, -5,
|
||||
-4, -4, -4, -3, -3, -3, -2, -2,
|
||||
-2, -2, -2, -1, -1, -1, -1, -1,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
};
|
||||
|
||||
static int16 cubic_spline_lut1[1024] = {
|
||||
16384, 16384, 16384, 16384, 16384, 16383, 16382, 16381,
|
||||
16381, 16381, 16380, 16379, 16379, 16377, 16377, 16376,
|
||||
16374, 16373, 16371, 16370, 16369, 16366, 16366, 16364,
|
||||
16361, 16360, 16358, 16357, 16354, 16351, 16349, 16347,
|
||||
16345, 16342, 16340, 16337, 16335, 16331, 16329, 16326,
|
||||
16322, 16320, 16317, 16314, 16309, 16307, 16304, 16299,
|
||||
16297, 16293, 16290, 16285, 16282, 16278, 16274, 16269,
|
||||
16265, 16262, 16257, 16253, 16247, 16244, 16239, 16235,
|
||||
16230, 16225, 16220, 16216, 16211, 16206, 16201, 16196,
|
||||
16191, 16185, 16180, 16174, 16169, 16163, 16158, 16151,
|
||||
16146, 16140, 16133, 16128, 16122, 16116, 16109, 16104,
|
||||
16097, 16092, 16085, 16077, 16071, 16064, 16058, 16052,
|
||||
16044, 16038, 16030, 16023, 16015, 16009, 16002, 15995,
|
||||
15988, 15980, 15973, 15964, 15957, 15949, 15941, 15934,
|
||||
15926, 15918, 15910, 15903, 15894, 15886, 15877, 15870,
|
||||
15861, 15853, 15843, 15836, 15827, 15818, 15810, 15801,
|
||||
15792, 15783, 15774, 15765, 15756, 15747, 15738, 15729,
|
||||
15719, 15709, 15700, 15691, 15681, 15672, 15662, 15652,
|
||||
15642, 15633, 15623, 15613, 15602, 15592, 15582, 15572,
|
||||
15562, 15552, 15540, 15530, 15520, 15509, 15499, 15489,
|
||||
15478, 15467, 15456, 15446, 15433, 15423, 15412, 15401,
|
||||
15390, 15379, 15367, 15356, 15345, 15333, 15321, 15310,
|
||||
15299, 15287, 15276, 15264, 15252, 15240, 15228, 15216,
|
||||
15205, 15192, 15180, 15167, 15155, 15143, 15131, 15118,
|
||||
15106, 15094, 15081, 15067, 15056, 15043, 15031, 15017,
|
||||
15004, 14992, 14979, 14966, 14953, 14940, 14927, 14913,
|
||||
14900, 14887, 14874, 14860, 14846, 14833, 14819, 14806,
|
||||
14793, 14778, 14764, 14752, 14737, 14723, 14709, 14696,
|
||||
14681, 14668, 14653, 14638, 14625, 14610, 14595, 14582,
|
||||
14567, 14553, 14538, 14523, 14509, 14494, 14480, 14465,
|
||||
14450, 14435, 14420, 14406, 14391, 14376, 14361, 14346,
|
||||
14330, 14316, 14301, 14285, 14270, 14254, 14239, 14223,
|
||||
14208, 14192, 14177, 14161, 14146, 14130, 14115, 14099,
|
||||
14082, 14067, 14051, 14035, 14019, 14003, 13986, 13971,
|
||||
13955, 13939, 13923, 13906, 13890, 13873, 13857, 13840,
|
||||
13823, 13808, 13791, 13775, 13758, 13741, 13724, 13707,
|
||||
13691, 13673, 13657, 13641, 13623, 13607, 13589, 13572,
|
||||
13556, 13538, 13521, 13504, 13486, 13469, 13451, 13435,
|
||||
13417, 13399, 13383, 13365, 13347, 13330, 13312, 13294,
|
||||
13277, 13258, 13241, 13224, 13205, 13188, 13170, 13152,
|
||||
13134, 13116, 13098, 13080, 13062, 13044, 13026, 13008,
|
||||
12989, 12971, 12953, 12934, 12916, 12898, 12879, 12860,
|
||||
12842, 12823, 12806, 12787, 12768, 12750, 12731, 12712,
|
||||
12694, 12675, 12655, 12637, 12618, 12599, 12580, 12562,
|
||||
12542, 12524, 12504, 12485, 12466, 12448, 12427, 12408,
|
||||
12390, 12370, 12351, 12332, 12312, 12293, 12273, 12254,
|
||||
12235, 12215, 12195, 12176, 12157, 12137, 12118, 12097,
|
||||
12079, 12059, 12039, 12019, 11998, 11980, 11960, 11940,
|
||||
11920, 11900, 11880, 11860, 11839, 11821, 11801, 11780,
|
||||
11761, 11741, 11720, 11700, 11680, 11660, 11640, 11619,
|
||||
11599, 11578, 11559, 11538, 11518, 11498, 11477, 11457,
|
||||
11436, 11415, 11394, 11374, 11354, 11333, 11313, 11292,
|
||||
11272, 11251, 11231, 11209, 11189, 11168, 11148, 11127,
|
||||
11107, 11084, 11064, 11043, 11023, 11002, 10982, 10959,
|
||||
10939, 10918, 10898, 10876, 10856, 10834, 10814, 10792,
|
||||
10772, 10750, 10728, 10708, 10687, 10666, 10644, 10623,
|
||||
10602, 10581, 10560, 10538, 10517, 10496, 10474, 10453,
|
||||
10431, 10410, 10389, 10368, 10346, 10325, 10303, 10283,
|
||||
10260, 10239, 10217, 10196, 10175, 10152, 10132, 10110,
|
||||
10088, 10068, 10045, 10023, 10002, 9981, 9959, 9936,
|
||||
9915, 9893, 9872, 9851, 9829, 9806, 9784, 9763,
|
||||
9742, 9720, 9698, 9676, 9653, 9633, 9611, 9589,
|
||||
9567, 9545, 9523, 9501, 9479, 9458, 9436, 9414,
|
||||
9392, 9370, 9348, 9326, 9304, 9282, 9260, 9238,
|
||||
9216, 9194, 9172, 9150, 9128, 9106, 9084, 9062,
|
||||
9040, 9018, 8996, 8974, 8951, 8929, 8907, 8885,
|
||||
8863, 8841, 8819, 8797, 8775, 8752, 8730, 8708,
|
||||
8686, 8664, 8642, 8620, 8597, 8575, 8553, 8531,
|
||||
8509, 8487, 8464, 8442, 8420, 8398, 8376, 8353,
|
||||
8331, 8309, 8287, 8265, 8242, 8220, 8198, 8176,
|
||||
8154, 8131, 8109, 8087, 8065, 8042, 8020, 7998,
|
||||
7976, 7954, 7931, 7909, 7887, 7865, 7842, 7820,
|
||||
7798, 7776, 7754, 7731, 7709, 7687, 7665, 7643,
|
||||
7620, 7598, 7576, 7554, 7531, 7509, 7487, 7465,
|
||||
7443, 7421, 7398, 7376, 7354, 7332, 7310, 7288,
|
||||
7265, 7243, 7221, 7199, 7177, 7155, 7132, 7110,
|
||||
7088, 7066, 7044, 7022, 7000, 6978, 6956, 6934,
|
||||
6911, 6889, 6867, 6845, 6823, 6801, 6779, 6757,
|
||||
6735, 6713, 6691, 6669, 6647, 6625, 6603, 6581,
|
||||
6559, 6537, 6515, 6493, 6472, 6450, 6428, 6406,
|
||||
6384, 6362, 6340, 6318, 6297, 6275, 6253, 6231,
|
||||
6209, 6188, 6166, 6144, 6122, 6101, 6079, 6057,
|
||||
6035, 6014, 5992, 5970, 5949, 5927, 5905, 5884,
|
||||
5862, 5841, 5819, 5797, 5776, 5754, 5733, 5711,
|
||||
5690, 5668, 5647, 5625, 5604, 5582, 5561, 5540,
|
||||
5518, 5497, 5476, 5454, 5433, 5412, 5390, 5369,
|
||||
5348, 5327, 5305, 5284, 5263, 5242, 5221, 5199,
|
||||
5178, 5157, 5136, 5115, 5094, 5073, 5052, 5031,
|
||||
5010, 4989, 4968, 4947, 4926, 4905, 4885, 4864,
|
||||
4843, 4822, 4801, 4780, 4760, 4739, 4718, 4698,
|
||||
4677, 4656, 4636, 4615, 4595, 4574, 4553, 4533,
|
||||
4512, 4492, 4471, 4451, 4431, 4410, 4390, 4370,
|
||||
4349, 4329, 4309, 4288, 4268, 4248, 4228, 4208,
|
||||
4188, 4167, 4147, 4127, 4107, 4087, 4067, 4047,
|
||||
4027, 4007, 3988, 3968, 3948, 3928, 3908, 3889,
|
||||
3869, 3849, 3829, 3810, 3790, 3771, 3751, 3732,
|
||||
3712, 3693, 3673, 3654, 3634, 3615, 3595, 3576,
|
||||
3557, 3538, 3518, 3499, 3480, 3461, 3442, 3423,
|
||||
3404, 3385, 3366, 3347, 3328, 3309, 3290, 3271,
|
||||
3252, 3233, 3215, 3196, 3177, 3159, 3140, 3121,
|
||||
3103, 3084, 3066, 3047, 3029, 3010, 2992, 2974,
|
||||
2955, 2937, 2919, 2901, 2882, 2864, 2846, 2828,
|
||||
2810, 2792, 2774, 2756, 2738, 2720, 2702, 2685,
|
||||
2667, 2649, 2631, 2614, 2596, 2579, 2561, 2543,
|
||||
2526, 2509, 2491, 2474, 2456, 2439, 2422, 2405,
|
||||
2387, 2370, 2353, 2336, 2319, 2302, 2285, 2268,
|
||||
2251, 2234, 2218, 2201, 2184, 2167, 2151, 2134,
|
||||
2117, 2101, 2084, 2068, 2052, 2035, 2019, 2003,
|
||||
1986, 1970, 1954, 1938, 1922, 1906, 1890, 1874,
|
||||
1858, 1842, 1826, 1810, 1794, 1779, 1763, 1747,
|
||||
1732, 1716, 1701, 1685, 1670, 1654, 1639, 1624,
|
||||
1608, 1593, 1578, 1563, 1548, 1533, 1518, 1503,
|
||||
1488, 1473, 1458, 1444, 1429, 1414, 1400, 1385,
|
||||
1370, 1356, 1342, 1327, 1313, 1298, 1284, 1270,
|
||||
1256, 1242, 1228, 1214, 1200, 1186, 1172, 1158,
|
||||
1144, 1131, 1117, 1103, 1090, 1076, 1063, 1049,
|
||||
1036, 1022, 1009, 996, 983, 970, 956, 943,
|
||||
930, 917, 905, 892, 879, 866, 854, 841,
|
||||
828, 816, 803, 791, 778, 766, 754, 742,
|
||||
729, 717, 705, 693, 681, 669, 658, 646,
|
||||
634, 622, 611, 599, 588, 576, 565, 553,
|
||||
542, 531, 520, 508, 497, 486, 475, 464,
|
||||
453, 443, 432, 421, 411, 400, 389, 379,
|
||||
369, 358, 348, 338, 327, 317, 307, 297,
|
||||
287, 277, 268, 258, 248, 238, 229, 219,
|
||||
210, 200, 191, 182, 172, 163, 154, 145,
|
||||
136, 127, 118, 109, 100, 92, 83, 75,
|
||||
66, 58, 49, 41, 32, 24, 16, 8,
|
||||
};
|
||||
|
||||
static int16 cubic_spline_lut2[1024] = {
|
||||
0, 8, 16, 24, 32, 41, 49, 58,
|
||||
66, 75, 83, 92, 100, 109, 118, 127,
|
||||
136, 145, 154, 163, 172, 182, 191, 200,
|
||||
210, 219, 229, 238, 248, 258, 268, 277,
|
||||
287, 297, 307, 317, 327, 338, 348, 358,
|
||||
369, 379, 389, 400, 411, 421, 432, 443,
|
||||
453, 464, 475, 486, 497, 508, 520, 531,
|
||||
542, 553, 565, 576, 588, 599, 611, 622,
|
||||
634, 646, 658, 669, 681, 693, 705, 717,
|
||||
729, 742, 754, 766, 778, 791, 803, 816,
|
||||
828, 841, 854, 866, 879, 892, 905, 917,
|
||||
930, 943, 956, 970, 983, 996, 1009, 1022,
|
||||
1036, 1049, 1063, 1076, 1090, 1103, 1117, 1131,
|
||||
1144, 1158, 1172, 1186, 1200, 1214, 1228, 1242,
|
||||
1256, 1270, 1284, 1298, 1313, 1327, 1342, 1356,
|
||||
1370, 1385, 1400, 1414, 1429, 1444, 1458, 1473,
|
||||
1488, 1503, 1518, 1533, 1548, 1563, 1578, 1593,
|
||||
1608, 1624, 1639, 1654, 1670, 1685, 1701, 1716,
|
||||
1732, 1747, 1763, 1779, 1794, 1810, 1826, 1842,
|
||||
1858, 1874, 1890, 1906, 1922, 1938, 1954, 1970,
|
||||
1986, 2003, 2019, 2035, 2052, 2068, 2084, 2101,
|
||||
2117, 2134, 2151, 2167, 2184, 2201, 2218, 2234,
|
||||
2251, 2268, 2285, 2302, 2319, 2336, 2353, 2370,
|
||||
2387, 2405, 2422, 2439, 2456, 2474, 2491, 2509,
|
||||
2526, 2543, 2561, 2579, 2596, 2614, 2631, 2649,
|
||||
2667, 2685, 2702, 2720, 2738, 2756, 2774, 2792,
|
||||
2810, 2828, 2846, 2864, 2882, 2901, 2919, 2937,
|
||||
2955, 2974, 2992, 3010, 3029, 3047, 3066, 3084,
|
||||
3103, 3121, 3140, 3159, 3177, 3196, 3215, 3233,
|
||||
3252, 3271, 3290, 3309, 3328, 3347, 3366, 3385,
|
||||
3404, 3423, 3442, 3461, 3480, 3499, 3518, 3538,
|
||||
3557, 3576, 3595, 3615, 3634, 3654, 3673, 3693,
|
||||
3712, 3732, 3751, 3771, 3790, 3810, 3829, 3849,
|
||||
3869, 3889, 3908, 3928, 3948, 3968, 3988, 4007,
|
||||
4027, 4047, 4067, 4087, 4107, 4127, 4147, 4167,
|
||||
4188, 4208, 4228, 4248, 4268, 4288, 4309, 4329,
|
||||
4349, 4370, 4390, 4410, 4431, 4451, 4471, 4492,
|
||||
4512, 4533, 4553, 4574, 4595, 4615, 4636, 4656,
|
||||
4677, 4698, 4718, 4739, 4760, 4780, 4801, 4822,
|
||||
4843, 4864, 4885, 4905, 4926, 4947, 4968, 4989,
|
||||
5010, 5031, 5052, 5073, 5094, 5115, 5136, 5157,
|
||||
5178, 5199, 5221, 5242, 5263, 5284, 5305, 5327,
|
||||
5348, 5369, 5390, 5412, 5433, 5454, 5476, 5497,
|
||||
5518, 5540, 5561, 5582, 5604, 5625, 5647, 5668,
|
||||
5690, 5711, 5733, 5754, 5776, 5797, 5819, 5841,
|
||||
5862, 5884, 5905, 5927, 5949, 5970, 5992, 6014,
|
||||
6035, 6057, 6079, 6101, 6122, 6144, 6166, 6188,
|
||||
6209, 6231, 6253, 6275, 6297, 6318, 6340, 6362,
|
||||
6384, 6406, 6428, 6450, 6472, 6493, 6515, 6537,
|
||||
6559, 6581, 6603, 6625, 6647, 6669, 6691, 6713,
|
||||
6735, 6757, 6779, 6801, 6823, 6845, 6867, 6889,
|
||||
6911, 6934, 6956, 6978, 7000, 7022, 7044, 7066,
|
||||
7088, 7110, 7132, 7155, 7177, 7199, 7221, 7243,
|
||||
7265, 7288, 7310, 7332, 7354, 7376, 7398, 7421,
|
||||
7443, 7465, 7487, 7509, 7531, 7554, 7576, 7598,
|
||||
7620, 7643, 7665, 7687, 7709, 7731, 7754, 7776,
|
||||
7798, 7820, 7842, 7865, 7887, 7909, 7931, 7954,
|
||||
7976, 7998, 8020, 8042, 8065, 8087, 8109, 8131,
|
||||
8154, 8176, 8198, 8220, 8242, 8265, 8287, 8309,
|
||||
8331, 8353, 8376, 8398, 8420, 8442, 8464, 8487,
|
||||
8509, 8531, 8553, 8575, 8597, 8620, 8642, 8664,
|
||||
8686, 8708, 8730, 8752, 8775, 8797, 8819, 8841,
|
||||
8863, 8885, 8907, 8929, 8951, 8974, 8996, 9018,
|
||||
9040, 9062, 9084, 9106, 9128, 9150, 9172, 9194,
|
||||
9216, 9238, 9260, 9282, 9304, 9326, 9348, 9370,
|
||||
9392, 9414, 9436, 9458, 9479, 9501, 9523, 9545,
|
||||
9567, 9589, 9611, 9633, 9653, 9676, 9698, 9720,
|
||||
9742, 9763, 9784, 9806, 9829, 9851, 9872, 9893,
|
||||
9915, 9936, 9959, 9981, 10002, 10023, 10045, 10068,
|
||||
10088, 10110, 10132, 10152, 10175, 10196, 10217, 10239,
|
||||
10260, 10283, 10303, 10325, 10346, 10368, 10389, 10410,
|
||||
10431, 10453, 10474, 10496, 10517, 10538, 10560, 10581,
|
||||
10602, 10623, 10644, 10666, 10687, 10708, 10728, 10750,
|
||||
10772, 10792, 10814, 10834, 10856, 10876, 10898, 10918,
|
||||
10939, 10959, 10982, 11002, 11023, 11043, 11064, 11084,
|
||||
11107, 11127, 11148, 11168, 11189, 11209, 11231, 11251,
|
||||
11272, 11292, 11313, 11333, 11354, 11374, 11394, 11415,
|
||||
11436, 11457, 11477, 11498, 11518, 11538, 11559, 11578,
|
||||
11599, 11619, 11640, 11660, 11680, 11700, 11720, 11741,
|
||||
11761, 11780, 11801, 11821, 11839, 11860, 11880, 11900,
|
||||
11920, 11940, 11960, 11980, 11998, 12019, 12039, 12059,
|
||||
12079, 12097, 12118, 12137, 12157, 12176, 12195, 12215,
|
||||
12235, 12254, 12273, 12293, 12312, 12332, 12351, 12370,
|
||||
12390, 12408, 12427, 12448, 12466, 12485, 12504, 12524,
|
||||
12542, 12562, 12580, 12599, 12618, 12637, 12655, 12675,
|
||||
12694, 12712, 12731, 12750, 12768, 12787, 12806, 12823,
|
||||
12842, 12860, 12879, 12898, 12916, 12934, 12953, 12971,
|
||||
12989, 13008, 13026, 13044, 13062, 13080, 13098, 13116,
|
||||
13134, 13152, 13170, 13188, 13205, 13224, 13241, 13258,
|
||||
13277, 13294, 13312, 13330, 13347, 13365, 13383, 13399,
|
||||
13417, 13435, 13451, 13469, 13486, 13504, 13521, 13538,
|
||||
13556, 13572, 13589, 13607, 13623, 13641, 13657, 13673,
|
||||
13691, 13707, 13724, 13741, 13758, 13775, 13791, 13808,
|
||||
13823, 13840, 13857, 13873, 13890, 13906, 13923, 13939,
|
||||
13955, 13971, 13986, 14003, 14019, 14035, 14051, 14067,
|
||||
14082, 14099, 14115, 14130, 14146, 14161, 14177, 14192,
|
||||
14208, 14223, 14239, 14254, 14270, 14285, 14301, 14316,
|
||||
14330, 14346, 14361, 14376, 14391, 14406, 14420, 14435,
|
||||
14450, 14465, 14480, 14494, 14509, 14523, 14538, 14553,
|
||||
14567, 14582, 14595, 14610, 14625, 14638, 14653, 14668,
|
||||
14681, 14696, 14709, 14723, 14737, 14752, 14764, 14778,
|
||||
14793, 14806, 14819, 14833, 14846, 14860, 14874, 14887,
|
||||
14900, 14913, 14927, 14940, 14953, 14966, 14979, 14992,
|
||||
15004, 15017, 15031, 15043, 15056, 15067, 15081, 15094,
|
||||
15106, 15118, 15131, 15143, 15155, 15167, 15180, 15192,
|
||||
15205, 15216, 15228, 15240, 15252, 15264, 15276, 15287,
|
||||
15299, 15310, 15321, 15333, 15345, 15356, 15367, 15379,
|
||||
15390, 15401, 15412, 15423, 15433, 15446, 15456, 15467,
|
||||
15478, 15489, 15499, 15509, 15520, 15530, 15540, 15552,
|
||||
15562, 15572, 15582, 15592, 15602, 15613, 15623, 15633,
|
||||
15642, 15652, 15662, 15672, 15681, 15691, 15700, 15709,
|
||||
15719, 15729, 15738, 15747, 15756, 15765, 15774, 15783,
|
||||
15792, 15801, 15810, 15818, 15827, 15836, 15843, 15853,
|
||||
15861, 15870, 15877, 15886, 15894, 15903, 15910, 15918,
|
||||
15926, 15934, 15941, 15949, 15957, 15964, 15973, 15980,
|
||||
15988, 15995, 16002, 16009, 16015, 16023, 16030, 16038,
|
||||
16044, 16052, 16058, 16064, 16071, 16077, 16085, 16092,
|
||||
16097, 16104, 16109, 16116, 16122, 16128, 16133, 16140,
|
||||
16146, 16151, 16158, 16163, 16169, 16174, 16180, 16185,
|
||||
16191, 16196, 16201, 16206, 16211, 16216, 16220, 16225,
|
||||
16230, 16235, 16239, 16244, 16247, 16253, 16257, 16262,
|
||||
16265, 16269, 16274, 16278, 16282, 16285, 16290, 16293,
|
||||
16297, 16299, 16304, 16307, 16309, 16314, 16317, 16320,
|
||||
16322, 16326, 16329, 16331, 16335, 16337, 16340, 16342,
|
||||
16345, 16347, 16349, 16351, 16354, 16357, 16358, 16360,
|
||||
16361, 16364, 16366, 16366, 16369, 16370, 16371, 16373,
|
||||
16374, 16376, 16377, 16377, 16379, 16379, 16380, 16381,
|
||||
16381, 16381, 16382, 16383, 16384, 16384, 16384, 16384,
|
||||
};
|
||||
|
||||
static int16 cubic_spline_lut3[1024] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, -1, -1, -1, -1, -1, -2, -2,
|
||||
-2, -2, -2, -3, -3, -3, -4, -4,
|
||||
-4, -5, -5, -6, -6, -6, -7, -7,
|
||||
-8, -8, -9, -9, -10, -10, -11, -11,
|
||||
-12, -13, -13, -14, -14, -15, -16, -16,
|
||||
-17, -18, -19, -19, -20, -21, -22, -22,
|
||||
-23, -24, -25, -26, -26, -27, -28, -29,
|
||||
-30, -31, -32, -33, -34, -35, -36, -37,
|
||||
-38, -39, -40, -41, -42, -43, -44, -45,
|
||||
-46, -47, -48, -49, -51, -52, -53, -54,
|
||||
-55, -57, -58, -59, -60, -61, -63, -64,
|
||||
-65, -67, -68, -69, -70, -72, -73, -75,
|
||||
-76, -77, -79, -80, -82, -83, -84, -86,
|
||||
-87, -89, -90, -92, -93, -95, -96, -98,
|
||||
-99, -101, -102, -104, -106, -107, -109, -110,
|
||||
-112, -114, -115, -117, -119, -120, -122, -124,
|
||||
-125, -127, -129, -130, -132, -134, -136, -137,
|
||||
-139, -141, -143, -145, -146, -148, -150, -152,
|
||||
-154, -156, -157, -159, -161, -163, -165, -167,
|
||||
-169, -171, -173, -175, -176, -178, -180, -182,
|
||||
-184, -186, -188, -190, -192, -194, -196, -198,
|
||||
-200, -202, -205, -207, -209, -211, -213, -215,
|
||||
-217, -219, -221, -223, -225, -228, -230, -232,
|
||||
-234, -236, -238, -240, -243, -245, -247, -249,
|
||||
-251, -254, -256, -258, -260, -263, -265, -267,
|
||||
-269, -272, -274, -276, -278, -281, -283, -285,
|
||||
-288, -290, -292, -295, -297, -299, -302, -304,
|
||||
-306, -309, -311, -313, -316, -318, -320, -323,
|
||||
-325, -328, -330, -332, -335, -337, -340, -342,
|
||||
-345, -347, -349, -352, -354, -357, -359, -362,
|
||||
-364, -367, -369, -372, -374, -377, -379, -382,
|
||||
-384, -387, -389, -392, -394, -397, -399, -402,
|
||||
-404, -407, -409, -412, -414, -417, -419, -422,
|
||||
-424, -427, -430, -432, -435, -437, -440, -442,
|
||||
-445, -448, -450, -453, -455, -458, -461, -463,
|
||||
-466, -468, -471, -474, -476, -479, -481, -484,
|
||||
-487, -489, -492, -495, -497, -500, -502, -505,
|
||||
-508, -510, -513, -516, -518, -521, -523, -526,
|
||||
-529, -531, -534, -537, -539, -542, -545, -547,
|
||||
-550, -553, -555, -558, -561, -563, -566, -569,
|
||||
-571, -574, -577, -579, -582, -585, -587, -590,
|
||||
-593, -595, -598, -601, -603, -606, -609, -611,
|
||||
-614, -617, -619, -622, -625, -627, -630, -633,
|
||||
-635, -638, -641, -643, -646, -649, -651, -654,
|
||||
-657, -659, -662, -665, -667, -670, -672, -675,
|
||||
-678, -680, -683, -686, -688, -691, -694, -696,
|
||||
-699, -702, -704, -707, -709, -712, -715, -717,
|
||||
-720, -723, -725, -728, -730, -733, -736, -738,
|
||||
-741, -744, -746, -749, -751, -754, -757, -759,
|
||||
-762, -764, -767, -769, -772, -775, -777, -780,
|
||||
-782, -785, -787, -790, -793, -795, -798, -800,
|
||||
-803, -805, -808, -810, -813, -815, -818, -820,
|
||||
-823, -825, -828, -830, -833, -835, -838, -840,
|
||||
-843, -845, -848, -850, -853, -855, -858, -860,
|
||||
-863, -865, -867, -870, -872, -875, -877, -880,
|
||||
-882, -884, -887, -889, -892, -894, -896, -899,
|
||||
-901, -903, -906, -908, -911, -913, -915, -918,
|
||||
-920, -922, -924, -927, -929, -931, -934, -936,
|
||||
-938, -941, -943, -945, -947, -950, -952, -954,
|
||||
-956, -958, -961, -963, -965, -967, -969, -972,
|
||||
-974, -976, -978, -980, -982, -985, -987, -989,
|
||||
-991, -993, -995, -997, -999, -1002, -1004, -1006,
|
||||
-1008, -1010, -1012, -1014, -1016, -1018, -1020, -1022,
|
||||
-1024, -1026, -1028, -1030, -1032, -1034, -1036, -1038,
|
||||
-1040, -1042, -1044, -1046, -1047, -1049, -1051, -1053,
|
||||
-1055, -1057, -1059, -1061, -1062, -1064, -1066, -1068,
|
||||
-1070, -1071, -1073, -1075, -1077, -1079, -1080, -1082,
|
||||
-1084, -1085, -1087, -1089, -1091, -1092, -1094, -1096,
|
||||
-1097, -1099, -1101, -1102, -1104, -1105, -1107, -1109,
|
||||
-1110, -1112, -1113, -1115, -1116, -1118, -1119, -1121,
|
||||
-1122, -1124, -1125, -1127, -1128, -1130, -1131, -1133,
|
||||
-1134, -1135, -1137, -1138, -1140, -1141, -1142, -1144,
|
||||
-1145, -1146, -1148, -1149, -1150, -1151, -1153, -1154,
|
||||
-1155, -1156, -1158, -1159, -1160, -1161, -1162, -1163,
|
||||
-1165, -1166, -1167, -1168, -1169, -1170, -1171, -1172,
|
||||
-1173, -1174, -1175, -1176, -1177, -1178, -1179, -1180,
|
||||
-1181, -1182, -1183, -1184, -1185, -1186, -1187, -1187,
|
||||
-1188, -1189, -1190, -1191, -1192, -1192, -1193, -1194,
|
||||
-1195, -1195, -1196, -1197, -1197, -1198, -1199, -1199,
|
||||
-1200, -1201, -1201, -1202, -1202, -1203, -1204, -1204,
|
||||
-1205, -1205, -1206, -1206, -1207, -1207, -1207, -1208,
|
||||
-1208, -1209, -1209, -1209, -1210, -1210, -1210, -1211,
|
||||
-1211, -1211, -1211, -1212, -1212, -1212, -1212, -1213,
|
||||
-1213, -1213, -1213, -1213, -1213, -1213, -1213, -1214,
|
||||
-1214, -1214, -1214, -1214, -1214, -1214, -1214, -1213,
|
||||
-1213, -1213, -1213, -1213, -1213, -1213, -1213, -1212,
|
||||
-1212, -1212, -1212, -1212, -1211, -1211, -1211, -1210,
|
||||
-1210, -1210, -1209, -1209, -1208, -1208, -1208, -1207,
|
||||
-1207, -1206, -1206, -1205, -1205, -1204, -1204, -1203,
|
||||
-1202, -1202, -1201, -1200, -1200, -1199, -1198, -1198,
|
||||
-1197, -1196, -1195, -1195, -1194, -1193, -1192, -1191,
|
||||
-1190, -1189, -1188, -1187, -1187, -1186, -1185, -1184,
|
||||
-1182, -1181, -1180, -1179, -1178, -1177, -1176, -1175,
|
||||
-1174, -1172, -1171, -1170, -1169, -1167, -1166, -1165,
|
||||
-1163, -1162, -1161, -1159, -1158, -1156, -1155, -1153,
|
||||
-1152, -1150, -1149, -1147, -1146, -1144, -1143, -1141,
|
||||
-1139, -1138, -1136, -1134, -1133, -1131, -1129, -1127,
|
||||
-1125, -1124, -1122, -1120, -1118, -1116, -1114, -1112,
|
||||
-1110, -1108, -1106, -1104, -1102, -1100, -1098, -1096,
|
||||
-1094, -1092, -1089, -1087, -1085, -1083, -1080, -1078,
|
||||
-1076, -1074, -1071, -1069, -1066, -1064, -1062, -1059,
|
||||
-1057, -1054, -1052, -1049, -1047, -1044, -1041, -1039,
|
||||
-1036, -1033, -1031, -1028, -1025, -1022, -1020, -1017,
|
||||
-1014, -1011, -1008, -1005, -1002, -999, -997, -994,
|
||||
-991, -987, -984, -981, -978, -975, -972, -969,
|
||||
-966, -962, -959, -956, -953, -949, -946, -943,
|
||||
-939, -936, -932, -929, -925, -922, -918, -915,
|
||||
-911, -908, -904, -900, -897, -893, -889, -886,
|
||||
-882, -878, -874, -870, -866, -863, -859, -855,
|
||||
-851, -847, -843, -839, -835, -831, -826, -822,
|
||||
-818, -814, -810, -806, -801, -797, -793, -788,
|
||||
-784, -780, -775, -771, -766, -762, -757, -753,
|
||||
-748, -744, -739, -734, -730, -725, -720, -715,
|
||||
-711, -706, -701, -696, -691, -686, -682, -677,
|
||||
-672, -667, -662, -656, -651, -646, -641, -636,
|
||||
-631, -626, -620, -615, -610, -604, -599, -594,
|
||||
-588, -583, -577, -572, -566, -561, -555, -550,
|
||||
-544, -538, -533, -527, -521, -515, -510, -504,
|
||||
-498, -492, -486, -480, -474, -468, -462, -456,
|
||||
-450, -444, -438, -432, -425, -419, -413, -407,
|
||||
-400, -394, -388, -381, -375, -368, -362, -355,
|
||||
-349, -342, -336, -329, -322, -316, -309, -302,
|
||||
-295, -289, -282, -275, -268, -261, -254, -247,
|
||||
-240, -233, -226, -219, -212, -205, -198, -190,
|
||||
-183, -176, -169, -161, -154, -146, -139, -132,
|
||||
-124, -117, -109, -101, -94, -86, -78, -71,
|
||||
-63, -55, -47, -40, -32, -24, -16, -8,
|
||||
};
|
||||
|
1626
internal/c/parts/audio/extras/libxmp-lite/read_event.c
Normal file
1626
internal/c/parts/audio/extras/libxmp-lite/read_event.c
Normal file
File diff suppressed because it is too large
Load diff
116
internal/c/parts/audio/extras/libxmp-lite/s3m.h
Normal file
116
internal/c/parts/audio/extras/libxmp-lite/s3m.h
Normal file
|
@ -0,0 +1,116 @@
|
|||
/* Extended Module Player
|
||||
* Copyright (C) 1996-2021 Claudio Matsuoka and Hipolito Carraro Jr
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/* S3M packed pattern macros */
|
||||
#define S3M_EOR 0 /* End of row */
|
||||
#define S3M_CH_MASK 0x1f /* Channel */
|
||||
#define S3M_NI_FOLLOW 0x20 /* Note and instrument follow */
|
||||
#define S3M_VOL_FOLLOWS 0x40 /* Volume follows */
|
||||
#define S3M_FX_FOLLOWS 0x80 /* Effect and parameter follow */
|
||||
|
||||
/* S3M channel info macros */
|
||||
#define S3M_CH_ON 0x80 /* Psi says it's bit 8, I'll assume bit 7 */
|
||||
#define S3M_CH_OFF 0xff
|
||||
#define S3M_CH_PAN 0x7f /* Left/Right */
|
||||
|
||||
/* S3M channel pan macros */
|
||||
#define S3M_PAN_SET 0x20
|
||||
#define S3M_PAN_MASK 0x0f
|
||||
|
||||
/* S3M flags */
|
||||
#define S3M_ST2_VIB 0x01 /* Not recognized */
|
||||
#define S3M_ST2_TEMPO 0x02 /* Not recognized */
|
||||
#define S3M_AMIGA_SLIDE 0x04 /* Not recognized */
|
||||
#define S3M_VOL_OPT 0x08 /* Not recognized */
|
||||
#define S3M_AMIGA_RANGE 0x10
|
||||
#define S3M_SB_FILTER 0x20 /* Not recognized */
|
||||
#define S3M_ST300_VOLS 0x40
|
||||
#define S3M_CUSTOM_DATA 0x80 /* Not recognized */
|
||||
|
||||
/* S3M Adlib instrument types */
|
||||
#define S3M_INST_SAMPLE 0x01
|
||||
#define S3M_INST_AMEL 0x02
|
||||
#define S3M_INST_ABD 0x03
|
||||
#define S3M_INST_ASNARE 0x04
|
||||
#define S3M_INST_ATOM 0x05
|
||||
#define S3M_INST_ACYM 0x06
|
||||
#define S3M_INST_AHIHAT 0x07
|
||||
|
||||
struct s3m_file_header {
|
||||
uint8 name[28]; /* Song name */
|
||||
uint8 doseof; /* 0x1a */
|
||||
uint8 type; /* File type */
|
||||
uint8 rsvd1[2]; /* Reserved */
|
||||
uint16 ordnum; /* Number of orders (must be even) */
|
||||
uint16 insnum; /* Number of instruments */
|
||||
uint16 patnum; /* Number of patterns */
|
||||
uint16 flags; /* Flags */
|
||||
uint16 version; /* Tracker ID and version */
|
||||
uint16 ffi; /* File format information */
|
||||
uint32 magic; /* 'SCRM' */
|
||||
uint8 gv; /* Global volume */
|
||||
uint8 is; /* Initial speed */
|
||||
uint8 it; /* Initial tempo */
|
||||
uint8 mv; /* Master volume */
|
||||
uint8 uc; /* Ultra click removal */
|
||||
uint8 dp; /* Default pan positions if 0xfc */
|
||||
uint8 rsvd2[8]; /* Reserved */
|
||||
uint16 special; /* Ptr to special custom data */
|
||||
uint8 chset[32]; /* Channel settings */
|
||||
};
|
||||
|
||||
struct s3m_instrument_header {
|
||||
uint8 dosname[13]; /* DOS file name */
|
||||
uint16 memseg; /* Pointer to sample data */
|
||||
uint32 length; /* Length */
|
||||
uint32 loopbeg; /* Loop begin */
|
||||
uint32 loopend; /* Loop end */
|
||||
uint8 vol; /* Volume */
|
||||
uint8 rsvd1; /* Reserved */
|
||||
uint8 pack; /* Packing type (not used) */
|
||||
uint8 flags; /* Loop/stereo/16bit samples flags */
|
||||
uint16 c2spd; /* C 4 speed */
|
||||
uint16 rsvd2; /* Reserved */
|
||||
uint8 rsvd3[4]; /* Reserved */
|
||||
uint16 int_gp; /* Internal - GUS pointer */
|
||||
uint16 int_512; /* Internal - SB pointer */
|
||||
uint32 int_last; /* Internal - SB index */
|
||||
uint8 name[28]; /* Instrument name */
|
||||
uint32 magic; /* 'SCRS' */
|
||||
};
|
||||
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
struct s3m_adlib_header {
|
||||
uint8 dosname[12]; /* DOS file name */
|
||||
uint8 rsvd1[3]; /* 0x00 0x00 0x00 */
|
||||
uint8 reg[12]; /* Adlib registers */
|
||||
uint8 vol;
|
||||
uint8 dsk;
|
||||
uint8 rsvd2[2];
|
||||
uint16 c2spd; /* C 4 speed */
|
||||
uint16 rsvd3; /* Reserved */
|
||||
uint8 rsvd4[12]; /* Reserved */
|
||||
uint8 name[28]; /* Instrument name */
|
||||
uint32 magic; /* 'SCRI' */
|
||||
};
|
||||
#endif
|
||||
|
625
internal/c/parts/audio/extras/libxmp-lite/s3m_load.c
Normal file
625
internal/c/parts/audio/extras/libxmp-lite/s3m_load.c
Normal file
|
@ -0,0 +1,625 @@
|
|||
/* Extended Module Player
|
||||
* Copyright (C) 1996-2021 Claudio Matsuoka and Hipolito Carraro Jr
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Tue, 30 Jun 1998 20:23:11 +0200
|
||||
* Reported by John v/d Kamp <blade_@dds.nl>:
|
||||
* I have this song from Purple Motion called wcharts.s3m, the global
|
||||
* volume was set to 0, creating a devide by 0 error in xmp. There should
|
||||
* be an extra test if it's 0 or not.
|
||||
*
|
||||
* Claudio's fix: global volume ignored
|
||||
*/
|
||||
|
||||
/*
|
||||
* Sat, 29 Aug 1998 18:50:43 -0500 (CDT)
|
||||
* Reported by Joel Jordan <scriber@usa.net>:
|
||||
* S3M files support tempos outside the ranges defined by xmp (that is,
|
||||
* the MOD/XM tempo ranges). S3M's can have tempos from 0 to 255 and speeds
|
||||
* from 0 to 255 as well, since these are handled with separate effects
|
||||
* unlike the MOD format. This becomes an issue in such songs as Skaven's
|
||||
* "Catch that Goblin", which uses speeds above 0x1f.
|
||||
*
|
||||
* Claudio's fix: FX_S3M_SPEED added. S3M supports speeds from 0 to 255 and
|
||||
* tempos from 32 to 255 (S3M speed == xmp tempo, S3M tempo == xmp BPM).
|
||||
*/
|
||||
|
||||
/* Wed, 21 Oct 1998 15:03:44 -0500 Geoff Reedy <vader21@imsa.edu>
|
||||
* It appears that xmp has issues loading/playing a specific instrument
|
||||
* used in LUCCA.S3M.
|
||||
* (Fixed by Hipolito in xmp-2.0.0dev34)
|
||||
*/
|
||||
|
||||
/*
|
||||
* From http://code.pui.ch/2007/02/18/turn-demoscene-modules-into-mp3s/
|
||||
* The only flaw I noticed [in xmp] is a problem with portamento in Purple
|
||||
* Motion's second reality soundtrack (1:06-1:17)
|
||||
*
|
||||
* Claudio's note: that's a dissonant beating between channels 6 and 7
|
||||
* starting at pos12, caused by pitchbending effect F25.
|
||||
*/
|
||||
|
||||
#include "loader.h"
|
||||
#include "s3m.h"
|
||||
#include "period.h"
|
||||
|
||||
#define MAGIC_SCRM MAGIC4('S','C','R','M')
|
||||
#define MAGIC_SCRI MAGIC4('S','C','R','I')
|
||||
#define MAGIC_SCRS MAGIC4('S','C','R','S')
|
||||
|
||||
static int s3m_test(HIO_HANDLE *, char *, const int);
|
||||
static int s3m_load(struct module_data *, HIO_HANDLE *, const int);
|
||||
|
||||
const struct format_loader libxmp_loader_s3m = {
|
||||
"Scream Tracker 3",
|
||||
s3m_test,
|
||||
s3m_load
|
||||
};
|
||||
|
||||
static int s3m_test(HIO_HANDLE *f, char *t, const int start)
|
||||
{
|
||||
hio_seek(f, start + 44, SEEK_SET);
|
||||
if (hio_read32b(f) != MAGIC_SCRM)
|
||||
return -1;
|
||||
|
||||
hio_seek(f, start + 29, SEEK_SET);
|
||||
if (hio_read8(f) != 0x10)
|
||||
return -1;
|
||||
|
||||
hio_seek(f, start + 0, SEEK_SET);
|
||||
libxmp_read_title(f, t, 28);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define NONE 0xff
|
||||
#define FX_S3M_EXTENDED 0xfe
|
||||
|
||||
/* Effect conversion table */
|
||||
static const uint8 fx[27] = {
|
||||
NONE,
|
||||
FX_S3M_SPEED, /* Axx Set speed to xx (the default is 06) */
|
||||
FX_JUMP, /* Bxx Jump to order xx (hexadecimal) */
|
||||
FX_BREAK, /* Cxx Break pattern to row xx (decimal) */
|
||||
FX_VOLSLIDE, /* Dxy Volume slide down by y/up by x */
|
||||
FX_PORTA_DN, /* Exx Slide down by xx */
|
||||
FX_PORTA_UP, /* Fxx Slide up by xx */
|
||||
FX_TONEPORTA, /* Gxx Tone portamento with speed xx */
|
||||
FX_VIBRATO, /* Hxy Vibrato with speed x and depth y */
|
||||
FX_TREMOR, /* Ixy Tremor with ontime x and offtime y */
|
||||
FX_S3M_ARPEGGIO, /* Jxy Arpeggio with halfnote additions */
|
||||
FX_VIBRA_VSLIDE, /* Kxy Dual command: H00 and Dxy */
|
||||
FX_TONE_VSLIDE, /* Lxy Dual command: G00 and Dxy */
|
||||
NONE,
|
||||
NONE,
|
||||
FX_OFFSET, /* Oxy Set sample offset */
|
||||
NONE,
|
||||
FX_MULTI_RETRIG, /* Qxy Retrig (+volumeslide) note */
|
||||
FX_TREMOLO, /* Rxy Tremolo with speed x and depth y */
|
||||
FX_S3M_EXTENDED, /* Sxx (misc effects) */
|
||||
FX_S3M_BPM, /* Txx Tempo = xx (hex) */
|
||||
FX_FINE_VIBRATO, /* Uxx Fine vibrato */
|
||||
FX_GLOBALVOL, /* Vxx Set global volume */
|
||||
NONE,
|
||||
FX_SETPAN, /* Xxx Set pan */
|
||||
NONE,
|
||||
NONE
|
||||
};
|
||||
|
||||
/* Effect translation */
|
||||
static void xlat_fx(int c, struct xmp_event *e)
|
||||
{
|
||||
uint8 h = MSN(e->fxp), l = LSN(e->fxp);
|
||||
|
||||
if (e->fxt >= ARRAY_SIZE(fx)) {
|
||||
D_(D_WARN "invalid effect %02x", e->fxt);
|
||||
e->fxt = e->fxp = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
switch (e->fxt = fx[e->fxt]) {
|
||||
case FX_S3M_BPM:
|
||||
if (e->fxp < 0x20) {
|
||||
e->fxp = e->fxt = 0;
|
||||
}
|
||||
break;
|
||||
case FX_S3M_EXTENDED: /* Extended effects */
|
||||
e->fxt = FX_EXTENDED;
|
||||
switch (h) {
|
||||
case 0x1: /* Glissando */
|
||||
e->fxp = LSN(e->fxp) | (EX_GLISS << 4);
|
||||
break;
|
||||
case 0x2: /* Finetune */
|
||||
e->fxp =
|
||||
((LSN(e->fxp) - 8) & 0x0f) | (EX_FINETUNE << 4);
|
||||
break;
|
||||
case 0x3: /* Vibrato wave */
|
||||
e->fxp = LSN(e->fxp) | (EX_VIBRATO_WF << 4);
|
||||
break;
|
||||
case 0x4: /* Tremolo wave */
|
||||
e->fxp = LSN(e->fxp) | (EX_TREMOLO_WF << 4);
|
||||
break;
|
||||
case 0x5:
|
||||
case 0x6:
|
||||
case 0x7:
|
||||
case 0x9:
|
||||
case 0xa: /* Ignore */
|
||||
e->fxt = e->fxp = 0;
|
||||
break;
|
||||
case 0x8: /* Set pan */
|
||||
e->fxt = FX_SETPAN;
|
||||
e->fxp = l << 4;
|
||||
break;
|
||||
case 0xb: /* Pattern loop */
|
||||
e->fxp = LSN(e->fxp) | (EX_PATTERN_LOOP << 4);
|
||||
break;
|
||||
case 0xc:
|
||||
if (!l)
|
||||
e->fxt = e->fxp = 0;
|
||||
}
|
||||
break;
|
||||
case FX_SETPAN:
|
||||
/* Saga Musix says: "The X effect in S3M files is not
|
||||
* exclusive to IT and clones. You will find tons of S3Ms made
|
||||
* with ST3 itself using this effect (and relying on an
|
||||
* external player being used). X in S3M also behaves
|
||||
* differently than in IT, which your code does not seem to
|
||||
* handle: X00 - X80 is left... right, XA4 is surround (like
|
||||
* S91 in IT), other values are not supposed to do anything.
|
||||
*/
|
||||
if (e->fxp == 0xa4) {
|
||||
// surround
|
||||
e->fxt = FX_SURROUND;
|
||||
e->fxp = 1;
|
||||
} else {
|
||||
int pan = ((int)e->fxp) << 1;
|
||||
if (pan > 0xff) {
|
||||
pan = 0xff;
|
||||
}
|
||||
e->fxp = pan;
|
||||
}
|
||||
break;
|
||||
case NONE: /* No effect */
|
||||
e->fxt = e->fxp = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int s3m_load(struct module_data *m, HIO_HANDLE * f, const int start)
|
||||
{
|
||||
struct xmp_module *mod = &m->mod;
|
||||
int c, r, i;
|
||||
struct xmp_event *event = 0, dummy;
|
||||
struct s3m_file_header sfh;
|
||||
struct s3m_instrument_header sih;
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
struct s3m_adlib_header sah;
|
||||
char tracker_name[40];
|
||||
#endif
|
||||
int pat_len;
|
||||
uint8 n, b;
|
||||
uint16 *pp_ins; /* Parapointers to instruments */
|
||||
uint16 *pp_pat; /* Parapointers to patterns */
|
||||
int ret;
|
||||
uint8 buf[96]
|
||||
|
||||
LOAD_INIT();
|
||||
|
||||
if (hio_read(buf, 1, 96, f) != 96) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
memcpy(sfh.name, buf, 28); /* Song name */
|
||||
sfh.type = buf[30]; /* File type */
|
||||
sfh.ordnum = readmem16l(buf + 32); /* Number of orders (must be even) */
|
||||
sfh.insnum = readmem16l(buf + 34); /* Number of instruments */
|
||||
sfh.patnum = readmem16l(buf + 36); /* Number of patterns */
|
||||
sfh.flags = readmem16l(buf + 38); /* Flags */
|
||||
sfh.version = readmem16l(buf + 40); /* Tracker ID and version */
|
||||
sfh.ffi = readmem16l(buf + 42); /* File format information */
|
||||
|
||||
/* Sanity check */
|
||||
if (sfh.ffi != 1 && sfh.ffi != 2) {
|
||||
goto err;
|
||||
}
|
||||
if (sfh.ordnum > 255 || sfh.insnum > 255 || sfh.patnum > 255) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
sfh.magic = readmem32b(buf + 44); /* 'SCRM' */
|
||||
sfh.gv = buf[48]; /* Global volume */
|
||||
sfh.is = buf[49]; /* Initial speed */
|
||||
sfh.it = buf[50]; /* Initial tempo */
|
||||
sfh.mv = buf[51]; /* Master volume */
|
||||
sfh.uc = buf[52]; /* Ultra click removal */
|
||||
sfh.dp = buf[53]; /* Default pan positions if 0xfc */
|
||||
memcpy(sfh.rsvd2, buf + 54, 8); /* Reserved */
|
||||
sfh.special = readmem16l(buf + 62); /* Ptr to special custom data */
|
||||
memcpy(sfh.chset, buf + 64, 32); /* Channel settings */
|
||||
|
||||
if (sfh.magic != MAGIC_SCRM) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
libxmp_copy_adjust(mod->name, sfh.name, 28);
|
||||
|
||||
pp_ins = calloc(2, sfh.insnum);
|
||||
if (pp_ins == NULL) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
pp_pat = calloc(2, sfh.patnum);
|
||||
if (pp_pat == NULL) {
|
||||
goto err2;
|
||||
}
|
||||
|
||||
if (sfh.flags & S3M_AMIGA_RANGE) {
|
||||
m->period_type = PERIOD_MODRNG;
|
||||
}
|
||||
if (sfh.flags & S3M_ST300_VOLS) {
|
||||
m->quirk |= QUIRK_VSALL;
|
||||
}
|
||||
/* m->volbase = 4096 / sfh.gv; */
|
||||
mod->spd = sfh.is;
|
||||
mod->bpm = sfh.it;
|
||||
mod->chn = 0;
|
||||
|
||||
for (i = 0; i < 32; i++) {
|
||||
if (sfh.chset[i] == S3M_CH_OFF)
|
||||
continue;
|
||||
|
||||
mod->chn = i + 1;
|
||||
|
||||
if (sfh.mv & 0x80) { /* stereo */
|
||||
int x = sfh.chset[i] & S3M_CH_PAN;
|
||||
mod->xxc[i].pan = (x & 0x0f) < 8 ? 0x30 : 0xc0;
|
||||
} else {
|
||||
mod->xxc[i].pan = 0x80;
|
||||
}
|
||||
}
|
||||
|
||||
if (sfh.ordnum <= XMP_MAX_MOD_LENGTH) {
|
||||
mod->len = sfh.ordnum;
|
||||
if (hio_read(mod->xxo, 1, mod->len, f) != mod->len) {
|
||||
goto err3;
|
||||
}
|
||||
} else {
|
||||
mod->len = XMP_MAX_MOD_LENGTH;
|
||||
if (hio_read(mod->xxo, 1, mod->len, f) != mod->len) {
|
||||
goto err3;
|
||||
}
|
||||
if (hio_seek(f, sfh.ordnum - XMP_MAX_MOD_LENGTH, SEEK_CUR) < 0) {
|
||||
goto err3;
|
||||
}
|
||||
}
|
||||
|
||||
/* Don't trust sfh.patnum */
|
||||
mod->pat = -1;
|
||||
for (i = 0; i < mod->len; ++i) {
|
||||
if (mod->xxo[i] < 0xfe && mod->xxo[i] > mod->pat) {
|
||||
mod->pat = mod->xxo[i];
|
||||
}
|
||||
}
|
||||
mod->pat++;
|
||||
if (mod->pat > sfh.patnum) {
|
||||
mod->pat = sfh.patnum;
|
||||
}
|
||||
if (mod->pat == 0) {
|
||||
goto err3;
|
||||
}
|
||||
|
||||
mod->trk = mod->pat * mod->chn;
|
||||
/* Load and convert header */
|
||||
mod->ins = sfh.insnum;
|
||||
mod->smp = mod->ins;
|
||||
|
||||
for (i = 0; i < sfh.insnum; i++) {
|
||||
pp_ins[i] = hio_read16l(f);
|
||||
}
|
||||
|
||||
for (i = 0; i < sfh.patnum; i++) {
|
||||
pp_pat[i] = hio_read16l(f);
|
||||
}
|
||||
|
||||
/* Default pan positions */
|
||||
|
||||
for (i = 0, sfh.dp -= 0xfc; !sfh.dp /* && n */ && (i < 32); i++) {
|
||||
uint8 x = hio_read8(f);
|
||||
if (x & S3M_PAN_SET) {
|
||||
mod->xxc[i].pan = (x << 4) & 0xff;
|
||||
} else {
|
||||
mod->xxc[i].pan =
|
||||
sfh.mv % 0x80 ? 0x30 + 0xa0 * (i & 1) : 0x80;
|
||||
}
|
||||
}
|
||||
|
||||
m->c4rate = C4_NTSC_RATE;
|
||||
|
||||
if (sfh.version == 0x1300) {
|
||||
m->quirk |= QUIRK_VSALL;
|
||||
}
|
||||
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
switch (sfh.version >> 12) {
|
||||
case 1:
|
||||
snprintf(tracker_name, 40, "Scream Tracker %d.%02x",
|
||||
(sfh.version & 0x0f00) >> 8, sfh.version & 0xff);
|
||||
m->quirk |= QUIRK_ST3BUGS;
|
||||
break;
|
||||
case 2:
|
||||
snprintf(tracker_name, 40, "Imago Orpheus %d.%02x",
|
||||
(sfh.version & 0x0f00) >> 8, sfh.version & 0xff);
|
||||
break;
|
||||
case 3:
|
||||
if (sfh.version == 0x3216) {
|
||||
strcpy(tracker_name, "Impulse Tracker 2.14v3");
|
||||
} else if (sfh.version == 0x3217) {
|
||||
strcpy(tracker_name, "Impulse Tracker 2.14v5");
|
||||
} else {
|
||||
snprintf(tracker_name, 40, "Impulse Tracker %d.%02x",
|
||||
(sfh.version & 0x0f00) >> 8,
|
||||
sfh.version & 0xff);
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
snprintf(tracker_name, 40, "OpenMPT %d.%02x",
|
||||
(sfh.version & 0x0f00) >> 8, sfh.version & 0xff);
|
||||
m->quirk |= QUIRK_ST3BUGS;
|
||||
break;
|
||||
case 4:
|
||||
if (sfh.version != 0x4100) {
|
||||
libxmp_schism_tracker_string(tracker_name, 40,
|
||||
(sfh.version & 0x0fff), sfh.rsvd2[0] | (sfh.rsvd2[1] << 8));
|
||||
break;
|
||||
}
|
||||
/* fall through */
|
||||
case 6:
|
||||
snprintf(tracker_name, 40, "BeRoTracker %d.%02x",
|
||||
(sfh.version & 0x0f00) >> 8, sfh.version & 0xff);
|
||||
break;
|
||||
default:
|
||||
snprintf(tracker_name, 40, "unknown (%04x)", sfh.version);
|
||||
}
|
||||
|
||||
libxmp_set_type(m, "%s S3M", tracker_name);
|
||||
#else
|
||||
libxmp_set_type(m, "Scream Tracker 3");
|
||||
m->quirk |= QUIRK_ST3BUGS;
|
||||
#endif
|
||||
|
||||
MODULE_INFO();
|
||||
|
||||
if (libxmp_init_pattern(mod) < 0)
|
||||
goto err3;
|
||||
|
||||
/* Read patterns */
|
||||
|
||||
D_(D_INFO "Stored patterns: %d", mod->pat);
|
||||
|
||||
for (i = 0; i < mod->pat; i++) {
|
||||
if (libxmp_alloc_pattern_tracks(mod, i, 64) < 0)
|
||||
goto err3;
|
||||
|
||||
if (pp_pat[i] == 0)
|
||||
continue;
|
||||
|
||||
hio_seek(f, start + pp_pat[i] * 16, SEEK_SET);
|
||||
r = 0;
|
||||
pat_len = hio_read16l(f) - 2;
|
||||
|
||||
while (pat_len >= 0 && r < mod->xxp[i]->rows) {
|
||||
b = hio_read8(f);
|
||||
|
||||
if (hio_error(f)) {
|
||||
goto err3;
|
||||
}
|
||||
|
||||
if (b == S3M_EOR) {
|
||||
r++;
|
||||
continue;
|
||||
}
|
||||
|
||||
c = b & S3M_CH_MASK;
|
||||
event = c >= mod->chn ? &dummy : &EVENT(i, c, r);
|
||||
|
||||
if (b & S3M_NI_FOLLOW) {
|
||||
switch (n = hio_read8(f)) {
|
||||
case 255:
|
||||
n = 0;
|
||||
break; /* Empty note */
|
||||
case 254:
|
||||
n = XMP_KEY_OFF;
|
||||
break; /* Key off */
|
||||
default:
|
||||
n = 13 + 12 * MSN(n) + LSN(n);
|
||||
}
|
||||
event->note = n;
|
||||
event->ins = hio_read8(f);
|
||||
pat_len -= 2;
|
||||
}
|
||||
|
||||
if (b & S3M_VOL_FOLLOWS) {
|
||||
event->vol = hio_read8(f) + 1;
|
||||
pat_len--;
|
||||
}
|
||||
|
||||
if (b & S3M_FX_FOLLOWS) {
|
||||
event->fxt = hio_read8(f);
|
||||
event->fxp = hio_read8(f);
|
||||
xlat_fx(c, event);
|
||||
|
||||
pat_len -= 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
D_(D_INFO "Stereo enabled: %s", sfh.mv & 0x80 ? "yes" : "no");
|
||||
D_(D_INFO "Pan settings: %s", sfh.dp ? "no" : "yes");
|
||||
|
||||
if (libxmp_init_instrument(m) < 0)
|
||||
goto err3;
|
||||
|
||||
/* Read and convert instruments and samples */
|
||||
|
||||
D_(D_INFO "Instruments: %d", mod->ins);
|
||||
|
||||
for (i = 0; i < mod->ins; i++) {
|
||||
struct xmp_instrument *xxi = &mod->xxi[i];
|
||||
struct xmp_sample *xxs = &mod->xxs[i];
|
||||
struct xmp_subinstrument *sub;
|
||||
int load_sample_flags;
|
||||
|
||||
xxi->sub = calloc(sizeof(struct xmp_subinstrument), 1);
|
||||
if (xxi->sub == NULL) {
|
||||
goto err3;
|
||||
}
|
||||
|
||||
sub = &xxi->sub[0];
|
||||
|
||||
hio_seek(f, start + pp_ins[i] * 16, SEEK_SET);
|
||||
sub->pan = 0x80;
|
||||
sub->sid = i;
|
||||
|
||||
if (hio_read(buf, 1, 80, f) != 80) {
|
||||
goto err3;
|
||||
}
|
||||
|
||||
if (buf[0] >= 2) {
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
/* OPL2 FM instrument */
|
||||
|
||||
memcpy(sah.dosname, buf + 1, 12); /* DOS file name */
|
||||
memcpy(sah.reg, buf + 16, 12); /* Adlib registers */
|
||||
sah.vol = buf[28];
|
||||
sah.dsk = buf[29];
|
||||
sah.c2spd = readmem16l(buf + 32); /* C4 speed */
|
||||
memcpy(sah.name, buf + 48, 28); /* Instrument name */
|
||||
sah.magic = readmem32b(buf + 76); /* 'SCRI' */
|
||||
|
||||
if (sah.magic != MAGIC_SCRI) {
|
||||
D_(D_CRIT "error: FM instrument magic");
|
||||
goto err3;
|
||||
}
|
||||
sah.magic = 0;
|
||||
|
||||
libxmp_instrument_name(mod, i, sah.name, 28);
|
||||
|
||||
xxi->nsm = 1;
|
||||
sub->vol = sah.vol;
|
||||
libxmp_c2spd_to_note(sah.c2spd, &sub->xpo, &sub->fin);
|
||||
sub->xpo += 12;
|
||||
ret =
|
||||
libxmp_load_sample(m, f, SAMPLE_FLAG_ADLIB, xxs,
|
||||
(char *)sah.reg);
|
||||
if (ret < 0)
|
||||
goto err3;
|
||||
|
||||
D_(D_INFO "[%2X] %-28.28s", i, xxi->name);
|
||||
|
||||
continue;
|
||||
#else
|
||||
goto err3;
|
||||
#endif
|
||||
}
|
||||
|
||||
memcpy(sih.dosname, buf + 1, 13); /* DOS file name */
|
||||
sih.memseg = readmem16l(buf + 14); /* Pointer to sample data */
|
||||
sih.length = readmem32l(buf + 16); /* Length */
|
||||
|
||||
#if 0
|
||||
/* ST3 limit */
|
||||
if ((sfh.version >> 12) == 1 && sih.length > 64000)
|
||||
sih.length = 64000;
|
||||
#endif
|
||||
|
||||
if (sih.length > MAX_SAMPLE_SIZE) {
|
||||
goto err3;
|
||||
}
|
||||
|
||||
sih.loopbeg = readmem32l(buf + 20); /* Loop begin */
|
||||
sih.loopend = readmem32l(buf + 24); /* Loop end */
|
||||
sih.vol = buf[28]; /* Volume */
|
||||
sih.pack = buf[30]; /* Packing type */
|
||||
sih.flags = buf[31]; /* Loop/stereo/16bit flags */
|
||||
sih.c2spd = readmem16l(buf + 32); /* C4 speed */
|
||||
memcpy(sih.name, buf + 48, 28); /* Instrument name */
|
||||
sih.magic = readmem32b(buf + 76); /* 'SCRS' */
|
||||
|
||||
if (buf[0] == 1 && sih.magic != MAGIC_SCRS) {
|
||||
D_(D_CRIT "error: instrument magic");
|
||||
goto err3;
|
||||
}
|
||||
|
||||
xxs->len = sih.length;
|
||||
xxi->nsm = sih.length > 0 ? 1 : 0;
|
||||
xxs->lps = sih.loopbeg;
|
||||
xxs->lpe = sih.loopend;
|
||||
|
||||
xxs->flg = sih.flags & 1 ? XMP_SAMPLE_LOOP : 0;
|
||||
|
||||
if (sih.flags & 4) {
|
||||
xxs->flg |= XMP_SAMPLE_16BIT;
|
||||
}
|
||||
|
||||
load_sample_flags = (sfh.ffi == 1) ? 0 : SAMPLE_FLAG_UNS;
|
||||
if (sih.pack == 4) {
|
||||
load_sample_flags = SAMPLE_FLAG_ADPCM;
|
||||
}
|
||||
|
||||
sub->vol = sih.vol;
|
||||
sih.magic = 0;
|
||||
|
||||
libxmp_instrument_name(mod, i, sih.name, 28);
|
||||
|
||||
D_(D_INFO "[%2X] %-28.28s %04x%c%04x %04x %c V%02x %5d",
|
||||
i, mod->xxi[i].name, mod->xxs[i].len,
|
||||
xxs->flg & XMP_SAMPLE_16BIT ? '+' : ' ',
|
||||
xxs->lps, mod->xxs[i].lpe,
|
||||
xxs->flg & XMP_SAMPLE_LOOP ? 'L' : ' ', sub->vol, sih.c2spd);
|
||||
|
||||
libxmp_c2spd_to_note(sih.c2spd, &sub->xpo, &sub->fin);
|
||||
|
||||
if (hio_seek(f, start + 16L * sih.memseg, SEEK_SET) < 0) {
|
||||
goto err3;
|
||||
}
|
||||
|
||||
ret = libxmp_load_sample(m, f, load_sample_flags, xxs, NULL);
|
||||
if (ret < 0) {
|
||||
goto err3;
|
||||
}
|
||||
}
|
||||
|
||||
free(pp_pat);
|
||||
free(pp_ins);
|
||||
|
||||
m->quirk |= QUIRKS_ST3 | QUIRK_ARPMEM;
|
||||
m->read_event_type = READ_EVENT_ST3;
|
||||
|
||||
return 0;
|
||||
|
||||
err3:
|
||||
free(pp_pat);
|
||||
err2:
|
||||
free(pp_ins);
|
||||
err:
|
||||
return -1;
|
||||
}
|
445
internal/c/parts/audio/extras/libxmp-lite/sample.c
Normal file
445
internal/c/parts/audio/extras/libxmp-lite/sample.c
Normal file
|
@ -0,0 +1,445 @@
|
|||
/* Extended Module Player
|
||||
* Copyright (C) 1996-2021 Claudio Matsuoka and Hipolito Carraro Jr
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "loader.h"
|
||||
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
|
||||
/*
|
||||
* From the Audio File Formats (version 2.5)
|
||||
* Submitted-by: Guido van Rossum <guido@cwi.nl>
|
||||
* Last-modified: 27-Aug-1992
|
||||
*
|
||||
* The Acorn Archimedes uses a variation on U-LAW with the bit order
|
||||
* reversed and the sign bit in bit 0. Being a 'minority' architecture,
|
||||
* Arc owners are quite adept at converting sound/image formats from
|
||||
* other machines, and it is unlikely that you'll ever encounter sound in
|
||||
* one of the Arc's own formats (there are several).
|
||||
*/
|
||||
static const int8 vdic_table[128] = {
|
||||
/* 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
/* 8 */ 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
/* 16 */ 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
/* 24 */ 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
/* 32 */ 1, 1, 1, 1, 2, 2, 2, 2,
|
||||
/* 40 */ 2, 2, 2, 2, 3, 3, 3, 3,
|
||||
/* 48 */ 3, 3, 4, 4, 4, 4, 5, 5,
|
||||
/* 56 */ 5, 5, 6, 6, 6, 6, 7, 7,
|
||||
/* 64 */ 7, 8, 8, 9, 9, 10, 10, 11,
|
||||
/* 72 */ 11, 12, 12, 13, 13, 14, 14, 15,
|
||||
/* 80 */ 15, 16, 17, 18, 19, 20, 21, 22,
|
||||
/* 88 */ 23, 24, 25, 26, 27, 28, 29, 30,
|
||||
/* 96 */ 31, 33, 34, 36, 38, 40, 42, 44,
|
||||
/* 104 */ 46, 48, 50, 52, 54, 56, 58, 60,
|
||||
/* 112 */ 62, 65, 68, 72, 77, 80, 84, 91,
|
||||
/* 120 */ 95, 98, 103, 109, 114, 120, 126, 127
|
||||
};
|
||||
|
||||
|
||||
/* Convert 7 bit samples to 8 bit */
|
||||
static void convert_7bit_to_8bit(uint8 *p, int l)
|
||||
{
|
||||
for (; l--; p++) {
|
||||
*p <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert Archimedes VIDC samples to linear */
|
||||
static void convert_vidc_to_linear(uint8 *p, int l)
|
||||
{
|
||||
int i;
|
||||
uint8 x;
|
||||
|
||||
for (i = 0; i < l; i++) {
|
||||
x = p[i];
|
||||
p[i] = vdic_table[x >> 1];
|
||||
if (x & 0x01)
|
||||
p[i] *= -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void adpcm4_decoder(uint8 *inp, uint8 *outp, char *tab, int len)
|
||||
{
|
||||
char delta = 0;
|
||||
uint8 b0, b1;
|
||||
int i;
|
||||
|
||||
len = (len + 1) / 2;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
b0 = *inp;
|
||||
b1 = *inp++ >> 4;
|
||||
delta += tab[b0 & 0x0f];
|
||||
*outp++ = delta;
|
||||
delta += tab[b1 & 0x0f];
|
||||
*outp++ = delta;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* Convert differential to absolute sample data */
|
||||
static void convert_delta(uint8 *p, int l, int r)
|
||||
{
|
||||
uint16 *w = (uint16 *)p;
|
||||
uint16 abs = 0;
|
||||
|
||||
if (r) {
|
||||
for (; l--;) {
|
||||
abs = *w + abs;
|
||||
*w++ = abs;
|
||||
}
|
||||
} else {
|
||||
for (; l--;) {
|
||||
abs = *p + abs;
|
||||
*p++ = (uint8) abs;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert signed to unsigned sample data */
|
||||
static void convert_signal(uint8 *p, int l, int r)
|
||||
{
|
||||
uint16 *w = (uint16 *)p;
|
||||
|
||||
if (r) {
|
||||
for (; l--; w++)
|
||||
*w += 0x8000;
|
||||
} else {
|
||||
for (; l--; p++)
|
||||
*p += (char)0x80; /* cast needed by MSVC++ */
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert little-endian 16 bit samples to big-endian */
|
||||
static void convert_endian(uint8 *p, int l)
|
||||
{
|
||||
uint8 b;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < l; i++) {
|
||||
b = p[0];
|
||||
p[0] = p[1];
|
||||
p[1] = b;
|
||||
p += 2;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* Downmix stereo samples to mono */
|
||||
static void convert_stereo_to_mono(uint8 *p, int l, int r)
|
||||
{
|
||||
int16 *b = (int16 *)p;
|
||||
int i;
|
||||
|
||||
if (r) {
|
||||
l /= 2;
|
||||
for (i = 0; i < l; i++)
|
||||
b[i] = (b[i * 2] + b[i * 2 + 1]) / 2;
|
||||
} else {
|
||||
for (i = 0; i < l; i++)
|
||||
p[i] = (p[i * 2] + p[i * 2 + 1]) / 2;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void unroll_loop(struct xmp_sample *xxs)
|
||||
{
|
||||
int8 *s8;
|
||||
int16 *s16;
|
||||
int start, loop_size;
|
||||
int i;
|
||||
|
||||
s16 = (int16 *)xxs->data;
|
||||
s8 = (int8 *)xxs->data;
|
||||
|
||||
if (xxs->len > xxs->lpe) {
|
||||
start = xxs->lpe;
|
||||
} else {
|
||||
start = xxs->len;
|
||||
}
|
||||
|
||||
loop_size = xxs->lpe - xxs->lps;
|
||||
|
||||
if (xxs->flg & XMP_SAMPLE_16BIT) {
|
||||
s16 += start;
|
||||
for (i = 0; i < loop_size; i++) {
|
||||
*(s16 + i) = *(s16 - i - 1);
|
||||
}
|
||||
} else {
|
||||
s8 += start;
|
||||
for (i = 0; i < loop_size; i++) {
|
||||
*(s8 + i) = *(s8 - i - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int libxmp_load_sample(struct module_data *m, HIO_HANDLE *f, int flags, struct xmp_sample *xxs, const void *buffer)
|
||||
{
|
||||
int bytelen, extralen, unroll_extralen, i;
|
||||
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
/* Adlib FM patches */
|
||||
if (flags & SAMPLE_FLAG_ADLIB) {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Empty or invalid samples
|
||||
*/
|
||||
if (xxs->len <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Skip sample loading
|
||||
* FIXME: fails for ADPCM samples
|
||||
*
|
||||
* + Sanity check: skip huge samples (likely corrupt module)
|
||||
*/
|
||||
if (xxs->len > MAX_SAMPLE_SIZE || (m && m->smpctl & XMP_SMPCTL_SKIP)) {
|
||||
if (~flags & SAMPLE_FLAG_NOLOAD) {
|
||||
/* coverity[check_return] */
|
||||
hio_seek(f, xxs->len, SEEK_CUR);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If this sample starts at or after EOF, skip it entirely.
|
||||
*/
|
||||
if (~flags & SAMPLE_FLAG_NOLOAD) {
|
||||
long file_pos, file_len;
|
||||
if (!f) {
|
||||
return 0;
|
||||
}
|
||||
file_pos = hio_tell(f);
|
||||
file_len = hio_size(f);
|
||||
if (file_pos >= file_len) {
|
||||
D_(D_WARN "ignoring sample at EOF");
|
||||
return 0;
|
||||
}
|
||||
/* If this sample goes past EOF, truncate it. */
|
||||
if (file_pos + xxs->len > file_len && (~flags & SAMPLE_FLAG_ADPCM)) {
|
||||
D_(D_WARN "sample would extend %ld bytes past EOF; truncating to %ld",
|
||||
file_pos + xxs->len - file_len, file_len - file_pos);
|
||||
xxs->len = file_len - file_pos;
|
||||
}
|
||||
}
|
||||
|
||||
/* Loop parameters sanity check
|
||||
*/
|
||||
if (xxs->lps < 0) {
|
||||
xxs->lps = 0;
|
||||
}
|
||||
if (xxs->lpe > xxs->len) {
|
||||
xxs->lpe = xxs->len;
|
||||
}
|
||||
if (xxs->lps >= xxs->len || xxs->lps >= xxs->lpe) {
|
||||
xxs->lps = xxs->lpe = 0;
|
||||
xxs->flg &= ~(XMP_SAMPLE_LOOP | XMP_SAMPLE_LOOP_BIDIR);
|
||||
}
|
||||
|
||||
/* Patches with samples
|
||||
* Allocate extra sample for interpolation.
|
||||
*/
|
||||
bytelen = xxs->len;
|
||||
extralen = 4;
|
||||
unroll_extralen = 0;
|
||||
|
||||
/* Disable birectional loop flag if sample is not looped
|
||||
*/
|
||||
if (xxs->flg & XMP_SAMPLE_LOOP_BIDIR) {
|
||||
if (~xxs->flg & XMP_SAMPLE_LOOP)
|
||||
xxs->flg &= ~XMP_SAMPLE_LOOP_BIDIR;
|
||||
}
|
||||
/* Unroll bidirectional loops
|
||||
*/
|
||||
if (xxs->flg & XMP_SAMPLE_LOOP_BIDIR) {
|
||||
unroll_extralen = (xxs->lpe - xxs->lps) -
|
||||
(xxs->len - xxs->lpe);
|
||||
|
||||
if (unroll_extralen < 0) {
|
||||
unroll_extralen = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (xxs->flg & XMP_SAMPLE_16BIT) {
|
||||
bytelen *= 2;
|
||||
extralen *= 2;
|
||||
unroll_extralen *= 2;
|
||||
}
|
||||
|
||||
/* add guard bytes before the buffer for higher order interpolation */
|
||||
xxs->data = malloc(bytelen + extralen + unroll_extralen + 4);
|
||||
if (xxs->data == NULL) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
*(uint32 *)xxs->data = 0;
|
||||
xxs->data += 4;
|
||||
|
||||
if (flags & SAMPLE_FLAG_NOLOAD) {
|
||||
memcpy(xxs->data, buffer, bytelen);
|
||||
} else
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
if (flags & SAMPLE_FLAG_ADPCM) {
|
||||
int x2 = (bytelen + 1) >> 1;
|
||||
char table[16];
|
||||
|
||||
if (hio_read(table, 1, 16, f) != 16) {
|
||||
goto err2;
|
||||
}
|
||||
if (hio_read(xxs->data + x2, 1, x2, f) != x2) {
|
||||
goto err2;
|
||||
}
|
||||
adpcm4_decoder((uint8 *)xxs->data + x2,
|
||||
(uint8 *)xxs->data, table, bytelen);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
int x = hio_read(xxs->data, 1, bytelen, f);
|
||||
if (x != bytelen) {
|
||||
D_(D_WARN "short read (%d) in sample load", x - bytelen);
|
||||
memset(xxs->data + x, 0, bytelen - x);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
if (flags & SAMPLE_FLAG_7BIT) {
|
||||
convert_7bit_to_8bit(xxs->data, xxs->len);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Fix endianism if needed */
|
||||
if (xxs->flg & XMP_SAMPLE_16BIT) {
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
if (~flags & SAMPLE_FLAG_BIGEND)
|
||||
convert_endian(xxs->data, xxs->len);
|
||||
#else
|
||||
if (flags & SAMPLE_FLAG_BIGEND)
|
||||
convert_endian(xxs->data, xxs->len);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Convert delta samples */
|
||||
if (flags & SAMPLE_FLAG_DIFF) {
|
||||
convert_delta(xxs->data, xxs->len, xxs->flg & XMP_SAMPLE_16BIT);
|
||||
} else if (flags & SAMPLE_FLAG_8BDIFF) {
|
||||
int len = xxs->len;
|
||||
if (xxs->flg & XMP_SAMPLE_16BIT) {
|
||||
len *= 2;
|
||||
}
|
||||
convert_delta(xxs->data, len, 0);
|
||||
}
|
||||
|
||||
/* Convert samples to signed */
|
||||
if (flags & SAMPLE_FLAG_UNS) {
|
||||
convert_signal(xxs->data, xxs->len,
|
||||
xxs->flg & XMP_SAMPLE_16BIT);
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* Downmix stereo samples */
|
||||
if (flags & SAMPLE_FLAG_STEREO) {
|
||||
convert_stereo_to_mono(xxs->data, xxs->len,
|
||||
xxs->flg & XMP_SAMPLE_16BIT);
|
||||
xxs->len /= 2;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
if (flags & SAMPLE_FLAG_VIDC) {
|
||||
convert_vidc_to_linear(xxs->data, xxs->len);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Check for full loop samples */
|
||||
if (flags & SAMPLE_FLAG_FULLREP) {
|
||||
if (xxs->lps == 0 && xxs->len > xxs->lpe)
|
||||
xxs->flg |= XMP_SAMPLE_LOOP_FULL;
|
||||
}
|
||||
|
||||
/* Unroll bidirectional loops */
|
||||
if (xxs->flg & XMP_SAMPLE_LOOP_BIDIR) {
|
||||
unroll_loop(xxs);
|
||||
bytelen += unroll_extralen;
|
||||
}
|
||||
|
||||
/* Add extra samples at end */
|
||||
if (xxs->flg & XMP_SAMPLE_16BIT) {
|
||||
for (i = 0; i < 8; i++) {
|
||||
xxs->data[bytelen + i] = xxs->data[bytelen - 2 + i];
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < 4; i++) {
|
||||
xxs->data[bytelen + i] = xxs->data[bytelen - 1 + i];
|
||||
}
|
||||
}
|
||||
|
||||
/* Add extra samples at start */
|
||||
if (xxs->flg & XMP_SAMPLE_16BIT) {
|
||||
xxs->data[-2] = xxs->data[0];
|
||||
xxs->data[-1] = xxs->data[1];
|
||||
} else {
|
||||
xxs->data[-1] = xxs->data[0];
|
||||
}
|
||||
|
||||
/* Fix sample at loop */
|
||||
if (xxs->flg & XMP_SAMPLE_LOOP) {
|
||||
int lpe = xxs->lpe;
|
||||
int lps = xxs->lps;
|
||||
|
||||
if (xxs->flg & XMP_SAMPLE_LOOP_BIDIR) {
|
||||
lpe += lpe - lps;
|
||||
}
|
||||
|
||||
if (xxs->flg & XMP_SAMPLE_16BIT) {
|
||||
lpe <<= 1;
|
||||
lps <<= 1;
|
||||
for (i = 0; i < 8; i++) {
|
||||
xxs->data[lpe + i] = xxs->data[lps + i];
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < 4; i++) {
|
||||
xxs->data[lpe + i] = xxs->data[lps + i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
err2:
|
||||
libxmp_free_sample(xxs);
|
||||
#endif
|
||||
err:
|
||||
return -1;
|
||||
}
|
||||
|
||||
void libxmp_free_sample(struct xmp_sample *s)
|
||||
{
|
||||
if (s->data) {
|
||||
free(s->data - 4);
|
||||
s->data = NULL; /* prevent double free in PCM load error */
|
||||
}
|
||||
}
|
580
internal/c/parts/audio/extras/libxmp-lite/scan.c
Normal file
580
internal/c/parts/audio/extras/libxmp-lite/scan.c
Normal file
|
@ -0,0 +1,580 @@
|
|||
/* Extended Module Player
|
||||
* Copyright (C) 1996-2021 Claudio Matsuoka and Hipolito Carraro Jr
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Sun, 31 May 1998 17:50:02 -0600
|
||||
* Reported by ToyKeeper <scriven@CS.ColoState.EDU>:
|
||||
* For loop-prevention, I know a way to do it which lets most songs play
|
||||
* fine once through even if they have backward-jumps. Just keep a small
|
||||
* array (256 bytes, or even bits) of flags, each entry determining if a
|
||||
* pattern in the song order has been played. If you get to an entry which
|
||||
* is already non-zero, skip to the next song (assuming looping is off).
|
||||
*/
|
||||
|
||||
/*
|
||||
* Tue, 6 Oct 1998 21:23:17 +0200 (CEST)
|
||||
* Reported by John v/d Kamp <blade_@dds.nl>:
|
||||
* scan.c was hanging when it jumps to an invalid restart value.
|
||||
* (Fixed by hipolito)
|
||||
*/
|
||||
|
||||
|
||||
#include "common.h"
|
||||
#include "effects.h"
|
||||
#include "mixer.h"
|
||||
|
||||
#define S3M_END 0xff
|
||||
#define S3M_SKIP 0xfe
|
||||
|
||||
|
||||
static int scan_module(struct context_data *ctx, int ep, int chain)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
struct module_data *m = &ctx->m;
|
||||
struct xmp_module *mod = &m->mod;
|
||||
int parm, gvol_memory, f1, f2, p1, p2, ord, ord2;
|
||||
int row, last_row, break_row, row_count, row_count_total;
|
||||
int orders_since_last_valid, any_valid;
|
||||
int gvl, bpm, speed, base_time, chn;
|
||||
int frame_count;
|
||||
double time, start_time;
|
||||
int loop_chn, loop_num, inside_loop;
|
||||
int pdelay = 0;
|
||||
int loop_count[XMP_MAX_CHANNELS];
|
||||
int loop_row[XMP_MAX_CHANNELS];
|
||||
struct xmp_event* event;
|
||||
int i, pat;
|
||||
int has_marker;
|
||||
struct ord_data *info;
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
int st26_speed;
|
||||
#endif
|
||||
|
||||
if (mod->len == 0)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < mod->len; i++) {
|
||||
int pat = mod->xxo[i];
|
||||
memset(m->scan_cnt[i], 0, pat >= mod->pat ? 1 :
|
||||
mod->xxp[pat]->rows ? mod->xxp[pat]->rows : 1);
|
||||
}
|
||||
|
||||
for (i = 0; i < mod->chn; i++) {
|
||||
loop_count[i] = 0;
|
||||
loop_row[i] = -1;
|
||||
}
|
||||
loop_num = 0;
|
||||
loop_chn = -1;
|
||||
|
||||
gvl = mod->gvl;
|
||||
bpm = mod->bpm;
|
||||
|
||||
speed = mod->spd;
|
||||
base_time = m->rrate;
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
st26_speed = 0;
|
||||
#endif
|
||||
|
||||
has_marker = HAS_QUIRK(QUIRK_MARKER);
|
||||
|
||||
/* By erlk ozlr <erlk.ozlr@gmail.com>
|
||||
*
|
||||
* xmp doesn't handle really properly the "start" option (-s for the
|
||||
* command-line) for DeusEx's .umx files. These .umx files contain
|
||||
* several loop "tracks" that never join together. That's how they put
|
||||
* multiple musics on each level with a file per level. Each "track"
|
||||
* starts at the same order in all files. The problem is that xmp starts
|
||||
* decoding the module at order 0 and not at the order specified with
|
||||
* the start option. If we have a module that does "0 -> 2 -> 0 -> ...",
|
||||
* we cannot play order 1, even with the supposed right option.
|
||||
*
|
||||
* was: ord2 = ord = -1;
|
||||
*
|
||||
* CM: Fixed by using different "sequences" for each loop or subsong.
|
||||
* Each sequence has its entry point. Sequences don't overlap.
|
||||
*/
|
||||
ord2 = -1;
|
||||
ord = ep - 1;
|
||||
|
||||
gvol_memory = break_row = row_count = row_count_total = frame_count = 0;
|
||||
orders_since_last_valid = any_valid = 0;
|
||||
start_time = time = 0.0;
|
||||
inside_loop = 0;
|
||||
|
||||
while (42) {
|
||||
/* Sanity check to prevent getting stuck due to broken patterns. */
|
||||
if (orders_since_last_valid > 512) {
|
||||
D_(D_CRIT "orders_since_last_valid = %d @ ord %d; ending scan", orders_since_last_valid, ord);
|
||||
break;
|
||||
}
|
||||
orders_since_last_valid++;
|
||||
|
||||
if ((uint32)++ord >= mod->len) {
|
||||
if (mod->rst > mod->len || mod->xxo[mod->rst] >= mod->pat) {
|
||||
ord = ep;
|
||||
} else {
|
||||
if (libxmp_get_sequence(ctx, mod->rst) == chain) {
|
||||
ord = mod->rst;
|
||||
} else {
|
||||
ord = ep;
|
||||
}
|
||||
}
|
||||
|
||||
pat = mod->xxo[ord];
|
||||
if (has_marker && pat == S3M_END) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pat = mod->xxo[ord];
|
||||
info = &m->xxo_info[ord];
|
||||
|
||||
/* Allow more complex order reuse only in main sequence */
|
||||
if (ep != 0 && p->sequence_control[ord] != 0xff) {
|
||||
break;
|
||||
}
|
||||
p->sequence_control[ord] = chain;
|
||||
|
||||
/* All invalid patterns skipped, only S3M_END aborts replay */
|
||||
if (pat >= mod->pat) {
|
||||
if (has_marker && pat == S3M_END) {
|
||||
ord = mod->len;
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (break_row >= mod->xxp[pat]->rows) {
|
||||
break_row = 0;
|
||||
}
|
||||
|
||||
/* Loops can cross pattern boundaries, so check if we're not looping */
|
||||
if (m->scan_cnt[ord][break_row] && !inside_loop) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Only update pattern information if we weren't here before. This also
|
||||
* means that we don't update pattern information if we're inside a loop,
|
||||
* otherwise a loop containing e.g. a global volume fade can make the
|
||||
* pattern start with the wrong volume. (fixes xyce-dans_la_rue.xm replay,
|
||||
* see https://github.com/libxmp/libxmp/issues/153 for more details).
|
||||
*/
|
||||
if (info->time < 0) {
|
||||
info->gvl = gvl;
|
||||
info->bpm = bpm;
|
||||
info->speed = speed;
|
||||
info->time = time + m->time_factor * frame_count * base_time / bpm;
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
info->st26_speed = st26_speed;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (info->start_row == 0 && ord != 0) {
|
||||
if (ord == ep) {
|
||||
start_time = time + m->time_factor * frame_count * base_time / bpm;
|
||||
}
|
||||
|
||||
info->start_row = break_row;
|
||||
}
|
||||
|
||||
last_row = mod->xxp[pat]->rows;
|
||||
for (row = break_row, break_row = 0; row < last_row; row++, row_count++, row_count_total++) {
|
||||
/* Prevent crashes caused by large softmixer frames */
|
||||
if (bpm < XMP_MIN_BPM) {
|
||||
bpm = XMP_MIN_BPM;
|
||||
}
|
||||
|
||||
/* Date: Sat, 8 Sep 2007 04:01:06 +0200
|
||||
* Reported by Zbigniew Luszpinski <zbiggy@o2.pl>
|
||||
* The scan routine falls into infinite looping and doesn't let
|
||||
* xmp play jos-dr4k.xm.
|
||||
* Claudio's workaround: we'll break infinite loops here.
|
||||
*
|
||||
* Date: Oct 27, 2007 8:05 PM
|
||||
* From: Adric Riedel <adric.riedel@gmail.com>
|
||||
* Jesper Kyd: Global Trash 3.mod (the 'Hardwired' theme) only
|
||||
* plays the first 4:41 of what should be a 10 minute piece.
|
||||
* (...) it dies at the end of position 2F
|
||||
*/
|
||||
|
||||
if (row_count_total > 512) { /* was 255, but Global trash goes to 318. */
|
||||
D_(D_CRIT "row_count_total = %d @ ord %d, pat %d, row %d; ending scan", row_count_total, ord, pat, row);
|
||||
goto end_module;
|
||||
}
|
||||
|
||||
if (!loop_num && m->scan_cnt[ord][row]) {
|
||||
row_count--;
|
||||
goto end_module;
|
||||
}
|
||||
m->scan_cnt[ord][row]++;
|
||||
orders_since_last_valid = 0;
|
||||
any_valid = 1;
|
||||
|
||||
/* If the scan count for this row overflows, break.
|
||||
* A scan count of 0 will help break this loop in playback (storlek_11.it).
|
||||
*/
|
||||
if (!m->scan_cnt[ord][row]) {
|
||||
goto end_module;
|
||||
}
|
||||
|
||||
pdelay = 0;
|
||||
|
||||
for (chn = 0; chn < mod->chn; chn++) {
|
||||
if (row >= mod->xxt[mod->xxp[pat]->index[chn]]->rows)
|
||||
continue;
|
||||
|
||||
event = &EVENT(mod->xxo[ord], chn, row);
|
||||
|
||||
f1 = event->fxt;
|
||||
p1 = event->fxp;
|
||||
f2 = event->f2t;
|
||||
p2 = event->f2p;
|
||||
|
||||
if (f1 == FX_GLOBALVOL || f2 == FX_GLOBALVOL) {
|
||||
gvl = (f1 == FX_GLOBALVOL) ? p1 : p2;
|
||||
gvl = gvl > m->gvolbase ? m->gvolbase : gvl < 0 ? 0 : gvl;
|
||||
}
|
||||
|
||||
/* Process fine global volume slide */
|
||||
if (f1 == FX_GVOL_SLIDE || f2 == FX_GVOL_SLIDE) {
|
||||
int h, l;
|
||||
parm = (f1 == FX_GVOL_SLIDE) ? p1 : p2;
|
||||
|
||||
process_gvol:
|
||||
if (parm) {
|
||||
gvol_memory = parm;
|
||||
h = MSN(parm);
|
||||
l = LSN(parm);
|
||||
|
||||
if (HAS_QUIRK(QUIRK_FINEFX)) {
|
||||
if (l == 0xf && h != 0) {
|
||||
gvl += h;
|
||||
} else if (h == 0xf && l != 0) {
|
||||
gvl -= l;
|
||||
} else {
|
||||
if (m->quirk & QUIRK_VSALL) {
|
||||
gvl += (h - l) * speed;
|
||||
} else {
|
||||
gvl += (h - l) * (speed - 1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (m->quirk & QUIRK_VSALL) {
|
||||
gvl += (h - l) * speed;
|
||||
} else {
|
||||
gvl += (h - l) * (speed - 1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ((parm = gvol_memory) != 0)
|
||||
goto process_gvol;
|
||||
}
|
||||
}
|
||||
|
||||
if ((f1 == FX_SPEED && p1) || (f2 == FX_SPEED && p2)) {
|
||||
parm = (f1 == FX_SPEED) ? p1 : p2;
|
||||
frame_count += row_count * speed;
|
||||
row_count = 0;
|
||||
if (parm) {
|
||||
if (HAS_QUIRK(QUIRK_NOBPM) || p->flags & XMP_FLAGS_VBLANK || parm < 0x20) {
|
||||
if (parm > 0) {
|
||||
speed = parm;
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
st26_speed = 0;
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
time += m->time_factor * frame_count * base_time / bpm;
|
||||
frame_count = 0;
|
||||
bpm = parm;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
if (f1 == FX_SPEED_CP) {
|
||||
f1 = FX_S3M_SPEED;
|
||||
}
|
||||
if (f2 == FX_SPEED_CP) {
|
||||
f2 = FX_S3M_SPEED;
|
||||
}
|
||||
|
||||
/* ST2.6 speed processing */
|
||||
|
||||
if (f1 == FX_ICE_SPEED && p1) {
|
||||
if (LSN(p1)) {
|
||||
st26_speed = (MSN(p1) << 8) | LSN(p1);
|
||||
} else {
|
||||
st26_speed = MSN(p1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((f1 == FX_S3M_SPEED && p1) || (f2 == FX_S3M_SPEED && p2)) {
|
||||
parm = (f1 == FX_S3M_SPEED) ? p1 : p2;
|
||||
if (parm > 0) {
|
||||
frame_count += row_count * speed;
|
||||
row_count = 0;
|
||||
speed = parm;
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
st26_speed = 0;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if ((f1 == FX_S3M_BPM && p1) || (f2 == FX_S3M_BPM && p2)) {
|
||||
parm = (f1 == FX_S3M_BPM) ? p1 : p2;
|
||||
if (parm >= 0x20) {
|
||||
frame_count += row_count * speed;
|
||||
row_count = 0;
|
||||
time += m->time_factor * frame_count * base_time / bpm;
|
||||
frame_count = 0;
|
||||
bpm = parm;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef LIBXMP_CORE_DISABLE_IT
|
||||
if ((f1 == FX_IT_BPM && p1) || (f2 == FX_IT_BPM && p2)) {
|
||||
parm = (f1 == FX_IT_BPM) ? p1 : p2;
|
||||
frame_count += row_count * speed;
|
||||
row_count = 0;
|
||||
time += m->time_factor * frame_count * base_time / bpm;
|
||||
frame_count = 0;
|
||||
|
||||
if (MSN(parm) == 0) {
|
||||
time += m->time_factor * base_time / bpm;
|
||||
for (i = 1; i < speed; i++) {
|
||||
bpm -= LSN(parm);
|
||||
if (bpm < 0x20)
|
||||
bpm = 0x20;
|
||||
time += m->time_factor * base_time / bpm;
|
||||
}
|
||||
|
||||
/* remove one row at final bpm */
|
||||
time -= m->time_factor * speed * base_time / bpm;
|
||||
|
||||
} else if (MSN(parm) == 1) {
|
||||
time += m->time_factor * base_time / bpm;
|
||||
for (i = 1; i < speed; i++) {
|
||||
bpm += LSN(parm);
|
||||
if (bpm > 0xff)
|
||||
bpm = 0xff;
|
||||
time += m->time_factor * base_time / bpm;
|
||||
}
|
||||
|
||||
/* remove one row at final bpm */
|
||||
time -= m->time_factor * speed * base_time / bpm;
|
||||
|
||||
} else {
|
||||
bpm = parm;
|
||||
}
|
||||
}
|
||||
|
||||
if (f1 == FX_IT_ROWDELAY) {
|
||||
/* Don't allow the scan count for this row to overflow here. */
|
||||
int x = m->scan_cnt[ord][row] + (p1 & 0x0f);
|
||||
m->scan_cnt[ord][row] = MIN(x, 255);
|
||||
frame_count += (p1 & 0x0f) * speed;
|
||||
}
|
||||
|
||||
if (f1 == FX_IT_BREAK) {
|
||||
break_row = p1;
|
||||
last_row = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (f1 == FX_JUMP || f2 == FX_JUMP) {
|
||||
ord2 = (f1 == FX_JUMP) ? p1 : p2;
|
||||
break_row = 0;
|
||||
last_row = 0;
|
||||
|
||||
/* prevent infinite loop, see OpenMPT PatLoop-Various.xm */
|
||||
inside_loop = 0;
|
||||
}
|
||||
|
||||
if (f1 == FX_BREAK || f2 == FX_BREAK) {
|
||||
parm = (f1 == FX_BREAK) ? p1 : p2;
|
||||
break_row = 10 * MSN(parm) + LSN(parm);
|
||||
last_row = 0;
|
||||
}
|
||||
|
||||
if (f1 == FX_EXTENDED || f2 == FX_EXTENDED) {
|
||||
parm = (f1 == FX_EXTENDED) ? p1 : p2;
|
||||
|
||||
if ((parm >> 4) == EX_PATT_DELAY) {
|
||||
if (m->read_event_type != READ_EVENT_ST3 || !pdelay) {
|
||||
pdelay = parm & 0x0f;
|
||||
frame_count += pdelay * speed;
|
||||
}
|
||||
}
|
||||
|
||||
if ((parm >> 4) == EX_PATTERN_LOOP) {
|
||||
if (parm &= 0x0f) {
|
||||
/* Loop end */
|
||||
if (loop_count[chn]) {
|
||||
if (--loop_count[chn]) {
|
||||
/* next iteraction */
|
||||
loop_chn = chn;
|
||||
} else {
|
||||
/* finish looping */
|
||||
loop_num--;
|
||||
inside_loop = 0;
|
||||
if (m->quirk & QUIRK_S3MLOOP)
|
||||
loop_row[chn] = row;
|
||||
}
|
||||
} else {
|
||||
loop_count[chn] = parm;
|
||||
loop_chn = chn;
|
||||
loop_num++;
|
||||
}
|
||||
} else {
|
||||
/* Loop start */
|
||||
loop_row[chn] = row - 1;
|
||||
inside_loop = 1;
|
||||
if (HAS_QUIRK(QUIRK_FT2BUGS))
|
||||
break_row = row;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (loop_chn >= 0) {
|
||||
row = loop_row[loop_chn];
|
||||
loop_chn = -1;
|
||||
}
|
||||
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
if (st26_speed) {
|
||||
frame_count += row_count * speed;
|
||||
row_count = 0;
|
||||
if (st26_speed & 0x10000) {
|
||||
speed = (st26_speed & 0xff00) >> 8;
|
||||
} else {
|
||||
speed = st26_speed & 0xff;
|
||||
}
|
||||
st26_speed ^= 0x10000;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (break_row && pdelay) {
|
||||
break_row++;
|
||||
}
|
||||
|
||||
if (ord2 >= 0) {
|
||||
ord = ord2 - 1;
|
||||
ord2 = -1;
|
||||
}
|
||||
|
||||
frame_count += row_count * speed;
|
||||
row_count_total = 0;
|
||||
row_count = 0;
|
||||
}
|
||||
row = break_row;
|
||||
|
||||
end_module:
|
||||
|
||||
/* Sanity check */
|
||||
{
|
||||
if (!any_valid) {
|
||||
return -1;
|
||||
}
|
||||
pat = mod->xxo[ord];
|
||||
if (pat >= mod->pat || row >= mod->xxp[pat]->rows) {
|
||||
row = 0;
|
||||
}
|
||||
}
|
||||
|
||||
p->scan[chain].num = m->scan_cnt[ord][row];
|
||||
p->scan[chain].row = row;
|
||||
p->scan[chain].ord = ord;
|
||||
|
||||
time -= start_time;
|
||||
frame_count += row_count * speed;
|
||||
|
||||
return (time + m->time_factor * frame_count * base_time / bpm);
|
||||
}
|
||||
|
||||
int libxmp_get_sequence(struct context_data *ctx, int ord)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
return p->sequence_control[ord];
|
||||
}
|
||||
|
||||
int libxmp_scan_sequences(struct context_data *ctx)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
struct module_data *m = &ctx->m;
|
||||
struct xmp_module *mod = &m->mod;
|
||||
int i, ep;
|
||||
int seq;
|
||||
unsigned char temp_ep[XMP_MAX_MOD_LENGTH];
|
||||
|
||||
/* Initialize order data to prevent overwrite when a position is used
|
||||
* multiple times at different starting points (see janosik.xm).
|
||||
*/
|
||||
for (i = 0; i < XMP_MAX_MOD_LENGTH; i++) {
|
||||
m->xxo_info[i].time = -1;
|
||||
}
|
||||
|
||||
ep = 0;
|
||||
memset(p->sequence_control, 0xff, XMP_MAX_MOD_LENGTH);
|
||||
temp_ep[0] = 0;
|
||||
p->scan[0].time = scan_module(ctx, ep, 0);
|
||||
seq = 1;
|
||||
|
||||
if (p->scan[0].time < 0) {
|
||||
D_(D_CRIT "scan was not able to find any valid orders");
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
/* Scan song starting at given entry point */
|
||||
/* Check if any patterns left */
|
||||
for (i = 0; i < mod->len; i++) {
|
||||
if (p->sequence_control[i] == 0xff) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i != mod->len && seq < MAX_SEQUENCES) {
|
||||
/* New entry point */
|
||||
ep = i;
|
||||
temp_ep[seq] = ep;
|
||||
p->scan[seq].time = scan_module(ctx, ep, seq);
|
||||
if (p->scan[seq].time > 0)
|
||||
seq++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
m->num_sequences = seq;
|
||||
|
||||
/* Now place entry points in the public accessible array */
|
||||
for (i = 0; i < m->num_sequences; i++) {
|
||||
m->seq_data[i].entry_point = temp_ep[i];
|
||||
m->seq_data[i].duration = p->scan[i].time;
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
331
internal/c/parts/audio/extras/libxmp-lite/smix.c
Normal file
331
internal/c/parts/audio/extras/libxmp-lite/smix.c
Normal file
|
@ -0,0 +1,331 @@
|
|||
/* Extended Module Player
|
||||
* Copyright (C) 1996-2021 Claudio Matsuoka and Hipolito Carraro Jr
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "period.h"
|
||||
#include "player.h"
|
||||
#include "hio.h"
|
||||
#include "loader.h"
|
||||
|
||||
|
||||
struct xmp_instrument *libxmp_get_instrument(struct context_data *ctx, int ins)
|
||||
{
|
||||
struct smix_data *smix = &ctx->smix;
|
||||
struct module_data *m = &ctx->m;
|
||||
struct xmp_module *mod = &m->mod;
|
||||
struct xmp_instrument *xxi;
|
||||
|
||||
if (ins < mod->ins) {
|
||||
xxi = &mod->xxi[ins];
|
||||
} else if (ins < mod->ins + smix->ins) {
|
||||
xxi = &smix->xxi[ins - mod->ins];
|
||||
} else {
|
||||
xxi = NULL;
|
||||
}
|
||||
|
||||
return xxi;
|
||||
}
|
||||
|
||||
struct xmp_sample *libxmp_get_sample(struct context_data *ctx, int smp)
|
||||
{
|
||||
struct smix_data *smix = &ctx->smix;
|
||||
struct module_data *m = &ctx->m;
|
||||
struct xmp_module *mod = &m->mod;
|
||||
struct xmp_sample *xxs;
|
||||
|
||||
if (smp < mod->smp) {
|
||||
xxs = &mod->xxs[smp];
|
||||
} else if (smp < mod->smp + smix->smp) {
|
||||
xxs = &smix->xxs[smp - mod->smp];
|
||||
} else {
|
||||
xxs = NULL;
|
||||
}
|
||||
|
||||
return xxs;
|
||||
}
|
||||
|
||||
int xmp_start_smix(xmp_context opaque, int chn, int smp)
|
||||
{
|
||||
struct context_data *ctx = (struct context_data *)opaque;
|
||||
struct smix_data *smix = &ctx->smix;
|
||||
|
||||
if (ctx->state > XMP_STATE_LOADED) {
|
||||
return -XMP_ERROR_STATE;
|
||||
}
|
||||
|
||||
smix->xxi = calloc(sizeof (struct xmp_instrument), smp);
|
||||
if (smix->xxi == NULL) {
|
||||
goto err;
|
||||
}
|
||||
smix->xxs = calloc(sizeof (struct xmp_sample), smp);
|
||||
if (smix->xxs == NULL) {
|
||||
goto err1;
|
||||
}
|
||||
|
||||
smix->chn = chn;
|
||||
smix->ins = smix->smp = smp;
|
||||
|
||||
return 0;
|
||||
|
||||
err1:
|
||||
free(smix->xxi);
|
||||
smix->xxi = NULL;
|
||||
err:
|
||||
return -XMP_ERROR_INTERNAL;
|
||||
}
|
||||
|
||||
int xmp_smix_play_instrument(xmp_context opaque, int ins, int note, int vol, int chn)
|
||||
{
|
||||
struct context_data *ctx = (struct context_data *)opaque;
|
||||
struct player_data *p = &ctx->p;
|
||||
struct smix_data *smix = &ctx->smix;
|
||||
struct module_data *m = &ctx->m;
|
||||
struct xmp_module *mod = &m->mod;
|
||||
struct xmp_event *event;
|
||||
|
||||
if (ctx->state < XMP_STATE_PLAYING) {
|
||||
return -XMP_ERROR_STATE;
|
||||
}
|
||||
|
||||
if (chn >= smix->chn || ins >= mod->ins) {
|
||||
return -XMP_ERROR_INVALID;
|
||||
}
|
||||
|
||||
if (note == 0) {
|
||||
note = 60; /* middle C note number */
|
||||
}
|
||||
|
||||
event = &p->inject_event[mod->chn + chn];
|
||||
memset(event, 0, sizeof (struct xmp_event));
|
||||
event->note = note + 1;
|
||||
event->ins = ins + 1;
|
||||
event->vol = vol + 1;
|
||||
event->_flag = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int xmp_smix_play_sample(xmp_context opaque, int ins, int note, int vol, int chn)
|
||||
{
|
||||
struct context_data *ctx = (struct context_data *)opaque;
|
||||
struct player_data *p = &ctx->p;
|
||||
struct smix_data *smix = &ctx->smix;
|
||||
struct module_data *m = &ctx->m;
|
||||
struct xmp_module *mod = &m->mod;
|
||||
struct xmp_event *event;
|
||||
|
||||
if (ctx->state < XMP_STATE_PLAYING) {
|
||||
return -XMP_ERROR_STATE;
|
||||
}
|
||||
|
||||
if (chn >= smix->chn || ins >= smix->ins) {
|
||||
return -XMP_ERROR_INVALID;
|
||||
}
|
||||
|
||||
if (note == 0) {
|
||||
note = 60; /* middle C note number */
|
||||
}
|
||||
|
||||
event = &p->inject_event[mod->chn + chn];
|
||||
memset(event, 0, sizeof (struct xmp_event));
|
||||
event->note = note + 1;
|
||||
event->ins = mod->ins + ins + 1;
|
||||
event->vol = vol + 1;
|
||||
event->_flag = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int xmp_smix_channel_pan(xmp_context opaque, int chn, int pan)
|
||||
{
|
||||
struct context_data *ctx = (struct context_data *)opaque;
|
||||
struct player_data *p = &ctx->p;
|
||||
struct smix_data *smix = &ctx->smix;
|
||||
struct module_data *m = &ctx->m;
|
||||
struct channel_data *xc;
|
||||
|
||||
if (chn >= smix->chn || pan < 0 || pan > 255) {
|
||||
return -XMP_ERROR_INVALID;
|
||||
}
|
||||
|
||||
xc = &p->xc_data[m->mod.chn + chn];
|
||||
xc->pan.val = pan;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int xmp_smix_load_sample(xmp_context opaque, int num, const char *path)
|
||||
{
|
||||
struct context_data *ctx = (struct context_data *)opaque;
|
||||
struct smix_data *smix = &ctx->smix;
|
||||
struct module_data *m = &ctx->m;
|
||||
struct xmp_instrument *xxi;
|
||||
struct xmp_sample *xxs;
|
||||
HIO_HANDLE *h;
|
||||
uint32 magic;
|
||||
int chn, rate, bits, size;
|
||||
int retval = -XMP_ERROR_INTERNAL;
|
||||
|
||||
if (num >= smix->ins) {
|
||||
retval = -XMP_ERROR_INVALID;
|
||||
goto err;
|
||||
}
|
||||
|
||||
xxi = &smix->xxi[num];
|
||||
xxs = &smix->xxs[num];
|
||||
|
||||
h = hio_open(path, "rb");
|
||||
if (h == NULL) {
|
||||
retval = -XMP_ERROR_SYSTEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Init instrument */
|
||||
|
||||
xxi->sub = calloc(sizeof(struct xmp_subinstrument), 1);
|
||||
if (xxi->sub == NULL) {
|
||||
retval = -XMP_ERROR_SYSTEM;
|
||||
goto err1;
|
||||
}
|
||||
|
||||
xxi->vol = m->volbase;
|
||||
xxi->nsm = 1;
|
||||
xxi->sub[0].sid = num;
|
||||
xxi->sub[0].vol = xxi->vol;
|
||||
xxi->sub[0].pan = 0x80;
|
||||
|
||||
/* Load sample */
|
||||
|
||||
magic = hio_read32b(h);
|
||||
if (magic != 0x52494646) { /* RIFF */
|
||||
retval = -XMP_ERROR_FORMAT;
|
||||
goto err2;
|
||||
}
|
||||
|
||||
if (hio_seek(h, 22, SEEK_SET) < 0) {
|
||||
retval = -XMP_ERROR_SYSTEM;
|
||||
goto err2;
|
||||
}
|
||||
chn = hio_read16l(h);
|
||||
if (chn != 1) {
|
||||
retval = -XMP_ERROR_FORMAT;
|
||||
goto err2;
|
||||
}
|
||||
|
||||
rate = hio_read32l(h);
|
||||
if (rate == 0) {
|
||||
retval = -XMP_ERROR_FORMAT;
|
||||
goto err2;
|
||||
}
|
||||
|
||||
if (hio_seek(h, 34, SEEK_SET) < 0) {
|
||||
retval = -XMP_ERROR_SYSTEM;
|
||||
goto err2;
|
||||
}
|
||||
bits = hio_read16l(h);
|
||||
if (bits == 0) {
|
||||
retval = -XMP_ERROR_FORMAT;
|
||||
goto err2;
|
||||
}
|
||||
|
||||
if (hio_seek(h, 40, SEEK_SET) < 0) {
|
||||
retval = -XMP_ERROR_SYSTEM;
|
||||
goto err2;
|
||||
}
|
||||
size = hio_read32l(h);
|
||||
if (size == 0) {
|
||||
retval = -XMP_ERROR_FORMAT;
|
||||
goto err2;
|
||||
}
|
||||
|
||||
libxmp_c2spd_to_note(rate, &xxi->sub[0].xpo, &xxi->sub[0].fin);
|
||||
|
||||
xxs->len = 8 * size / bits;
|
||||
xxs->lps = 0;
|
||||
xxs->lpe = 0;
|
||||
xxs->flg = bits == 16 ? XMP_SAMPLE_16BIT : 0;
|
||||
|
||||
xxs->data = malloc(size + 8);
|
||||
if (xxs->data == NULL) {
|
||||
retval = -XMP_ERROR_SYSTEM;
|
||||
goto err2;
|
||||
}
|
||||
|
||||
/* ugly hack to make the interpolator happy */
|
||||
memset(xxs->data, 0, 4);
|
||||
memset(xxs->data + 4 + size, 0, 4);
|
||||
xxs->data += 4;
|
||||
|
||||
if (hio_seek(h, 44, SEEK_SET) < 0) {
|
||||
retval = -XMP_ERROR_SYSTEM;
|
||||
goto err2;
|
||||
}
|
||||
if (hio_read(xxs->data, 1, size, h) != size) {
|
||||
retval = -XMP_ERROR_SYSTEM;
|
||||
goto err2;
|
||||
}
|
||||
hio_close(h);
|
||||
|
||||
return 0;
|
||||
|
||||
err2:
|
||||
free(xxi->sub);
|
||||
xxi->sub = NULL;
|
||||
err1:
|
||||
hio_close(h);
|
||||
err:
|
||||
return retval;
|
||||
}
|
||||
|
||||
int xmp_smix_release_sample(xmp_context opaque, int num)
|
||||
{
|
||||
struct context_data *ctx = (struct context_data *)opaque;
|
||||
struct smix_data *smix = &ctx->smix;
|
||||
|
||||
if (num >= smix->ins) {
|
||||
return -XMP_ERROR_INVALID;
|
||||
}
|
||||
|
||||
libxmp_free_sample(&smix->xxs[num]);
|
||||
free(smix->xxi[num].sub);
|
||||
|
||||
smix->xxs[num].data = NULL;
|
||||
smix->xxi[num].sub = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void xmp_end_smix(xmp_context opaque)
|
||||
{
|
||||
struct context_data *ctx = (struct context_data *)opaque;
|
||||
struct smix_data *smix = &ctx->smix;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < smix->smp; i++) {
|
||||
xmp_smix_release_sample(opaque, i);
|
||||
}
|
||||
|
||||
free(smix->xxs);
|
||||
free(smix->xxi);
|
||||
smix->xxs = NULL;
|
||||
smix->xxi = NULL;
|
||||
}
|
7
internal/c/parts/audio/extras/libxmp-lite/tempfile.h
Normal file
7
internal/c/parts/audio/extras/libxmp-lite/tempfile.h
Normal file
|
@ -0,0 +1,7 @@
|
|||
#ifndef XMP_PLATFORM_H
|
||||
#define XMP_PLATFORM_H
|
||||
|
||||
FILE *make_temp_file(char **);
|
||||
void unlink_temp_file(char *);
|
||||
|
||||
#endif
|
609
internal/c/parts/audio/extras/libxmp-lite/virtual.c
Normal file
609
internal/c/parts/audio/extras/libxmp-lite/virtual.c
Normal file
|
@ -0,0 +1,609 @@
|
|||
/* Extended Module Player
|
||||
* Copyright (C) 1996-2021 Claudio Matsuoka and Hipolito Carraro Jr
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <limits.h>
|
||||
#include "common.h"
|
||||
#include "virtual.h"
|
||||
#include "mixer.h"
|
||||
|
||||
#ifdef LIBXMP_PAULA_SIMULATOR
|
||||
#include "paula.h"
|
||||
#endif
|
||||
|
||||
#define FREE -1
|
||||
|
||||
/* For virt_pastnote() */
|
||||
void libxmp_player_set_release(struct context_data *, int);
|
||||
void libxmp_player_set_fadeout(struct context_data *, int);
|
||||
|
||||
|
||||
/* Get parent channel */
|
||||
int libxmp_virt_getroot(struct context_data *ctx, int chn)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
struct mixer_voice *vi;
|
||||
int voc;
|
||||
|
||||
voc = p->virt.virt_channel[chn].map;
|
||||
if (voc < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
vi = &p->virt.voice_array[voc];
|
||||
|
||||
return vi->root;
|
||||
}
|
||||
|
||||
void libxmp_virt_resetvoice(struct context_data *ctx, int voc, int mute)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
struct mixer_voice *vi = &p->virt.voice_array[voc];
|
||||
#ifdef LIBXMP_PAULA_SIMULATOR
|
||||
struct paula_state *paula;
|
||||
#endif
|
||||
|
||||
if ((uint32)voc >= p->virt.maxvoc) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mute) {
|
||||
libxmp_mixer_setvol(ctx, voc, 0);
|
||||
}
|
||||
|
||||
p->virt.virt_used--;
|
||||
p->virt.virt_channel[vi->root].count--;
|
||||
p->virt.virt_channel[vi->chn].map = FREE;
|
||||
#ifdef LIBXMP_PAULA_SIMULATOR
|
||||
paula = vi->paula;
|
||||
#endif
|
||||
memset(vi, 0, sizeof(struct mixer_voice));
|
||||
#ifdef LIBXMP_PAULA_SIMULATOR
|
||||
vi->paula = paula;
|
||||
#endif
|
||||
vi->chn = vi->root = FREE;
|
||||
}
|
||||
|
||||
/* virt_on (number of tracks) */
|
||||
int libxmp_virt_on(struct context_data *ctx, int num)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
struct module_data *m = &ctx->m;
|
||||
int i;
|
||||
|
||||
p->virt.num_tracks = num;
|
||||
num = libxmp_mixer_numvoices(ctx, -1);
|
||||
|
||||
p->virt.virt_channels = p->virt.num_tracks;
|
||||
|
||||
if (HAS_QUIRK(QUIRK_VIRTUAL)) {
|
||||
p->virt.virt_channels += num;
|
||||
} else if (num > p->virt.virt_channels) {
|
||||
num = p->virt.virt_channels;
|
||||
}
|
||||
|
||||
p->virt.maxvoc = libxmp_mixer_numvoices(ctx, num);
|
||||
|
||||
p->virt.voice_array = calloc(p->virt.maxvoc,
|
||||
sizeof(struct mixer_voice));
|
||||
if (p->virt.voice_array == NULL)
|
||||
goto err;
|
||||
|
||||
for (i = 0; i < p->virt.maxvoc; i++) {
|
||||
p->virt.voice_array[i].chn = FREE;
|
||||
p->virt.voice_array[i].root = FREE;
|
||||
}
|
||||
|
||||
#ifdef LIBXMP_PAULA_SIMULATOR
|
||||
/* Initialize Paula simulator */
|
||||
if (IS_AMIGA_MOD()) {
|
||||
for (i = 0; i < p->virt.maxvoc; i++) {
|
||||
p->virt.voice_array[i].paula = calloc(1, sizeof (struct paula_state));
|
||||
if (p->virt.voice_array[i].paula == NULL) {
|
||||
goto err2;
|
||||
}
|
||||
libxmp_paula_init(ctx, p->virt.voice_array[i].paula);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
p->virt.virt_channel = malloc(p->virt.virt_channels *
|
||||
sizeof(struct virt_channel));
|
||||
if (p->virt.virt_channel == NULL)
|
||||
goto err2;
|
||||
|
||||
for (i = 0; i < p->virt.virt_channels; i++) {
|
||||
p->virt.virt_channel[i].map = FREE;
|
||||
p->virt.virt_channel[i].count = 0;
|
||||
}
|
||||
|
||||
p->virt.virt_used = 0;
|
||||
|
||||
return 0;
|
||||
|
||||
err2:
|
||||
#ifdef LIBXMP_PAULA_SIMULATOR
|
||||
if (IS_AMIGA_MOD()) {
|
||||
for (i = 0; i < p->virt.maxvoc; i++) {
|
||||
free(p->virt.voice_array[i].paula);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
free(p->virt.voice_array);
|
||||
p->virt.voice_array = NULL;
|
||||
err:
|
||||
return -1;
|
||||
}
|
||||
|
||||
void libxmp_virt_off(struct context_data *ctx)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
#ifdef LIBXMP_PAULA_SIMULATOR
|
||||
struct module_data *m = &ctx->m;
|
||||
int i;
|
||||
#endif
|
||||
|
||||
#ifdef LIBXMP_PAULA_SIMULATOR
|
||||
/* Free Paula simulator state */
|
||||
if (IS_AMIGA_MOD()) {
|
||||
for (i = 0; i < p->virt.maxvoc; i++) {
|
||||
free(p->virt.voice_array[i].paula);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
p->virt.virt_used = p->virt.maxvoc = 0;
|
||||
p->virt.virt_channels = 0;
|
||||
p->virt.num_tracks = 0;
|
||||
|
||||
free(p->virt.voice_array);
|
||||
free(p->virt.virt_channel);
|
||||
p->virt.voice_array = NULL;
|
||||
p->virt.virt_channel = NULL;
|
||||
}
|
||||
|
||||
void libxmp_virt_reset(struct context_data *ctx)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
int i;
|
||||
|
||||
if (p->virt.virt_channels < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* CID 129203 (#1 of 1): Useless call (USELESS_CALL)
|
||||
* Call is only useful for its return value, which is ignored.
|
||||
*
|
||||
* libxmp_mixer_numvoices(ctx, p->virt.maxvoc);
|
||||
*/
|
||||
|
||||
for (i = 0; i < p->virt.maxvoc; i++) {
|
||||
struct mixer_voice *vi = &p->virt.voice_array[i];
|
||||
#ifdef LIBXMP_PAULA_SIMULATOR
|
||||
struct paula_state *paula = vi->paula;
|
||||
#endif
|
||||
memset(vi, 0, sizeof(struct mixer_voice));
|
||||
#ifdef LIBXMP_PAULA_SIMULATOR
|
||||
vi->paula = paula;
|
||||
#endif
|
||||
vi->chn = FREE;
|
||||
vi->root = FREE;
|
||||
}
|
||||
|
||||
for (i = 0; i < p->virt.virt_channels; i++) {
|
||||
p->virt.virt_channel[i].map = FREE;
|
||||
p->virt.virt_channel[i].count = 0;
|
||||
}
|
||||
|
||||
p->virt.virt_used = 0;
|
||||
}
|
||||
|
||||
static int free_voice(struct context_data *ctx)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
int i, num, vol;
|
||||
|
||||
/* Find background voice with lowest volume*/
|
||||
num = FREE;
|
||||
vol = INT_MAX;
|
||||
for (i = 0; i < p->virt.maxvoc; i++) {
|
||||
struct mixer_voice *vi = &p->virt.voice_array[i];
|
||||
|
||||
if (vi->chn >= p->virt.num_tracks && vi->vol < vol) {
|
||||
num = i;
|
||||
vol = vi->vol;
|
||||
}
|
||||
}
|
||||
|
||||
/* Free voice */
|
||||
if (num >= 0) {
|
||||
p->virt.virt_channel[p->virt.voice_array[num].chn].map = FREE;
|
||||
p->virt.virt_channel[p->virt.voice_array[num].root].count--;
|
||||
p->virt.virt_used--;
|
||||
}
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
static int alloc_voice(struct context_data *ctx, int chn)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
int i;
|
||||
|
||||
/* Find free voice */
|
||||
for (i = 0; i < p->virt.maxvoc; i++) {
|
||||
if (p->virt.voice_array[i].chn == FREE)
|
||||
break;
|
||||
}
|
||||
|
||||
/* not found */
|
||||
if (i == p->virt.maxvoc) {
|
||||
i = free_voice(ctx);
|
||||
}
|
||||
|
||||
if (i >= 0) {
|
||||
p->virt.virt_channel[chn].count++;
|
||||
p->virt.virt_used++;
|
||||
|
||||
p->virt.voice_array[i].chn = chn;
|
||||
p->virt.voice_array[i].root = chn;
|
||||
p->virt.virt_channel[chn].map = i;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static int map_virt_channel(struct player_data *p, int chn)
|
||||
{
|
||||
int voc;
|
||||
|
||||
if ((uint32)chn >= p->virt.virt_channels)
|
||||
return -1;
|
||||
|
||||
voc = p->virt.virt_channel[chn].map;
|
||||
|
||||
if ((uint32)voc >= p->virt.maxvoc)
|
||||
return -1;
|
||||
|
||||
return voc;
|
||||
}
|
||||
|
||||
int libxmp_virt_mapchannel(struct context_data *ctx, int chn)
|
||||
{
|
||||
return map_virt_channel(&ctx->p, chn);
|
||||
}
|
||||
|
||||
void libxmp_virt_resetchannel(struct context_data *ctx, int chn)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
struct mixer_voice *vi;
|
||||
#ifdef LIBXMP_PAULA_SIMULATOR
|
||||
struct paula_state *paula;
|
||||
#endif
|
||||
int voc;
|
||||
|
||||
if ((voc = map_virt_channel(p, chn)) < 0)
|
||||
return;
|
||||
|
||||
libxmp_mixer_setvol(ctx, voc, 0);
|
||||
|
||||
p->virt.virt_used--;
|
||||
p->virt.virt_channel[p->virt.voice_array[voc].root].count--;
|
||||
p->virt.virt_channel[chn].map = FREE;
|
||||
|
||||
vi = &p->virt.voice_array[voc];
|
||||
#ifdef LIBXMP_PAULA_SIMULATOR
|
||||
paula = vi->paula;
|
||||
#endif
|
||||
memset(vi, 0, sizeof(struct mixer_voice));
|
||||
#ifdef LIBXMP_PAULA_SIMULATOR
|
||||
vi->paula = paula;
|
||||
#endif
|
||||
vi->chn = vi->root = FREE;
|
||||
}
|
||||
|
||||
void libxmp_virt_setvol(struct context_data *ctx, int chn, int vol)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
int voc, root;
|
||||
|
||||
if ((voc = map_virt_channel(p, chn)) < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
root = p->virt.voice_array[voc].root;
|
||||
if (root < XMP_MAX_CHANNELS && p->channel_mute[root]) {
|
||||
vol = 0;
|
||||
}
|
||||
|
||||
libxmp_mixer_setvol(ctx, voc, vol);
|
||||
|
||||
if (vol == 0 && chn >= p->virt.num_tracks) {
|
||||
libxmp_virt_resetvoice(ctx, voc, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void libxmp_virt_release(struct context_data *ctx, int chn, int rel)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
int voc;
|
||||
|
||||
if ((voc = map_virt_channel(p, chn)) < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
libxmp_mixer_release(ctx, voc, rel);
|
||||
}
|
||||
|
||||
void libxmp_virt_setpan(struct context_data *ctx, int chn, int pan)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
int voc;
|
||||
|
||||
if ((voc = map_virt_channel(p, chn)) < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
libxmp_mixer_setpan(ctx, voc, pan);
|
||||
}
|
||||
|
||||
void libxmp_virt_seteffect(struct context_data *ctx, int chn, int type, int val)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
int voc;
|
||||
|
||||
if ((voc = map_virt_channel(p, chn)) < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
libxmp_mixer_seteffect(ctx, voc, type, val);
|
||||
}
|
||||
|
||||
double libxmp_virt_getvoicepos(struct context_data *ctx, int chn)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
int voc;
|
||||
|
||||
if ((voc = map_virt_channel(p, chn)) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return libxmp_mixer_getvoicepos(ctx, voc);
|
||||
}
|
||||
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
|
||||
void libxmp_virt_setsmp(struct context_data *ctx, int chn, int smp)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
struct mixer_voice *vi;
|
||||
double pos;
|
||||
int voc;
|
||||
|
||||
if ((voc = map_virt_channel(p, chn)) < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
vi = &p->virt.voice_array[voc];
|
||||
if (vi->smp == smp) {
|
||||
return;
|
||||
}
|
||||
|
||||
pos = libxmp_mixer_getvoicepos(ctx, voc);
|
||||
libxmp_mixer_setpatch(ctx, voc, smp, 0);
|
||||
libxmp_mixer_voicepos(ctx, voc, pos, 0); /* Restore old position */
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef LIBXMP_CORE_DISABLE_IT
|
||||
|
||||
void libxmp_virt_setnna(struct context_data *ctx, int chn, int nna)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
int voc;
|
||||
|
||||
if ((voc = map_virt_channel(p, chn)) < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
p->virt.voice_array[voc].act = nna;
|
||||
}
|
||||
|
||||
static void check_dct(struct context_data *ctx, int i, int chn, int ins,
|
||||
int smp, int note, int nna, int dct, int dca)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
struct mixer_voice *vi = &p->virt.voice_array[i];
|
||||
int voc;
|
||||
|
||||
voc = p->virt.virt_channel[chn].map;
|
||||
|
||||
if (vi->root == chn && vi->ins == ins) {
|
||||
|
||||
if (nna == XMP_INST_NNA_CUT) {
|
||||
libxmp_virt_resetvoice(ctx, i, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
vi->act = nna;
|
||||
|
||||
if ((dct == XMP_INST_DCT_INST) ||
|
||||
(dct == XMP_INST_DCT_SMP && vi->smp == smp) ||
|
||||
(dct == XMP_INST_DCT_NOTE && vi->note == note)) {
|
||||
|
||||
if (nna == XMP_INST_NNA_OFF && dca == XMP_INST_DCA_FADE) {
|
||||
vi->act = VIRT_ACTION_OFF;
|
||||
} else if (dca) {
|
||||
if (i != voc || vi->act) {
|
||||
vi->act = dca;
|
||||
}
|
||||
} else {
|
||||
libxmp_virt_resetvoice(ctx, i, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* For note slides */
|
||||
void libxmp_virt_setnote(struct context_data *ctx, int chn, int note)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
int voc;
|
||||
|
||||
if ((voc = map_virt_channel(p, chn)) < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
libxmp_mixer_setnote(ctx, voc, note);
|
||||
}
|
||||
|
||||
int libxmp_virt_setpatch(struct context_data *ctx, int chn, int ins, int smp,
|
||||
int note, int nna, int dct, int dca)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
int voc, vfree;
|
||||
|
||||
if ((uint32)chn >= p->virt.virt_channels) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ins < 0) {
|
||||
smp = -1;
|
||||
}
|
||||
|
||||
#ifndef LIBXMP_CORE_DISABLE_IT
|
||||
if (dct) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < p->virt.maxvoc; i++) {
|
||||
check_dct(ctx, i, chn, ins, smp, note, nna, dct, dca);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
voc = p->virt.virt_channel[chn].map;
|
||||
|
||||
if (voc > FREE) {
|
||||
if (p->virt.voice_array[voc].act) {
|
||||
vfree = alloc_voice(ctx, chn);
|
||||
|
||||
if (vfree < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (chn = p->virt.num_tracks;
|
||||
p->virt.virt_channel[chn++].map > FREE;) ;
|
||||
|
||||
p->virt.voice_array[voc].chn = --chn;
|
||||
p->virt.virt_channel[chn].map = voc;
|
||||
voc = vfree;
|
||||
}
|
||||
} else {
|
||||
voc = alloc_voice(ctx, chn);
|
||||
if (voc < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (smp < 0) {
|
||||
libxmp_virt_resetvoice(ctx, voc, 1);
|
||||
return chn; /* was -1 */
|
||||
}
|
||||
|
||||
libxmp_mixer_setpatch(ctx, voc, smp, 1);
|
||||
libxmp_mixer_setnote(ctx, voc, note);
|
||||
p->virt.voice_array[voc].ins = ins;
|
||||
p->virt.voice_array[voc].act = nna;
|
||||
|
||||
return chn;
|
||||
}
|
||||
|
||||
void libxmp_virt_setperiod(struct context_data *ctx, int chn, double period)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
int voc;
|
||||
|
||||
if ((voc = map_virt_channel(p, chn)) < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
libxmp_mixer_setperiod(ctx, voc, period);
|
||||
}
|
||||
|
||||
void libxmp_virt_voicepos(struct context_data *ctx, int chn, double pos)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
int voc;
|
||||
|
||||
if ((voc = map_virt_channel(p, chn)) < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
libxmp_mixer_voicepos(ctx, voc, pos, 1);
|
||||
}
|
||||
|
||||
#ifndef LIBXMP_CORE_DISABLE_IT
|
||||
|
||||
void libxmp_virt_pastnote(struct context_data *ctx, int chn, int act)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
int c, voc;
|
||||
|
||||
for (c = p->virt.num_tracks; c < p->virt.virt_channels; c++) {
|
||||
if ((voc = map_virt_channel(p, c)) < 0)
|
||||
continue;
|
||||
|
||||
if (p->virt.voice_array[voc].root == chn) {
|
||||
switch (act) {
|
||||
case VIRT_ACTION_CUT:
|
||||
libxmp_virt_resetvoice(ctx, voc, 1);
|
||||
break;
|
||||
case VIRT_ACTION_OFF:
|
||||
libxmp_player_set_release(ctx, c);
|
||||
break;
|
||||
case VIRT_ACTION_FADE:
|
||||
libxmp_player_set_fadeout(ctx, c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int libxmp_virt_cstat(struct context_data *ctx, int chn)
|
||||
{
|
||||
struct player_data *p = &ctx->p;
|
||||
int voc;
|
||||
|
||||
if ((voc = map_virt_channel(p, chn)) < 0) {
|
||||
return VIRT_INVALID;
|
||||
}
|
||||
|
||||
if (chn < p->virt.num_tracks) {
|
||||
return VIRT_ACTIVE;
|
||||
}
|
||||
|
||||
return p->virt.voice_array[voc].act;
|
||||
}
|
38
internal/c/parts/audio/extras/libxmp-lite/virtual.h
Normal file
38
internal/c/parts/audio/extras/libxmp-lite/virtual.h
Normal file
|
@ -0,0 +1,38 @@
|
|||
#ifndef LIBXMP_VIRTUAL_H
|
||||
#define LIBXMP_VIRTUAL_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#define VIRT_ACTION_CUT XMP_INST_NNA_CUT
|
||||
#define VIRT_ACTION_CONT XMP_INST_NNA_CONT
|
||||
#define VIRT_ACTION_OFF XMP_INST_NNA_OFF
|
||||
#define VIRT_ACTION_FADE XMP_INST_NNA_FADE
|
||||
|
||||
#define VIRT_ACTIVE 0x100
|
||||
#define VIRT_INVALID -1
|
||||
|
||||
int libxmp_virt_on (struct context_data *, int);
|
||||
void libxmp_virt_off (struct context_data *);
|
||||
int libxmp_virt_mute (struct context_data *, int, int);
|
||||
int libxmp_virt_setpatch (struct context_data *, int, int, int, int,
|
||||
int, int, int);
|
||||
int libxmp_virt_cvt8bit (void);
|
||||
void libxmp_virt_setnote (struct context_data *, int, int);
|
||||
void libxmp_virt_setsmp (struct context_data *, int, int);
|
||||
void libxmp_virt_setnna (struct context_data *, int, int);
|
||||
void libxmp_virt_pastnote (struct context_data *, int, int);
|
||||
void libxmp_virt_setvol (struct context_data *, int, int);
|
||||
void libxmp_virt_voicepos (struct context_data *, int, double);
|
||||
double libxmp_virt_getvoicepos (struct context_data *, int);
|
||||
void libxmp_virt_setperiod (struct context_data *, int, double);
|
||||
void libxmp_virt_setpan (struct context_data *, int, int);
|
||||
void libxmp_virt_seteffect (struct context_data *, int, int, int);
|
||||
int libxmp_virt_cstat (struct context_data *, int);
|
||||
int libxmp_virt_mapchannel (struct context_data *, int);
|
||||
void libxmp_virt_resetchannel(struct context_data *, int);
|
||||
void libxmp_virt_resetvoice (struct context_data *, int, int);
|
||||
void libxmp_virt_reset (struct context_data *);
|
||||
void libxmp_virt_release (struct context_data *, int, int);
|
||||
int libxmp_virt_getroot (struct context_data *, int);
|
||||
|
||||
#endif /* LIBXMP_VIRTUAL_H */
|
33
internal/c/parts/audio/extras/libxmp-lite/win32.c
Normal file
33
internal/c/parts/audio/extras/libxmp-lite/win32.c
Normal file
|
@ -0,0 +1,33 @@
|
|||
/* _[v]snprintf() from msvcrt.dll might not nul terminate */
|
||||
/* OpenWatcom-provided versions seem to behave the same... */
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#if defined(USE_LIBXMP_SNPRINTF)
|
||||
|
||||
#undef snprintf
|
||||
#undef vsnprintf
|
||||
|
||||
int libxmp_vsnprintf(char *str, size_t sz, const char *fmt, va_list ap)
|
||||
{
|
||||
int rc = _vsnprintf(str, sz, fmt, ap);
|
||||
if (sz != 0) {
|
||||
if (rc < 0) rc = (int)sz;
|
||||
if ((size_t)rc >= sz) str[sz - 1] = '\0';
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
int libxmp_snprintf (char *str, size_t sz, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int rc;
|
||||
|
||||
va_start (ap, fmt);
|
||||
rc = _vsnprintf(str, sz, fmt, ap);
|
||||
va_end (ap);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
#endif
|
101
internal/c/parts/audio/extras/libxmp-lite/xm.h
Normal file
101
internal/c/parts/audio/extras/libxmp-lite/xm.h
Normal file
|
@ -0,0 +1,101 @@
|
|||
#ifndef LIBXMP_LOADERS_XM_H
|
||||
#define LIBXMP_LOADERS_XM_H
|
||||
|
||||
#define XM_EVENT_PACKING 0x80
|
||||
#define XM_EVENT_PACK_MASK 0x7f
|
||||
#define XM_EVENT_NOTE_FOLLOWS 0x01
|
||||
#define XM_EVENT_INSTRUMENT_FOLLOWS 0x02
|
||||
#define XM_EVENT_VOLUME_FOLLOWS 0x04
|
||||
#define XM_EVENT_FXTYPE_FOLLOWS 0x08
|
||||
#define XM_EVENT_FXPARM_FOLLOWS 0x10
|
||||
#define XM_LINEAR_FREQ 0x01
|
||||
#define XM_LOOP_MASK 0x03
|
||||
#define XM_LOOP_NONE 0
|
||||
#define XM_LOOP_FORWARD 1
|
||||
#define XM_LOOP_PINGPONG 2
|
||||
#define XM_SAMPLE_16BIT 0x10
|
||||
#define XM_ENVELOPE_ON 0x01
|
||||
#define XM_ENVELOPE_SUSTAIN 0x02
|
||||
#define XM_ENVELOPE_LOOP 0x04
|
||||
#define XM_LINEAR_PERIOD_MODE 0x01
|
||||
|
||||
|
||||
struct xm_file_header {
|
||||
uint8 id[17]; /* ID text: "Extended module: " */
|
||||
uint8 name[20]; /* Module name, padded with zeroes */
|
||||
uint8 doseof; /* 0x1a */
|
||||
uint8 tracker[20]; /* Tracker name */
|
||||
uint16 version; /* Version number, minor-major */
|
||||
uint32 headersz; /* Header size */
|
||||
uint16 songlen; /* Song length (in patten order table) */
|
||||
uint16 restart; /* Restart position */
|
||||
uint16 channels; /* Number of channels (2,4,6,8,10,...,32) */
|
||||
uint16 patterns; /* Number of patterns (max 256) */
|
||||
uint16 instruments; /* Number of instruments (max 128) */
|
||||
uint16 flags; /* bit 0: 0=Amiga freq table, 1=Linear */
|
||||
uint16 tempo; /* Default tempo */
|
||||
uint16 bpm; /* Default BPM */
|
||||
uint8 order[256]; /* Pattern order table */
|
||||
};
|
||||
|
||||
struct xm_pattern_header {
|
||||
uint32 length; /* Pattern header length */
|
||||
uint8 packing; /* Packing type (always 0) */
|
||||
uint16 rows; /* Number of rows in pattern (1..256) */
|
||||
uint16 datasize; /* Packed patterndata size */
|
||||
};
|
||||
|
||||
struct xm_instrument_header {
|
||||
uint32 size; /* Instrument size */
|
||||
uint8 name[22]; /* Instrument name */
|
||||
uint8 type; /* Instrument type (always 0) */
|
||||
uint16 samples; /* Number of samples in instrument */
|
||||
uint32 sh_size; /* Sample header size */
|
||||
};
|
||||
|
||||
struct xm_instrument {
|
||||
uint8 sample[96]; /* Sample number for all notes */
|
||||
uint16 v_env[24]; /* Points for volume envelope */
|
||||
uint16 p_env[24]; /* Points for panning envelope */
|
||||
uint8 v_pts; /* Number of volume points */
|
||||
uint8 p_pts; /* Number of panning points */
|
||||
uint8 v_sus; /* Volume sustain point */
|
||||
uint8 v_start; /* Volume loop start point */
|
||||
uint8 v_end; /* Volume loop end point */
|
||||
uint8 p_sus; /* Panning sustain point */
|
||||
uint8 p_start; /* Panning loop start point */
|
||||
uint8 p_end; /* Panning loop end point */
|
||||
uint8 v_type; /* Bit 0: On; 1: Sustain; 2: Loop */
|
||||
uint8 p_type; /* Bit 0: On; 1: Sustain; 2: Loop */
|
||||
uint8 y_wave; /* Vibrato waveform */
|
||||
uint8 y_sweep; /* Vibrato sweep */
|
||||
uint8 y_depth; /* Vibrato depth */
|
||||
uint8 y_rate; /* Vibrato rate */
|
||||
uint16 v_fade; /* Volume fadeout */
|
||||
#if 0
|
||||
uint8 reserved[22]; /* Reserved; 2 bytes in specs, 22 in 1.04 */
|
||||
#endif
|
||||
};
|
||||
|
||||
struct xm_sample_header {
|
||||
uint32 length; /* Sample length */
|
||||
uint32 loop_start; /* Sample loop start */
|
||||
uint32 loop_length; /* Sample loop length */
|
||||
uint8 volume; /* Volume */
|
||||
int8 finetune; /* Finetune (signed byte -128..+127) */
|
||||
uint8 type; /* 0=No loop,1=Fwd loop,2=Ping-pong,16-bit */
|
||||
uint8 pan; /* Panning (0-255) */
|
||||
int8 relnote; /* Relative note number (signed byte) */
|
||||
uint8 reserved; /* Reserved */
|
||||
uint8 name[22]; /* Sample_name */
|
||||
};
|
||||
|
||||
struct xm_event {
|
||||
uint8 note; /* Note (0-71, 0 = C-0) */
|
||||
uint8 instrument; /* Instrument (0-128) */
|
||||
uint8 volume; /* Volume column byte */
|
||||
uint8 fx_type; /* Effect type */
|
||||
uint8 fx_parm; /* Effect parameter */
|
||||
};
|
||||
|
||||
#endif
|
800
internal/c/parts/audio/extras/libxmp-lite/xm_load.c
Normal file
800
internal/c/parts/audio/extras/libxmp-lite/xm_load.c
Normal file
|
@ -0,0 +1,800 @@
|
|||
/* Extended Module Player
|
||||
* Copyright (C) 1996-2021 Claudio Matsuoka and Hipolito Carraro Jr
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Fri, 26 Jun 1998 17:45:59 +1000 Andrew Leahy <alf@cit.nepean.uws.edu.au>
|
||||
* Finally got it working on the DEC Alpha running DEC UNIX! In the pattern
|
||||
* reading loop I found I was getting "0" for (p-patbuf) and "0" for
|
||||
* xph.datasize, the next if statement (where it tries to read the patbuf)
|
||||
* would then cause a seg_fault.
|
||||
*
|
||||
* Sun Sep 27 12:07:12 EST 1998 Claudio Matsuoka <claudio@pos.inf.ufpr.br>
|
||||
* Extended Module 1.02 stores data in a different order, we must handle
|
||||
* this accordingly. MAX_SAMP used as a workaround to check the number of
|
||||
* samples recognized by the player.
|
||||
*/
|
||||
|
||||
#include "loader.h"
|
||||
#include "xm.h"
|
||||
|
||||
static int xm_test(HIO_HANDLE *, char *, const int);
|
||||
static int xm_load(struct module_data *, HIO_HANDLE *, const int);
|
||||
|
||||
const struct format_loader libxmp_loader_xm = {
|
||||
"Fast Tracker II",
|
||||
xm_test,
|
||||
xm_load
|
||||
};
|
||||
|
||||
static int xm_test(HIO_HANDLE *f, char *t, const int start)
|
||||
{
|
||||
char buf[20];
|
||||
|
||||
if (hio_read(buf, 1, 17, f) < 17) /* ID text */
|
||||
return -1;
|
||||
|
||||
if (memcmp(buf, "Extended Module: ", 17))
|
||||
return -1;
|
||||
|
||||
libxmp_read_title(f, t, 20);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int load_xm_pattern(struct module_data *m, int num, int version, HIO_HANDLE *f)
|
||||
{
|
||||
const int headsize = version > 0x0102 ? 9 : 8;
|
||||
struct xmp_module *mod = &m->mod;
|
||||
struct xm_pattern_header xph;
|
||||
struct xmp_event *event;
|
||||
uint8 *patbuf, *pat, b;
|
||||
int j, r;
|
||||
int size;
|
||||
|
||||
xph.length = hio_read32l(f);
|
||||
xph.packing = hio_read8(f);
|
||||
xph.rows = version > 0x0102 ? hio_read16l(f) : hio_read8(f) + 1;
|
||||
|
||||
/* Sanity check */
|
||||
if (xph.rows > 256) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
xph.datasize = hio_read16l(f);
|
||||
hio_seek(f, xph.length - headsize, SEEK_CUR);
|
||||
if (hio_error(f)) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
r = xph.rows;
|
||||
if (r == 0) {
|
||||
r = 0x100;
|
||||
}
|
||||
|
||||
if (libxmp_alloc_pattern_tracks(mod, num, r) < 0) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (xph.datasize == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
size = xph.datasize;
|
||||
|
||||
pat = patbuf = calloc(1, size);
|
||||
if (patbuf == NULL) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
hio_read(patbuf, 1, size, f);
|
||||
for (j = 0; j < (mod->chn * r); j++) {
|
||||
|
||||
/*if ((pat - patbuf) >= xph.datasize)
|
||||
break; */
|
||||
|
||||
event = &EVENT(num, j % mod->chn, j / mod->chn);
|
||||
|
||||
if (--size < 0) {
|
||||
goto err2;
|
||||
}
|
||||
|
||||
if ((b = *pat++) & XM_EVENT_PACKING) {
|
||||
if (b & XM_EVENT_NOTE_FOLLOWS) {
|
||||
if (--size < 0)
|
||||
goto err2;
|
||||
event->note = *pat++;
|
||||
}
|
||||
if (b & XM_EVENT_INSTRUMENT_FOLLOWS) {
|
||||
if (--size < 0)
|
||||
goto err2;
|
||||
event->ins = *pat++;
|
||||
}
|
||||
if (b & XM_EVENT_VOLUME_FOLLOWS) {
|
||||
if (--size < 0)
|
||||
goto err2;
|
||||
event->vol = *pat++;
|
||||
}
|
||||
if (b & XM_EVENT_FXTYPE_FOLLOWS) {
|
||||
if (--size < 0)
|
||||
goto err2;
|
||||
event->fxt = *pat++;
|
||||
}
|
||||
if (b & XM_EVENT_FXPARM_FOLLOWS) {
|
||||
if (--size < 0)
|
||||
goto err2;
|
||||
event->fxp = *pat++;
|
||||
}
|
||||
} else {
|
||||
size -= 4;
|
||||
if (size < 0)
|
||||
goto err2;
|
||||
event->note = b;
|
||||
event->ins = *pat++;
|
||||
event->vol = *pat++;
|
||||
event->fxt = *pat++;
|
||||
event->fxp = *pat++;
|
||||
}
|
||||
|
||||
/* Sanity check */
|
||||
switch (event->fxt) {
|
||||
case 18:
|
||||
case 19:
|
||||
case 22:
|
||||
case 23:
|
||||
case 24:
|
||||
case 26:
|
||||
case 28:
|
||||
case 30:
|
||||
case 31:
|
||||
case 32:
|
||||
event->fxt = 0;
|
||||
}
|
||||
if (event->fxt > 34) {
|
||||
event->fxt = 0;
|
||||
}
|
||||
|
||||
if (event->note == 0x61) {
|
||||
/* See OpenMPT keyoff+instr.xm test case */
|
||||
if (event->fxt == 0x0e && MSN(event->fxp) == 0x0d) {
|
||||
event->note = XMP_KEY_OFF;
|
||||
} else {
|
||||
event->note =
|
||||
event->ins ? XMP_KEY_FADE : XMP_KEY_OFF;
|
||||
}
|
||||
} else if (event->note > 0) {
|
||||
event->note += 12;
|
||||
}
|
||||
|
||||
if (event->fxt == 0x0e) {
|
||||
if (MSN(event->fxp) == EX_FINETUNE) {
|
||||
unsigned char val = (LSN(event->fxp) - 8) & 0xf;
|
||||
event->fxp = (EX_FINETUNE << 4) | val;
|
||||
}
|
||||
switch (event->fxp) {
|
||||
case 0x43:
|
||||
case 0x73:
|
||||
event->fxp--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!event->vol) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Volume set */
|
||||
if ((event->vol >= 0x10) && (event->vol <= 0x50)) {
|
||||
event->vol -= 0x0f;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Volume column effects */
|
||||
switch (event->vol >> 4) {
|
||||
case 0x06: /* Volume slide down */
|
||||
event->f2t = FX_VOLSLIDE_2;
|
||||
event->f2p = event->vol - 0x60;
|
||||
break;
|
||||
case 0x07: /* Volume slide up */
|
||||
event->f2t = FX_VOLSLIDE_2;
|
||||
event->f2p = (event->vol - 0x70) << 4;
|
||||
break;
|
||||
case 0x08: /* Fine volume slide down */
|
||||
event->f2t = FX_EXTENDED;
|
||||
event->f2p =
|
||||
(EX_F_VSLIDE_DN << 4) | (event->vol - 0x80);
|
||||
break;
|
||||
case 0x09: /* Fine volume slide up */
|
||||
event->f2t = FX_EXTENDED;
|
||||
event->f2p =
|
||||
(EX_F_VSLIDE_UP << 4) | (event->vol - 0x90);
|
||||
break;
|
||||
case 0x0a: /* Set vibrato speed */
|
||||
event->f2t = FX_VIBRATO;
|
||||
event->f2p = (event->vol - 0xa0) << 4;
|
||||
break;
|
||||
case 0x0b: /* Vibrato */
|
||||
event->f2t = FX_VIBRATO;
|
||||
event->f2p = event->vol - 0xb0;
|
||||
break;
|
||||
case 0x0c: /* Set panning */
|
||||
event->f2t = FX_SETPAN;
|
||||
event->f2p = (event->vol - 0xc0) << 4;
|
||||
break;
|
||||
case 0x0d: /* Pan slide left */
|
||||
event->f2t = FX_PANSL_NOMEM;
|
||||
event->f2p = (event->vol - 0xd0) << 4;
|
||||
break;
|
||||
case 0x0e: /* Pan slide right */
|
||||
event->f2t = FX_PANSL_NOMEM;
|
||||
event->f2p = event->vol - 0xe0;
|
||||
break;
|
||||
case 0x0f: /* Tone portamento */
|
||||
event->f2t = FX_TONEPORTA;
|
||||
event->f2p = (event->vol - 0xf0) << 4;
|
||||
|
||||
/* From OpenMPT TonePortamentoMemory.xm:
|
||||
* "Another nice bug (...) is the combination of both
|
||||
* portamento commands (Mx and 3xx) in the same cell:
|
||||
* The 3xx parameter is ignored completely, and the Mx
|
||||
* parameter is doubled. (M2 3FF is the same as M4 000)
|
||||
*/
|
||||
if (event->fxt == FX_TONEPORTA
|
||||
|| event->fxt == FX_TONE_VSLIDE) {
|
||||
if (event->fxt == FX_TONEPORTA) {
|
||||
event->fxt = 0;
|
||||
} else {
|
||||
event->fxt = FX_VOLSLIDE;
|
||||
}
|
||||
event->fxp = 0;
|
||||
|
||||
if (event->f2p < 0x80) {
|
||||
event->f2p <<= 1;
|
||||
} else {
|
||||
event->f2p = 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
/* From OpenMPT porta-offset.xm:
|
||||
* "If there is a portamento command next to an offset
|
||||
* command, the offset command is ignored completely. In
|
||||
* particular, the offset parameter is not memorized."
|
||||
*/
|
||||
if (event->fxt == FX_OFFSET
|
||||
&& event->f2t == FX_TONEPORTA) {
|
||||
event->fxt = event->fxp = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
event->vol = 0;
|
||||
}
|
||||
free(patbuf);
|
||||
|
||||
return 0;
|
||||
|
||||
err2:
|
||||
free(patbuf);
|
||||
err:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int load_patterns(struct module_data *m, int version, HIO_HANDLE *f)
|
||||
{
|
||||
struct xmp_module *mod = &m->mod;
|
||||
int i, j;
|
||||
|
||||
mod->pat++;
|
||||
if (libxmp_init_pattern(mod) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
D_(D_INFO "Stored patterns: %d", mod->pat - 1);
|
||||
|
||||
for (i = 0; i < mod->pat - 1; i++) {
|
||||
if (load_xm_pattern(m, i, version, f) < 0) {
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
/* Alloc one extra pattern */
|
||||
{
|
||||
int t = i * mod->chn;
|
||||
|
||||
if (libxmp_alloc_pattern(mod, i) < 0) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
mod->xxp[i]->rows = 64;
|
||||
|
||||
if (libxmp_alloc_track(mod, t, 64) < 0) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
for (j = 0; j < mod->chn; j++) {
|
||||
mod->xxp[i]->index[j] = t;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Packed structures size */
|
||||
#define XM_INST_HEADER_SIZE 33
|
||||
#define XM_INST_SIZE 208
|
||||
|
||||
/* grass.near.the.house.xm defines 23 samples in instrument 1. FT2 docs
|
||||
* specify at most 16. See https://github.com/libxmp/libxmp/issues/168
|
||||
* for more details. */
|
||||
#define XM_MAX_SAMPLES_PER_INST 32
|
||||
|
||||
static int load_instruments(struct module_data *m, int version, HIO_HANDLE *f)
|
||||
{
|
||||
struct xmp_module *mod = &m->mod;
|
||||
struct xm_instrument_header xih;
|
||||
struct xm_instrument xi;
|
||||
struct xm_sample_header xsh[XM_MAX_SAMPLES_PER_INST];
|
||||
int sample_num = 0;
|
||||
long total_sample_size;
|
||||
int i, j;
|
||||
uint8 buf[208];
|
||||
|
||||
D_(D_INFO "Instruments: %d", mod->ins);
|
||||
|
||||
/* ESTIMATED value! We don't know the actual value at this point */
|
||||
mod->smp = MAX_SAMPLES;
|
||||
|
||||
if (libxmp_init_instrument(m) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < mod->ins; i++) {
|
||||
long instr_pos = hio_tell(f);
|
||||
struct xmp_instrument *xxi = &mod->xxi[i];
|
||||
|
||||
/* Modules converted with MOD2XM 1.0 always say we have 31
|
||||
* instruments, but file may end abruptly before that. Also covers
|
||||
* XMLiTE stripped modules and truncated files. This test will not
|
||||
* work if file has trailing garbage.
|
||||
*/
|
||||
if (hio_read(buf, 33, 1, f) != 1) {
|
||||
D_(D_WARN "short read in instrument header data");
|
||||
break;
|
||||
}
|
||||
|
||||
xih.size = readmem32l(buf); /* Instrument size */
|
||||
memcpy(xih.name, buf + 4, 22); /* Instrument name */
|
||||
xih.type = buf[26]; /* Instrument type (always 0) */
|
||||
xih.samples = readmem16l(buf + 27); /* Number of samples */
|
||||
xih.sh_size = readmem32l(buf + 29); /* Sample header size */
|
||||
|
||||
/* Sanity check */
|
||||
if (xih.samples > XM_MAX_SAMPLES_PER_INST || (xih.samples > 0 && xih.sh_size > 0x100)) {
|
||||
D_(D_CRIT "instrument %d: samples:%d sample header size:%d", i + 1, xih.samples, xih.sh_size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
libxmp_instrument_name(mod, i, xih.name, 22);
|
||||
|
||||
xxi->nsm = xih.samples;
|
||||
|
||||
D_(D_INFO "instrument:%2X (%s) samples:%2d", i, xxi->name, xxi->nsm);
|
||||
|
||||
if (xxi->nsm == 0) {
|
||||
/* Sample size should be in struct xm_instrument according to
|
||||
* the official format description, but FT2 actually puts it in
|
||||
* struct xm_instrument header. There's a tracker or converter
|
||||
* that follow the specs, so we must handle both cases (see
|
||||
* "Braintomb" by Jazztiz/ART).
|
||||
*/
|
||||
|
||||
/* Umm, Cyke O'Path <cyker@heatwave.co.uk> sent me a couple of
|
||||
* mods ("Breath of the Wind" and "Broken Dimension") that
|
||||
* reserve the instrument data space after the instrument header
|
||||
* even if the number of instruments is set to 0. In these modules
|
||||
* the instrument header size is marked as 263. The following
|
||||
* generalization should take care of both cases.
|
||||
*/
|
||||
|
||||
if (hio_seek(f, (int)xih.size - XM_INST_HEADER_SIZE, SEEK_CUR) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (libxmp_alloc_subinstrument(mod, i, xxi->nsm) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (xih.size < XM_INST_HEADER_SIZE) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* for BoobieSqueezer (see http://boobie.rotfl.at/)
|
||||
* It works pretty much the same way as Impulse Tracker's sample
|
||||
* only mode, where it will strip off the instrument data.
|
||||
*/
|
||||
if (xih.size < XM_INST_HEADER_SIZE + XM_INST_SIZE) {
|
||||
memset(&xi, 0, sizeof(struct xm_instrument));
|
||||
hio_seek(f, xih.size - XM_INST_HEADER_SIZE, SEEK_CUR);
|
||||
} else {
|
||||
uint8 *b = buf;
|
||||
|
||||
if (hio_read(buf, 208, 1, f) != 1) {
|
||||
D_(D_CRIT "short read in instrument data");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(xi.sample, b, 96); /* Sample map */
|
||||
b += 96;
|
||||
|
||||
for (j = 0; j < 24; j++) {
|
||||
xi.v_env[j] = readmem16l(b); /* Points for volume envelope */
|
||||
b += 2;
|
||||
}
|
||||
|
||||
for (j = 0; j < 24; j++) {
|
||||
xi.p_env[j] = readmem16l(b); /* Points for pan envelope */
|
||||
b += 2;
|
||||
}
|
||||
|
||||
xi.v_pts = *b++; /* Number of volume points */
|
||||
xi.p_pts = *b++; /* Number of pan points */
|
||||
xi.v_sus = *b++; /* Volume sustain point */
|
||||
xi.v_start = *b++; /* Volume loop start point */
|
||||
xi.v_end = *b++; /* Volume loop end point */
|
||||
xi.p_sus = *b++; /* Pan sustain point */
|
||||
xi.p_start = *b++; /* Pan loop start point */
|
||||
xi.p_end = *b++; /* Pan loop end point */
|
||||
xi.v_type = *b++; /* Bit 0:On 1:Sustain 2:Loop */
|
||||
xi.p_type = *b++; /* Bit 0:On 1:Sustain 2:Loop */
|
||||
xi.y_wave = *b++; /* Vibrato waveform */
|
||||
xi.y_sweep = *b++; /* Vibrato sweep */
|
||||
xi.y_depth = *b++; /* Vibrato depth */
|
||||
xi.y_rate = *b++; /* Vibrato rate */
|
||||
xi.v_fade = readmem16l(b); /* Volume fadeout */
|
||||
|
||||
/* Skip reserved space */
|
||||
if (hio_seek(f, (int)xih.size - (XM_INST_HEADER_SIZE + XM_INST_SIZE), SEEK_CUR) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Envelope */
|
||||
xxi->rls = xi.v_fade << 1;
|
||||
xxi->aei.npt = xi.v_pts;
|
||||
xxi->aei.sus = xi.v_sus;
|
||||
xxi->aei.lps = xi.v_start;
|
||||
xxi->aei.lpe = xi.v_end;
|
||||
xxi->aei.flg = xi.v_type;
|
||||
xxi->pei.npt = xi.p_pts;
|
||||
xxi->pei.sus = xi.p_sus;
|
||||
xxi->pei.lps = xi.p_start;
|
||||
xxi->pei.lpe = xi.p_end;
|
||||
xxi->pei.flg = xi.p_type;
|
||||
|
||||
if (xxi->aei.npt <= 0 || xxi->aei.npt > 12 /*XMP_MAX_ENV_POINTS */ ) {
|
||||
xxi->aei.flg &= ~XMP_ENVELOPE_ON;
|
||||
} else {
|
||||
memcpy(xxi->aei.data, xi.v_env, xxi->aei.npt * 4);
|
||||
}
|
||||
|
||||
if (xxi->pei.npt <= 0 || xxi->pei.npt > 12 /*XMP_MAX_ENV_POINTS */ ) {
|
||||
xxi->pei.flg &= ~XMP_ENVELOPE_ON;
|
||||
} else {
|
||||
memcpy(xxi->pei.data, xi.p_env, xxi->pei.npt * 4);
|
||||
}
|
||||
|
||||
for (j = 12; j < 108; j++) {
|
||||
xxi->map[j].ins = xi.sample[j - 12];
|
||||
if (xxi->map[j].ins >= xxi->nsm)
|
||||
xxi->map[j].ins = -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Read subinstrument and sample parameters */
|
||||
|
||||
for (j = 0; j < xxi->nsm; j++, sample_num++) {
|
||||
struct xmp_subinstrument *sub = &xxi->sub[j];
|
||||
struct xmp_sample *xxs;
|
||||
uint8 *b = buf;
|
||||
|
||||
D_(D_INFO " sample index:%d sample id:%d", j, sample_num);
|
||||
|
||||
if (sample_num >= mod->smp) {
|
||||
if (libxmp_realloc_samples(m, mod->smp * 3 / 2) < 0)
|
||||
return -1;
|
||||
}
|
||||
xxs = &mod->xxs[sample_num];
|
||||
|
||||
if (hio_read(buf, 40, 1, f) != 1) {
|
||||
D_(D_CRIT "short read in sample data");
|
||||
return -1;
|
||||
}
|
||||
|
||||
xsh[j].length = readmem32l(b); /* Sample length */
|
||||
b += 4;
|
||||
|
||||
/* Sanity check */
|
||||
if (xsh[j].length > MAX_SAMPLE_SIZE) {
|
||||
D_(D_CRIT "sanity check: %d: bad sample size", j);
|
||||
return -1;
|
||||
}
|
||||
|
||||
xsh[j].loop_start = readmem32l(b); /* Sample loop start */
|
||||
b += 4;
|
||||
xsh[j].loop_length = readmem32l(b); /* Sample loop length */
|
||||
b += 4;
|
||||
xsh[j].volume = *b++; /* Volume */
|
||||
xsh[j].finetune = *b++; /* Finetune (-128..+127) */
|
||||
xsh[j].type = *b++; /* Flags */
|
||||
xsh[j].pan = *b++; /* Panning (0-255) */
|
||||
xsh[j].relnote = *(int8 *) b++; /* Relative note number */
|
||||
xsh[j].reserved = *b++;
|
||||
memcpy(xsh[j].name, b, 22);
|
||||
|
||||
sub->vol = xsh[j].volume;
|
||||
sub->pan = xsh[j].pan;
|
||||
sub->xpo = xsh[j].relnote;
|
||||
sub->fin = xsh[j].finetune;
|
||||
sub->vwf = xi.y_wave;
|
||||
sub->vde = xi.y_depth << 2;
|
||||
sub->vra = xi.y_rate;
|
||||
sub->vsw = xi.y_sweep;
|
||||
sub->sid = sample_num;
|
||||
|
||||
libxmp_copy_adjust(xxs->name, xsh[j].name, 22);
|
||||
|
||||
xxs->len = xsh[j].length;
|
||||
xxs->lps = xsh[j].loop_start;
|
||||
xxs->lpe = xsh[j].loop_start + xsh[j].loop_length;
|
||||
|
||||
xxs->flg = 0;
|
||||
if (xsh[j].type & XM_SAMPLE_16BIT) {
|
||||
xxs->flg |= XMP_SAMPLE_16BIT;
|
||||
xxs->len >>= 1;
|
||||
xxs->lps >>= 1;
|
||||
xxs->lpe >>= 1;
|
||||
}
|
||||
|
||||
xxs->flg |= xsh[j].type & XM_LOOP_FORWARD ? XMP_SAMPLE_LOOP : 0;
|
||||
xxs->flg |= xsh[j].type & XM_LOOP_PINGPONG ? XMP_SAMPLE_LOOP | XMP_SAMPLE_LOOP_BIDIR : 0;
|
||||
|
||||
D_(D_INFO " size:%06x loop start:%06x loop end:%06x %c V%02x F%+04d P%02x R%+03d %s",
|
||||
mod->xxs[sub->sid].len,
|
||||
mod->xxs[sub->sid].lps,
|
||||
mod->xxs[sub->sid].lpe,
|
||||
mod->xxs[sub->sid].flg & XMP_SAMPLE_LOOP_BIDIR ? 'B' :
|
||||
mod->xxs[sub->sid].flg & XMP_SAMPLE_LOOP ? 'L' : ' ',
|
||||
sub->vol, sub->fin, sub->pan, sub->xpo,
|
||||
mod->xxs[sub->sid].flg & XMP_SAMPLE_16BIT ? " (16 bit)" : "");
|
||||
}
|
||||
|
||||
/* Read actual sample data */
|
||||
|
||||
total_sample_size = 0;
|
||||
for (j = 0; j < xxi->nsm; j++) {
|
||||
struct xmp_subinstrument *sub = &xxi->sub[j];
|
||||
int flags;
|
||||
|
||||
flags = SAMPLE_FLAG_DIFF;
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
if (xsh[j].reserved == 0xad) {
|
||||
flags = SAMPLE_FLAG_ADPCM;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (version > 0x0103) {
|
||||
D_(D_INFO " read sample: index:%d sample id:%d", j, sub->sid);
|
||||
if (libxmp_load_sample(m, f, flags, &mod->xxs[sub->sid], NULL) < 0) {
|
||||
return -1;
|
||||
}
|
||||
if (flags & SAMPLE_FLAG_ADPCM) {
|
||||
D_(D_INFO " sample is adpcm");
|
||||
total_sample_size += 16 + ((xsh[j].length + 1) >> 1);
|
||||
} else {
|
||||
total_sample_size += xsh[j].length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Reposition correctly in case of 16-bit sample having odd in-file length.
|
||||
* See "Lead Lined for '99", reported by Dennis Mulleneers.
|
||||
*/
|
||||
if (hio_seek(f, instr_pos + xih.size + 40 * xih.samples + total_sample_size, SEEK_SET) < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Final sample number adjustment */
|
||||
if (libxmp_realloc_samples(m, sample_num) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xm_load(struct module_data *m, HIO_HANDLE * f, const int start)
|
||||
{
|
||||
struct xmp_module *mod = &m->mod;
|
||||
int i, j;
|
||||
struct xm_file_header xfh;
|
||||
char tracker_name[21];
|
||||
int len;
|
||||
uint8 buf[80];
|
||||
|
||||
LOAD_INIT();
|
||||
|
||||
if (hio_read(buf, 80, 1, f) != 1) {
|
||||
D_(D_CRIT "error reading header");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(xfh.id, buf, 17); /* ID text */
|
||||
memcpy(xfh.name, buf + 17, 20); /* Module name */
|
||||
/* */ /* skip 0x1a */
|
||||
memcpy(xfh.tracker, buf + 38, 20); /* Tracker name */
|
||||
xfh.version = readmem16l(buf + 58); /* Version number, minor-major */
|
||||
xfh.headersz = readmem32l(buf + 60); /* Header size */
|
||||
xfh.songlen = readmem16l(buf + 64); /* Song length */
|
||||
xfh.restart = readmem16l(buf + 66); /* Restart position */
|
||||
xfh.channels = readmem16l(buf + 68); /* Number of channels */
|
||||
xfh.patterns = readmem16l(buf + 70); /* Number of patterns */
|
||||
xfh.instruments = readmem16l(buf + 72); /* Number of instruments */
|
||||
xfh.flags = readmem16l(buf + 74); /* 0=Amiga freq table, 1=Linear */
|
||||
xfh.tempo = readmem16l(buf + 76); /* Default tempo */
|
||||
xfh.bpm = readmem16l(buf + 78); /* Default BPM */
|
||||
|
||||
/* Sanity checks */
|
||||
if (xfh.songlen > 256 || xfh.patterns > 256 || xfh.instruments > 255) {
|
||||
D_(D_CRIT "Sanity check: %d %d %d", xfh.songlen, xfh.patterns, xfh.instruments);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (xfh.restart > 255 || xfh.channels > XMP_MAX_CHANNELS) {
|
||||
D_(D_CRIT "Sanity check: %d %d", xfh.restart, xfh.channels);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (xfh.tempo >= 32 || xfh.bpm < 32 || xfh.bpm > 255) {
|
||||
if (memcmp("MED2XM", xfh.tracker, 6)) {
|
||||
D_(D_CRIT "Sanity check: %d %d", xfh.tempo, xfh.bpm);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Honor header size -- needed by BoobieSqueezer XMs */
|
||||
len = xfh.headersz - 0x14;
|
||||
if (len < 0 || len > 256) {
|
||||
D_(D_CRIT "Sanity check: %d", len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (hio_read(xfh.order, len, 1, f) != 1) { /* Pattern order table */
|
||||
D_(D_CRIT "error reading orders");
|
||||
return -1;
|
||||
}
|
||||
|
||||
strncpy(mod->name, (char *)xfh.name, 20);
|
||||
|
||||
mod->len = xfh.songlen;
|
||||
mod->chn = xfh.channels;
|
||||
mod->pat = xfh.patterns;
|
||||
mod->ins = xfh.instruments;
|
||||
mod->rst = xfh.restart;
|
||||
mod->spd = xfh.tempo;
|
||||
mod->bpm = xfh.bpm;
|
||||
mod->trk = mod->chn * mod->pat + 1;
|
||||
|
||||
m->c4rate = C4_NTSC_RATE;
|
||||
m->period_type = xfh.flags & XM_LINEAR_PERIOD_MODE ? PERIOD_LINEAR : PERIOD_AMIGA;
|
||||
|
||||
memcpy(mod->xxo, xfh.order, mod->len);
|
||||
/*tracker_name[20] = 0;*/
|
||||
snprintf(tracker_name, 21, "%-20.20s", xfh.tracker);
|
||||
for (i = 20; i >= 0; i--) {
|
||||
if (tracker_name[i] == 0x20)
|
||||
tracker_name[i] = 0;
|
||||
if (tracker_name[i])
|
||||
break;
|
||||
}
|
||||
|
||||
/* OpenMPT accurately emulates weird FT2 bugs */
|
||||
if (!strncmp(tracker_name, "FastTracker v2.00", 17) ||
|
||||
!strncmp(tracker_name, "OpenMPT ", 8)) {
|
||||
m->quirk |= QUIRK_FT2BUGS;
|
||||
}
|
||||
#ifndef LIBXMP_CORE_PLAYER
|
||||
if (xfh.headersz == 0x0113) {
|
||||
strcpy(tracker_name, "unknown tracker");
|
||||
m->quirk &= ~QUIRK_FT2BUGS;
|
||||
} else if (*tracker_name == 0) {
|
||||
strcpy(tracker_name, "Digitrakker"); /* best guess */
|
||||
m->quirk &= ~QUIRK_FT2BUGS;
|
||||
}
|
||||
|
||||
/* See MMD1 loader for explanation */
|
||||
if (!strncmp(tracker_name, "MED2XM by J.Pynnone", 19)) {
|
||||
if (mod->bpm <= 10) {
|
||||
mod->bpm = 125 * (0x35 - mod->bpm * 2) / 33;
|
||||
}
|
||||
m->quirk &= ~QUIRK_FT2BUGS;
|
||||
}
|
||||
|
||||
if (!strncmp(tracker_name, "FastTracker v 2.00", 18)) {
|
||||
strcpy(tracker_name, "old ModPlug Tracker");
|
||||
m->quirk &= ~QUIRK_FT2BUGS;
|
||||
}
|
||||
|
||||
libxmp_set_type(m, "%s XM %d.%02d", tracker_name, xfh.version >> 8, xfh.version & 0xff);
|
||||
#else
|
||||
libxmp_set_type(m, tracker_name);
|
||||
#endif
|
||||
|
||||
MODULE_INFO();
|
||||
|
||||
/* Honor header size */
|
||||
if (hio_seek(f, start + xfh.headersz + 60, SEEK_SET) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* XM 1.02/1.03 has a different patterns and instruments order */
|
||||
if (xfh.version <= 0x0103) {
|
||||
if (load_instruments(m, xfh.version, f) < 0) {
|
||||
return -1;
|
||||
}
|
||||
if (load_patterns(m, xfh.version, f) < 0) {
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
if (load_patterns(m, xfh.version, f) < 0) {
|
||||
return -1;
|
||||
}
|
||||
if (load_instruments(m, xfh.version, f) < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
D_(D_INFO "Stored samples: %d", mod->smp);
|
||||
|
||||
/* XM 1.02 stores all samples after the patterns */
|
||||
if (xfh.version <= 0x0103) {
|
||||
for (i = 0; i < mod->ins; i++) {
|
||||
for (j = 0; j < mod->xxi[i].nsm; j++) {
|
||||
int sid = mod->xxi[i].sub[j].sid;
|
||||
if (libxmp_load_sample(m, f, SAMPLE_FLAG_DIFF, &mod->xxs[sid], NULL) < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < mod->chn; i++) {
|
||||
mod->xxc[i].pan = 0x80;
|
||||
}
|
||||
|
||||
m->quirk |= QUIRKS_FT2;
|
||||
m->read_event_type = READ_EVENT_FT2;
|
||||
|
||||
return 0;
|
||||
}
|
389
internal/c/parts/audio/extras/libxmp-lite/xmp.h
Normal file
389
internal/c/parts/audio/extras/libxmp-lite/xmp.h
Normal file
|
@ -0,0 +1,389 @@
|
|||
#ifndef XMP_H
|
||||
#define XMP_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define XMP_VERSION "4.5.0"
|
||||
#define XMP_VERCODE 0x040500
|
||||
#define XMP_VER_MAJOR 4
|
||||
#define XMP_VER_MINOR 5
|
||||
#define XMP_VER_RELEASE 0
|
||||
|
||||
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||
# if defined(BUILDING_STATIC)
|
||||
# define LIBXMP_EXPORT
|
||||
# elif defined(BUILDING_DLL)
|
||||
# define LIBXMP_EXPORT __declspec(dllexport)
|
||||
# else
|
||||
# define LIBXMP_EXPORT __declspec(dllimport)
|
||||
# endif
|
||||
#elif defined(__OS2__) && defined(__WATCOMC__) && defined(__SW_BD)
|
||||
# define LIBXMP_EXPORT __declspec(dllexport)
|
||||
#elif (defined(__GNUC__) || defined(__clang__) || defined(__HP_cc)) && defined(XMP_SYM_VISIBILITY)
|
||||
# define LIBXMP_EXPORT __attribute__((visibility ("default")))
|
||||
#elif defined(__SUNPRO_C) && defined(XMP_LDSCOPE_GLOBAL)
|
||||
# define LIBXMP_EXPORT __global
|
||||
#elif defined(EMSCRIPTEN)
|
||||
# include <emscripten.h>
|
||||
# define LIBXMP_EXPORT EMSCRIPTEN_KEEPALIVE
|
||||
# define LIBXMP_EXPORT_VAR
|
||||
#else
|
||||
# define LIBXMP_EXPORT
|
||||
#endif
|
||||
|
||||
#if !defined (LIBXMP_EXPORT_VAR)
|
||||
# define LIBXMP_EXPORT_VAR LIBXMP_EXPORT
|
||||
#endif
|
||||
|
||||
#define XMP_NAME_SIZE 64 /* Size of module name and type */
|
||||
|
||||
#define XMP_KEY_OFF 0x81 /* Note number for key off event */
|
||||
#define XMP_KEY_CUT 0x82 /* Note number for key cut event */
|
||||
#define XMP_KEY_FADE 0x83 /* Note number for fade event */
|
||||
|
||||
/* mixer parameter macros */
|
||||
|
||||
/* sample format flags */
|
||||
#define XMP_FORMAT_8BIT (1 << 0) /* Mix to 8-bit instead of 16 */
|
||||
#define XMP_FORMAT_UNSIGNED (1 << 1) /* Mix to unsigned samples */
|
||||
#define XMP_FORMAT_MONO (1 << 2) /* Mix to mono instead of stereo */
|
||||
|
||||
/* player parameters */
|
||||
#define XMP_PLAYER_AMP 0 /* Amplification factor */
|
||||
#define XMP_PLAYER_MIX 1 /* Stereo mixing */
|
||||
#define XMP_PLAYER_INTERP 2 /* Interpolation type */
|
||||
#define XMP_PLAYER_DSP 3 /* DSP effect flags */
|
||||
#define XMP_PLAYER_FLAGS 4 /* Player flags */
|
||||
#define XMP_PLAYER_CFLAGS 5 /* Player flags for current module */
|
||||
#define XMP_PLAYER_SMPCTL 6 /* Sample control flags */
|
||||
#define XMP_PLAYER_VOLUME 7 /* Player module volume */
|
||||
#define XMP_PLAYER_STATE 8 /* Internal player state (read only) */
|
||||
#define XMP_PLAYER_SMIX_VOLUME 9 /* SMIX volume */
|
||||
#define XMP_PLAYER_DEFPAN 10 /* Default pan setting */
|
||||
#define XMP_PLAYER_MODE 11 /* Player personality */
|
||||
#define XMP_PLAYER_MIXER_TYPE 12 /* Current mixer (read only) */
|
||||
#define XMP_PLAYER_VOICES 13 /* Maximum number of mixer voices */
|
||||
|
||||
/* interpolation types */
|
||||
#define XMP_INTERP_NEAREST 0 /* Nearest neighbor */
|
||||
#define XMP_INTERP_LINEAR 1 /* Linear (default) */
|
||||
#define XMP_INTERP_SPLINE 2 /* Cubic spline */
|
||||
|
||||
/* dsp effect types */
|
||||
#define XMP_DSP_LOWPASS (1 << 0) /* Lowpass filter effect */
|
||||
#define XMP_DSP_ALL (XMP_DSP_LOWPASS)
|
||||
|
||||
/* player state */
|
||||
#define XMP_STATE_UNLOADED 0 /* Context created */
|
||||
#define XMP_STATE_LOADED 1 /* Module loaded */
|
||||
#define XMP_STATE_PLAYING 2 /* Module playing */
|
||||
|
||||
/* player flags */
|
||||
#define XMP_FLAGS_VBLANK (1 << 0) /* Use vblank timing */
|
||||
#define XMP_FLAGS_FX9BUG (1 << 1) /* Emulate FX9 bug */
|
||||
#define XMP_FLAGS_FIXLOOP (1 << 2) /* Emulate sample loop bug */
|
||||
#define XMP_FLAGS_A500 (1 << 3) /* Use Paula mixer in Amiga modules */
|
||||
|
||||
/* player modes */
|
||||
#define XMP_MODE_AUTO 0 /* Autodetect mode (default) */
|
||||
#define XMP_MODE_MOD 1 /* Play as a generic MOD player */
|
||||
#define XMP_MODE_NOISETRACKER 2 /* Play using Noisetracker quirks */
|
||||
#define XMP_MODE_PROTRACKER 3 /* Play using Protracker quirks */
|
||||
#define XMP_MODE_S3M 4 /* Play as a generic S3M player */
|
||||
#define XMP_MODE_ST3 5 /* Play using ST3 bug emulation */
|
||||
#define XMP_MODE_ST3GUS 6 /* Play using ST3+GUS quirks */
|
||||
#define XMP_MODE_XM 7 /* Play as a generic XM player */
|
||||
#define XMP_MODE_FT2 8 /* Play using FT2 bug emulation */
|
||||
#define XMP_MODE_IT 9 /* Play using IT quirks */
|
||||
#define XMP_MODE_ITSMP 10 /* Play using IT sample mode quirks */
|
||||
|
||||
/* mixer types */
|
||||
#define XMP_MIXER_STANDARD 0 /* Standard mixer */
|
||||
#define XMP_MIXER_A500 1 /* Amiga 500 */
|
||||
#define XMP_MIXER_A500F 2 /* Amiga 500 with led filter */
|
||||
|
||||
/* sample flags */
|
||||
#define XMP_SMPCTL_SKIP (1 << 0) /* Don't load samples */
|
||||
|
||||
/* limits */
|
||||
#define XMP_MAX_KEYS 121 /* Number of valid keys */
|
||||
#define XMP_MAX_ENV_POINTS 32 /* Max number of envelope points */
|
||||
#define XMP_MAX_MOD_LENGTH 256 /* Max number of patterns in module */
|
||||
#define XMP_MAX_CHANNELS 64 /* Max number of channels in module */
|
||||
#define XMP_MAX_SRATE 49170 /* max sampling rate (Hz) */
|
||||
#define XMP_MIN_SRATE 4000 /* min sampling rate (Hz) */
|
||||
#define XMP_MIN_BPM 20 /* min BPM */
|
||||
/* frame rate = (50 * bpm / 125) Hz */
|
||||
/* frame size = (sampling rate * channels * size) / frame rate */
|
||||
#define XMP_MAX_FRAMESIZE (5 * XMP_MAX_SRATE * 2 / XMP_MIN_BPM)
|
||||
|
||||
/* error codes */
|
||||
#define XMP_END 1
|
||||
#define XMP_ERROR_INTERNAL 2 /* Internal error */
|
||||
#define XMP_ERROR_FORMAT 3 /* Unsupported module format */
|
||||
#define XMP_ERROR_LOAD 4 /* Error loading file */
|
||||
#define XMP_ERROR_DEPACK 5 /* Error depacking file */
|
||||
#define XMP_ERROR_SYSTEM 6 /* System error */
|
||||
#define XMP_ERROR_INVALID 7 /* Invalid parameter */
|
||||
#define XMP_ERROR_STATE 8 /* Invalid player state */
|
||||
|
||||
struct xmp_channel {
|
||||
int pan; /* Channel pan (0x80 is center) */
|
||||
int vol; /* Channel volume */
|
||||
#define XMP_CHANNEL_SYNTH (1 << 0) /* Channel is synthesized */
|
||||
#define XMP_CHANNEL_MUTE (1 << 1) /* Channel is muted */
|
||||
#define XMP_CHANNEL_SPLIT (1 << 2) /* Split Amiga channel in bits 5-4 */
|
||||
#define XMP_CHANNEL_SURROUND (1 << 4) /* Surround channel */
|
||||
int flg; /* Channel flags */
|
||||
};
|
||||
|
||||
struct xmp_pattern {
|
||||
int rows; /* Number of rows */
|
||||
int index[1]; /* Track index */
|
||||
};
|
||||
|
||||
struct xmp_event {
|
||||
unsigned char note; /* Note number (0 means no note) */
|
||||
unsigned char ins; /* Patch number */
|
||||
unsigned char vol; /* Volume (0 to basevol) */
|
||||
unsigned char fxt; /* Effect type */
|
||||
unsigned char fxp; /* Effect parameter */
|
||||
unsigned char f2t; /* Secondary effect type */
|
||||
unsigned char f2p; /* Secondary effect parameter */
|
||||
unsigned char _flag; /* Internal (reserved) flags */
|
||||
};
|
||||
|
||||
struct xmp_track {
|
||||
int rows; /* Number of rows */
|
||||
struct xmp_event event[1]; /* Event data */
|
||||
};
|
||||
|
||||
struct xmp_envelope {
|
||||
#define XMP_ENVELOPE_ON (1 << 0) /* Envelope is enabled */
|
||||
#define XMP_ENVELOPE_SUS (1 << 1) /* Envelope has sustain point */
|
||||
#define XMP_ENVELOPE_LOOP (1 << 2) /* Envelope has loop */
|
||||
#define XMP_ENVELOPE_FLT (1 << 3) /* Envelope is used for filter */
|
||||
#define XMP_ENVELOPE_SLOOP (1 << 4) /* Envelope has sustain loop */
|
||||
#define XMP_ENVELOPE_CARRY (1 << 5) /* Don't reset envelope position */
|
||||
int flg; /* Flags */
|
||||
int npt; /* Number of envelope points */
|
||||
int scl; /* Envelope scaling */
|
||||
int sus; /* Sustain start point */
|
||||
int sue; /* Sustain end point */
|
||||
int lps; /* Loop start point */
|
||||
int lpe; /* Loop end point */
|
||||
short data[XMP_MAX_ENV_POINTS * 2];
|
||||
};
|
||||
|
||||
struct xmp_subinstrument {
|
||||
int vol; /* Default volume */
|
||||
int gvl; /* Global volume */
|
||||
int pan; /* Pan */
|
||||
int xpo; /* Transpose */
|
||||
int fin; /* Finetune */
|
||||
int vwf; /* Vibrato waveform */
|
||||
int vde; /* Vibrato depth */
|
||||
int vra; /* Vibrato rate */
|
||||
int vsw; /* Vibrato sweep */
|
||||
int rvv; /* Random volume/pan variation (IT) */
|
||||
int sid; /* Sample number */
|
||||
#define XMP_INST_NNA_CUT 0x00
|
||||
#define XMP_INST_NNA_CONT 0x01
|
||||
#define XMP_INST_NNA_OFF 0x02
|
||||
#define XMP_INST_NNA_FADE 0x03
|
||||
int nna; /* New note action */
|
||||
#define XMP_INST_DCT_OFF 0x00
|
||||
#define XMP_INST_DCT_NOTE 0x01
|
||||
#define XMP_INST_DCT_SMP 0x02
|
||||
#define XMP_INST_DCT_INST 0x03
|
||||
int dct; /* Duplicate check type */
|
||||
#define XMP_INST_DCA_CUT XMP_INST_NNA_CUT
|
||||
#define XMP_INST_DCA_OFF XMP_INST_NNA_OFF
|
||||
#define XMP_INST_DCA_FADE XMP_INST_NNA_FADE
|
||||
int dca; /* Duplicate check action */
|
||||
int ifc; /* Initial filter cutoff */
|
||||
int ifr; /* Initial filter resonance */
|
||||
};
|
||||
|
||||
struct xmp_instrument {
|
||||
char name[32]; /* Instrument name */
|
||||
int vol; /* Instrument volume */
|
||||
int nsm; /* Number of samples */
|
||||
int rls; /* Release (fadeout) */
|
||||
struct xmp_envelope aei; /* Amplitude envelope info */
|
||||
struct xmp_envelope pei; /* Pan envelope info */
|
||||
struct xmp_envelope fei; /* Frequency envelope info */
|
||||
|
||||
struct {
|
||||
unsigned char ins; /* Instrument number for each key */
|
||||
signed char xpo; /* Instrument transpose for each key */
|
||||
} map[XMP_MAX_KEYS];
|
||||
|
||||
struct xmp_subinstrument *sub;
|
||||
|
||||
void *extra; /* Extra fields */
|
||||
};
|
||||
|
||||
struct xmp_sample {
|
||||
char name[32]; /* Sample name */
|
||||
int len; /* Sample length */
|
||||
int lps; /* Loop start */
|
||||
int lpe; /* Loop end */
|
||||
#define XMP_SAMPLE_16BIT (1 << 0) /* 16bit sample */
|
||||
#define XMP_SAMPLE_LOOP (1 << 1) /* Sample is looped */
|
||||
#define XMP_SAMPLE_LOOP_BIDIR (1 << 2) /* Bidirectional sample loop */
|
||||
#define XMP_SAMPLE_LOOP_REVERSE (1 << 3) /* Backwards sample loop */
|
||||
#define XMP_SAMPLE_LOOP_FULL (1 << 4) /* Play full sample before looping */
|
||||
#define XMP_SAMPLE_SLOOP (1 << 5) /* Sample has sustain loop */
|
||||
#define XMP_SAMPLE_SLOOP_BIDIR (1 << 6) /* Bidirectional sustain loop */
|
||||
#define XMP_SAMPLE_SYNTH (1 << 15) /* Data contains synth patch */
|
||||
int flg; /* Flags */
|
||||
unsigned char *data; /* Sample data */
|
||||
};
|
||||
|
||||
struct xmp_sequence {
|
||||
int entry_point;
|
||||
int duration;
|
||||
};
|
||||
|
||||
struct xmp_module {
|
||||
char name[XMP_NAME_SIZE]; /* Module title */
|
||||
char type[XMP_NAME_SIZE]; /* Module format */
|
||||
int pat; /* Number of patterns */
|
||||
int trk; /* Number of tracks */
|
||||
int chn; /* Tracks per pattern */
|
||||
int ins; /* Number of instruments */
|
||||
int smp; /* Number of samples */
|
||||
int spd; /* Initial speed */
|
||||
int bpm; /* Initial BPM */
|
||||
int len; /* Module length in patterns */
|
||||
int rst; /* Restart position */
|
||||
int gvl; /* Global volume */
|
||||
|
||||
struct xmp_pattern **xxp; /* Patterns */
|
||||
struct xmp_track **xxt; /* Tracks */
|
||||
struct xmp_instrument *xxi; /* Instruments */
|
||||
struct xmp_sample *xxs; /* Samples */
|
||||
struct xmp_channel xxc[XMP_MAX_CHANNELS]; /* Channel info */
|
||||
unsigned char xxo[XMP_MAX_MOD_LENGTH]; /* Orders */
|
||||
};
|
||||
|
||||
struct xmp_test_info {
|
||||
char name[XMP_NAME_SIZE]; /* Module title */
|
||||
char type[XMP_NAME_SIZE]; /* Module format */
|
||||
};
|
||||
|
||||
struct xmp_module_info {
|
||||
unsigned char md5[16]; /* MD5 message digest */
|
||||
int vol_base; /* Volume scale */
|
||||
struct xmp_module *mod; /* Pointer to module data */
|
||||
char *comment; /* Comment text, if any */
|
||||
int num_sequences; /* Number of valid sequences */
|
||||
struct xmp_sequence *seq_data; /* Pointer to sequence data */
|
||||
};
|
||||
|
||||
struct xmp_channel_info {
|
||||
unsigned int period; /* Sample period (* 4096) */
|
||||
unsigned int position; /* Sample position */
|
||||
short pitchbend; /* Linear bend from base note*/
|
||||
unsigned char note; /* Current base note number */
|
||||
unsigned char instrument; /* Current instrument number */
|
||||
unsigned char sample; /* Current sample number */
|
||||
unsigned char volume; /* Current volume */
|
||||
unsigned char pan; /* Current stereo pan */
|
||||
unsigned char reserved; /* Reserved */
|
||||
struct xmp_event event; /* Current track event */
|
||||
};
|
||||
|
||||
struct xmp_frame_info { /* Current frame information */
|
||||
int pos; /* Current position */
|
||||
int pattern; /* Current pattern */
|
||||
int row; /* Current row in pattern */
|
||||
int num_rows; /* Number of rows in current pattern */
|
||||
int frame; /* Current frame */
|
||||
int speed; /* Current replay speed */
|
||||
int bpm; /* Current bpm */
|
||||
int time; /* Current module time in ms */
|
||||
int total_time; /* Estimated replay time in ms*/
|
||||
int frame_time; /* Frame replay time in us */
|
||||
void *buffer; /* Pointer to sound buffer */
|
||||
int buffer_size; /* Used buffer size */
|
||||
int total_size; /* Total buffer size */
|
||||
int volume; /* Current master volume */
|
||||
int loop_count; /* Loop counter */
|
||||
int virt_channels; /* Number of virtual channels */
|
||||
int virt_used; /* Used virtual channels */
|
||||
int sequence; /* Current sequence */
|
||||
|
||||
struct xmp_channel_info channel_info[XMP_MAX_CHANNELS]; /* Current channel information */
|
||||
};
|
||||
|
||||
struct xmp_callbacks {
|
||||
unsigned long (*read_func)(void *dest, unsigned long len,
|
||||
unsigned long nmemb, void *priv);
|
||||
int (*seek_func)(void *priv, long offset, int whence);
|
||||
long (*tell_func)(void *priv);
|
||||
int (*close_func)(void *priv);
|
||||
};
|
||||
|
||||
typedef char *xmp_context;
|
||||
|
||||
LIBXMP_EXPORT_VAR extern const char *xmp_version;
|
||||
LIBXMP_EXPORT_VAR extern const unsigned int xmp_vercode;
|
||||
|
||||
LIBXMP_EXPORT int xmp_syserrno (void);
|
||||
|
||||
LIBXMP_EXPORT xmp_context xmp_create_context (void);
|
||||
LIBXMP_EXPORT void xmp_free_context (xmp_context);
|
||||
|
||||
LIBXMP_EXPORT int xmp_load_module (xmp_context, const char *);
|
||||
LIBXMP_EXPORT int xmp_load_module_from_memory (xmp_context, const void *, long);
|
||||
LIBXMP_EXPORT int xmp_load_module_from_file (xmp_context, void *, long);
|
||||
LIBXMP_EXPORT int xmp_load_module_from_callbacks (xmp_context, void *, struct xmp_callbacks);
|
||||
|
||||
LIBXMP_EXPORT int xmp_test_module (const char *, struct xmp_test_info *);
|
||||
LIBXMP_EXPORT int xmp_test_module_from_memory (const void *, long, struct xmp_test_info *);
|
||||
LIBXMP_EXPORT int xmp_test_module_from_file (void *, struct xmp_test_info *);
|
||||
LIBXMP_EXPORT int xmp_test_module_from_callbacks (void *, struct xmp_callbacks, struct xmp_test_info *);
|
||||
|
||||
LIBXMP_EXPORT void xmp_scan_module (xmp_context);
|
||||
LIBXMP_EXPORT void xmp_release_module (xmp_context);
|
||||
|
||||
LIBXMP_EXPORT int xmp_start_player (xmp_context, int, int);
|
||||
LIBXMP_EXPORT int xmp_play_frame (xmp_context);
|
||||
LIBXMP_EXPORT int xmp_play_buffer (xmp_context, void *, int, int);
|
||||
LIBXMP_EXPORT void xmp_get_frame_info (xmp_context, struct xmp_frame_info *);
|
||||
LIBXMP_EXPORT void xmp_end_player (xmp_context);
|
||||
LIBXMP_EXPORT void xmp_inject_event (xmp_context, int, struct xmp_event *);
|
||||
LIBXMP_EXPORT void xmp_get_module_info (xmp_context, struct xmp_module_info *);
|
||||
LIBXMP_EXPORT const char *const *xmp_get_format_list (void);
|
||||
LIBXMP_EXPORT int xmp_next_position (xmp_context);
|
||||
LIBXMP_EXPORT int xmp_prev_position (xmp_context);
|
||||
LIBXMP_EXPORT int xmp_set_position (xmp_context, int);
|
||||
LIBXMP_EXPORT int xmp_set_row (xmp_context, int);
|
||||
LIBXMP_EXPORT int xmp_set_tempo_factor(xmp_context, double);
|
||||
LIBXMP_EXPORT void xmp_stop_module (xmp_context);
|
||||
LIBXMP_EXPORT void xmp_restart_module (xmp_context);
|
||||
LIBXMP_EXPORT int xmp_seek_time (xmp_context, int);
|
||||
LIBXMP_EXPORT int xmp_channel_mute (xmp_context, int, int);
|
||||
LIBXMP_EXPORT int xmp_channel_vol (xmp_context, int, int);
|
||||
LIBXMP_EXPORT int xmp_set_player (xmp_context, int, int);
|
||||
LIBXMP_EXPORT int xmp_get_player (xmp_context, int);
|
||||
LIBXMP_EXPORT int xmp_set_instrument_path (xmp_context, const char *);
|
||||
|
||||
/* External sample mixer API */
|
||||
LIBXMP_EXPORT int xmp_start_smix (xmp_context, int, int);
|
||||
LIBXMP_EXPORT void xmp_end_smix (xmp_context);
|
||||
LIBXMP_EXPORT int xmp_smix_play_instrument(xmp_context, int, int, int, int);
|
||||
LIBXMP_EXPORT int xmp_smix_play_sample (xmp_context, int, int, int, int);
|
||||
LIBXMP_EXPORT int xmp_smix_channel_pan (xmp_context, int, int);
|
||||
LIBXMP_EXPORT int xmp_smix_load_sample (xmp_context, int, const char *);
|
||||
LIBXMP_EXPORT int xmp_smix_release_sample (xmp_context, int);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* XMP_H */
|
505
internal/c/parts/audio/extras/miniaudio_libxmp-lite.h
Normal file
505
internal/c/parts/audio/extras/miniaudio_libxmp-lite.h
Normal file
|
@ -0,0 +1,505 @@
|
|||
//----------------------------------------------------------------------------------------------------
|
||||
// ___ ___ __ _ _ ___ ___ _ _ _ ___ _
|
||||
// / _ \| _ ) / /| | || _ \ __| /_\ _ _ __| (_)___ | __|_ _ __ _(_)_ _ ___
|
||||
// | (_) | _ \/ _ \_ _| _/ _| / _ \ || / _` | / _ \ | _|| ' \/ _` | | ' \/ -_)
|
||||
// \__\_\___/\___/ |_||_| |___| /_/ \_\_,_\__,_|_\___/ |___|_||_\__, |_|_||_\___|
|
||||
// |___/
|
||||
//
|
||||
// QB64-PE Audio Engine powered by miniaudio (https://miniaud.io/)
|
||||
//
|
||||
// This implements a data source that decodes MOD, S3M, XM & IT files using libxmp-lite
|
||||
// https://github.com/libxmp/libxmp/tree/master/lite (MIT)
|
||||
//
|
||||
// Copyright (c) 2022 Samuel Gomes
|
||||
// https://github.com/a740g
|
||||
//
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
// HEADER FILES
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
#include "../miniaudio.h"
|
||||
#define BUILDING_STATIC 1
|
||||
#include "libxmp-lite/xmp.h"
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
|
||||
struct ma_modplay {
|
||||
// This part is for miniaudio
|
||||
ma_data_source_base ds; /* The decoder can be used independently as a data source. */
|
||||
ma_read_proc onRead;
|
||||
ma_seek_proc onSeek;
|
||||
ma_tell_proc onTell;
|
||||
void *pReadSeekTellUserData;
|
||||
ma_format format;
|
||||
|
||||
// This part is format specific
|
||||
xmp_context xmpContext; // The player context
|
||||
xmp_frame_info xmpFrameInfo; // LibXMP frameinfo - used to detect loops
|
||||
ma_uint32 loopCount; // We'll maintain our own loop counter and check this against LibXMP's to detect new loops
|
||||
};
|
||||
|
||||
static ma_result ma_modplay_seek_to_pcm_frame(ma_modplay *pModplay, ma_uint64 frameIndex) {
|
||||
if (pModplay == NULL) {
|
||||
return MA_INVALID_ARGS;
|
||||
}
|
||||
|
||||
if (xmp_seek_time(pModplay->xmpContext, (int)((frameIndex * 1000) / MA_DEFAULT_SAMPLE_RATE)) == -XMP_ERROR_STATE) {
|
||||
return MA_INVALID_OPERATION;
|
||||
}
|
||||
|
||||
return MA_SUCCESS;
|
||||
}
|
||||
|
||||
static ma_result ma_modplay_get_data_format(ma_modplay *pModplay, ma_format *pFormat, ma_uint32 *pChannels, ma_uint32 *pSampleRate, ma_channel *pChannelMap,
|
||||
size_t channelMapCap) {
|
||||
/* Defaults for safety. */
|
||||
if (pFormat != NULL) {
|
||||
*pFormat = ma_format_unknown;
|
||||
}
|
||||
if (pChannels != NULL) {
|
||||
*pChannels = 0;
|
||||
}
|
||||
if (pSampleRate != NULL) {
|
||||
*pSampleRate = 0;
|
||||
}
|
||||
if (pChannelMap != NULL) {
|
||||
MA_ZERO_MEMORY(pChannelMap, sizeof(*pChannelMap) * channelMapCap);
|
||||
}
|
||||
|
||||
if (pModplay == NULL) {
|
||||
return MA_INVALID_OPERATION;
|
||||
}
|
||||
|
||||
if (pFormat != NULL) {
|
||||
*pFormat = pModplay->format;
|
||||
}
|
||||
|
||||
if (pChannels != NULL) {
|
||||
*pChannels = 2; // Stereo
|
||||
}
|
||||
|
||||
if (pSampleRate != NULL) {
|
||||
*pSampleRate = MA_DEFAULT_SAMPLE_RATE;
|
||||
}
|
||||
|
||||
if (pChannelMap != NULL) {
|
||||
ma_channel_map_init_standard(ma_standard_channel_map_default, pChannelMap, channelMapCap, 2);
|
||||
}
|
||||
|
||||
return MA_SUCCESS;
|
||||
}
|
||||
|
||||
static ma_result ma_modplay_read_pcm_frames(ma_modplay *pModplay, void *pFramesOut, ma_uint64 frameCount, ma_uint64 *pFramesRead) {
|
||||
if (pFramesRead != NULL) {
|
||||
*pFramesRead = 0;
|
||||
}
|
||||
|
||||
if (frameCount == 0) {
|
||||
return MA_INVALID_ARGS;
|
||||
}
|
||||
|
||||
if (pModplay == NULL) {
|
||||
return MA_INVALID_ARGS;
|
||||
}
|
||||
|
||||
ma_result result = MA_SUCCESS; // Must be initialized to MA_SUCCESS
|
||||
|
||||
// Render some 16-bit stereo sample frames
|
||||
int xmpError = xmp_play_buffer(pModplay->xmpContext, pFramesOut, (int)(frameCount * sizeof(ma_int16) * 2), 0);
|
||||
|
||||
// Get the frame information to detect if we are looping
|
||||
xmp_get_frame_info(pModplay->xmpContext, &pModplay->xmpFrameInfo);
|
||||
|
||||
// Check if we have reached the end or are looping
|
||||
if (pModplay->xmpFrameInfo.loop_count != pModplay->loopCount || xmpError == -XMP_END || xmpError == -XMP_ERROR_STATE) {
|
||||
pModplay->loopCount = pModplay->xmpFrameInfo.loop_count;
|
||||
result = MA_AT_END;
|
||||
}
|
||||
|
||||
if (pFramesRead != NULL) {
|
||||
*pFramesRead = frameCount;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static ma_result ma_modplay_get_cursor_in_pcm_frames(ma_modplay *pModplay, ma_uint64 *pCursor) {
|
||||
if (!pCursor) {
|
||||
return MA_INVALID_ARGS;
|
||||
}
|
||||
|
||||
*pCursor = 0; /* Safety. */
|
||||
|
||||
if (!pModplay) {
|
||||
return MA_INVALID_ARGS;
|
||||
}
|
||||
|
||||
// Get the frame information
|
||||
xmp_get_frame_info(pModplay->xmpContext, &pModplay->xmpFrameInfo);
|
||||
|
||||
ma_int64 offset = ((ma_int64)pModplay->xmpFrameInfo.time * MA_DEFAULT_SAMPLE_RATE) / 1000;
|
||||
if (offset < 0) {
|
||||
return MA_INVALID_FILE;
|
||||
}
|
||||
|
||||
*pCursor = (ma_uint64)offset;
|
||||
|
||||
return MA_SUCCESS;
|
||||
}
|
||||
|
||||
static ma_result ma_modplay_get_length_in_pcm_frames(ma_modplay *pModplay, ma_uint64 *pLength) {
|
||||
if (!pLength) {
|
||||
return MA_INVALID_ARGS;
|
||||
}
|
||||
|
||||
*pLength = 0; /* Safety. */
|
||||
|
||||
if (!pModplay) {
|
||||
return MA_INVALID_ARGS;
|
||||
}
|
||||
|
||||
ma_int64 length = ((ma_int64)pModplay->xmpFrameInfo.total_time * MA_DEFAULT_SAMPLE_RATE) / 1000;
|
||||
if (length < 0) {
|
||||
return MA_INVALID_FILE;
|
||||
}
|
||||
|
||||
*pLength = (ma_uint64)length;
|
||||
|
||||
return MA_SUCCESS;
|
||||
}
|
||||
|
||||
static ma_result ma_modplay_ds_read(ma_data_source *pDataSource, void *pFramesOut, ma_uint64 frameCount, ma_uint64 *pFramesRead) {
|
||||
return ma_modplay_read_pcm_frames((ma_modplay *)pDataSource, pFramesOut, frameCount, pFramesRead);
|
||||
}
|
||||
|
||||
static ma_result ma_modplay_ds_seek(ma_data_source *pDataSource, ma_uint64 frameIndex) {
|
||||
return ma_modplay_seek_to_pcm_frame((ma_modplay *)pDataSource, frameIndex);
|
||||
}
|
||||
|
||||
static ma_result ma_modplay_ds_get_data_format(ma_data_source *pDataSource, ma_format *pFormat, ma_uint32 *pChannels, ma_uint32 *pSampleRate,
|
||||
ma_channel *pChannelMap, size_t channelMapCap) {
|
||||
return ma_modplay_get_data_format((ma_modplay *)pDataSource, pFormat, pChannels, pSampleRate, pChannelMap, channelMapCap);
|
||||
}
|
||||
|
||||
static ma_result ma_modplay_ds_get_cursor(ma_data_source *pDataSource, ma_uint64 *pCursor) {
|
||||
return ma_modplay_get_cursor_in_pcm_frames((ma_modplay *)pDataSource, pCursor);
|
||||
}
|
||||
|
||||
static ma_result ma_modplay_ds_get_length(ma_data_source *pDataSource, ma_uint64 *pLength) {
|
||||
return ma_modplay_get_length_in_pcm_frames((ma_modplay *)pDataSource, pLength);
|
||||
}
|
||||
|
||||
static ma_data_source_vtable ma_data_source_vtable_modplay = {ma_modplay_ds_read, ma_modplay_ds_seek, ma_modplay_ds_get_data_format, ma_modplay_ds_get_cursor,
|
||||
ma_modplay_ds_get_length};
|
||||
|
||||
static int ma_modplay_of_callback__read(void *pUserData, unsigned char *pBufferOut, int bytesToRead) {
|
||||
ma_modplay *pModplay = (ma_modplay *)pUserData;
|
||||
ma_result result;
|
||||
size_t bytesRead;
|
||||
|
||||
result = pModplay->onRead(pModplay->pReadSeekTellUserData, (void *)pBufferOut, bytesToRead, &bytesRead);
|
||||
|
||||
if (result != MA_SUCCESS) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return (int)bytesRead;
|
||||
}
|
||||
|
||||
static int ma_modplay_of_callback__seek(void *pUserData, ma_int64 offset, int whence) {
|
||||
ma_modplay *pModplay = (ma_modplay *)pUserData;
|
||||
ma_result result;
|
||||
ma_seek_origin origin;
|
||||
|
||||
if (whence == SEEK_SET) {
|
||||
origin = ma_seek_origin_start;
|
||||
} else if (whence == SEEK_END) {
|
||||
origin = ma_seek_origin_end;
|
||||
} else {
|
||||
origin = ma_seek_origin_current;
|
||||
}
|
||||
|
||||
result = pModplay->onSeek(pModplay->pReadSeekTellUserData, offset, origin);
|
||||
if (result != MA_SUCCESS) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ma_int64 ma_modplay_of_callback__tell(void *pUserData) {
|
||||
ma_modplay *pModplay = (ma_modplay *)pUserData;
|
||||
ma_result result;
|
||||
ma_int64 cursor;
|
||||
|
||||
if (pModplay->onTell == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
result = pModplay->onTell(pModplay->pReadSeekTellUserData, &cursor);
|
||||
if (result != MA_SUCCESS) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return cursor;
|
||||
}
|
||||
|
||||
static ma_result ma_modplay_init_internal(const ma_decoding_backend_config *pConfig, ma_modplay *pModplay) {
|
||||
ma_result result;
|
||||
ma_data_source_config dataSourceConfig;
|
||||
|
||||
if (pModplay == NULL) {
|
||||
return MA_INVALID_ARGS;
|
||||
}
|
||||
|
||||
MA_ZERO_OBJECT(pModplay);
|
||||
pModplay->format = ma_format::ma_format_s16; // We'll render 16-bit signed samples by default
|
||||
|
||||
if (pConfig != NULL && pConfig->preferredFormat == ma_format::ma_format_s16) {
|
||||
pModplay->format = pConfig->preferredFormat;
|
||||
} else {
|
||||
/* Getting here means something other than s16 was specified. Just leave this unset to use the default format. */
|
||||
}
|
||||
|
||||
dataSourceConfig = ma_data_source_config_init();
|
||||
dataSourceConfig.vtable = &ma_data_source_vtable_modplay;
|
||||
|
||||
result = ma_data_source_init(&dataSourceConfig, &pModplay->ds);
|
||||
if (result != MA_SUCCESS) {
|
||||
return result; /* Failed to initialize the base data source. */
|
||||
}
|
||||
|
||||
return MA_SUCCESS;
|
||||
}
|
||||
|
||||
static ma_result ma_modplay_init(ma_read_proc onRead, ma_seek_proc onSeek, ma_tell_proc onTell, void *pReadSeekTellUserData,
|
||||
const ma_decoding_backend_config *pConfig, const ma_allocation_callbacks *pAllocationCallbacks, ma_modplay *pModplay) {
|
||||
ma_result result;
|
||||
|
||||
(void)pAllocationCallbacks; /* Can't seem to find a way to configure memory allocations in libopus. */
|
||||
|
||||
result = ma_modplay_init_internal(pConfig, pModplay);
|
||||
if (result != MA_SUCCESS) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if (onRead == NULL || onSeek == NULL) {
|
||||
return MA_INVALID_ARGS; /* onRead and onSeek are mandatory. */
|
||||
}
|
||||
|
||||
pModplay->onRead = onRead;
|
||||
pModplay->onSeek = onSeek;
|
||||
pModplay->onTell = onTell;
|
||||
pModplay->pReadSeekTellUserData = pReadSeekTellUserData;
|
||||
|
||||
// Find the size of the file
|
||||
if (ma_modplay_of_callback__seek(pModplay, 0, SEEK_END) != 0) {
|
||||
return MA_BAD_SEEK;
|
||||
}
|
||||
|
||||
// Calculate the length
|
||||
ma_int64 file_size = ma_modplay_of_callback__tell(pModplay);
|
||||
if (file_size < 1) {
|
||||
return MA_INVALID_FILE;
|
||||
}
|
||||
|
||||
// Seek to the beginning of the file
|
||||
if (ma_modplay_of_callback__seek(pModplay, 0, SEEK_SET) != 0) {
|
||||
return MA_BAD_SEEK;
|
||||
}
|
||||
|
||||
// Allocate some memory for the tune
|
||||
ma_uint8 *tune = new ma_uint8[file_size];
|
||||
if (tune == nullptr) {
|
||||
return MA_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
// Read the file
|
||||
if (ma_modplay_of_callback__read(pModplay, tune, (int)file_size) < 1) {
|
||||
delete[] tune;
|
||||
return MA_IO_ERROR;
|
||||
}
|
||||
|
||||
// Check if the file is a valid module music
|
||||
xmp_test_info xmpTestInfo;
|
||||
int xmpError = xmp_test_module_from_memory(tune, (long)file_size, &xmpTestInfo);
|
||||
if (xmpError != 0) {
|
||||
delete[] tune;
|
||||
return MA_INVALID_FILE;
|
||||
}
|
||||
|
||||
// Initialize the player
|
||||
pModplay->xmpContext = xmp_create_context();
|
||||
if (!pModplay->xmpContext) {
|
||||
delete[] tune;
|
||||
return MA_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
// Load the module file
|
||||
xmpError = xmp_load_module_from_memory(pModplay->xmpContext, tune, (long)file_size);
|
||||
if (xmpError != 0) {
|
||||
xmp_free_context(pModplay->xmpContext);
|
||||
pModplay->xmpContext = nullptr;
|
||||
delete[] tune;
|
||||
return MA_INVALID_FILE;
|
||||
}
|
||||
|
||||
// Free the memory now that we don't need it anymore
|
||||
delete[] tune;
|
||||
|
||||
// Initialize the player
|
||||
xmpError = xmp_start_player(pModplay->xmpContext, MA_DEFAULT_SAMPLE_RATE, 0);
|
||||
if (xmpError != 0) {
|
||||
xmp_release_module(pModplay->xmpContext);
|
||||
xmp_free_context(pModplay->xmpContext);
|
||||
pModplay->xmpContext = nullptr;
|
||||
return MA_INVALID_FILE;
|
||||
}
|
||||
|
||||
// Set some player properties. These are not critical. So, we will not check the return values
|
||||
// These makes the sound quality much better when devices have sample rates other than 44100
|
||||
xmpError = xmp_set_player(pModplay->xmpContext, XMP_PLAYER_INTERP, XMP_INTERP_SPLINE);
|
||||
xmpError = xmp_set_player(pModplay->xmpContext, XMP_PLAYER_DSP, XMP_DSP_ALL);
|
||||
|
||||
xmp_get_frame_info(pModplay->xmpContext, &pModplay->xmpFrameInfo); // Get the frame information
|
||||
pModplay->loopCount = pModplay->xmpFrameInfo.loop_count; // Save the loop counter
|
||||
|
||||
return MA_SUCCESS;
|
||||
}
|
||||
|
||||
static ma_result ma_modplay_init_file(const char *pFilePath, const ma_decoding_backend_config *pConfig, const ma_allocation_callbacks *pAllocationCallbacks,
|
||||
ma_modplay *pModplay) {
|
||||
ma_result result;
|
||||
|
||||
(void)pAllocationCallbacks; /* Can't seem to find a way to configure memory allocations in libopus. */
|
||||
|
||||
result = ma_modplay_init_internal(pConfig, pModplay);
|
||||
if (result != MA_SUCCESS) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// Check the file extension
|
||||
if (!ma_path_extension_equal(pFilePath, "it") && !ma_path_extension_equal(pFilePath, "xm") && !ma_path_extension_equal(pFilePath, "s3m") &&
|
||||
!ma_path_extension_equal(pFilePath, "mod")) {
|
||||
return MA_INVALID_FILE;
|
||||
}
|
||||
|
||||
// Check if the file is a valid module music
|
||||
xmp_test_info xmpTestInfo;
|
||||
int xmpError = xmp_test_module(pFilePath, &xmpTestInfo);
|
||||
if (xmpError != 0) {
|
||||
return MA_INVALID_FILE;
|
||||
}
|
||||
|
||||
// Initialize the player
|
||||
pModplay->xmpContext = xmp_create_context();
|
||||
if (!pModplay->xmpContext) {
|
||||
return MA_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
// Load the module file
|
||||
xmpError = xmp_load_module(pModplay->xmpContext, pFilePath);
|
||||
if (xmpError != 0) {
|
||||
xmp_free_context(pModplay->xmpContext);
|
||||
pModplay->xmpContext = nullptr;
|
||||
return MA_INVALID_FILE;
|
||||
}
|
||||
|
||||
// Initialize the player
|
||||
xmpError = xmp_start_player(pModplay->xmpContext, MA_DEFAULT_SAMPLE_RATE, 0);
|
||||
if (xmpError != 0) {
|
||||
xmp_release_module(pModplay->xmpContext);
|
||||
xmp_free_context(pModplay->xmpContext);
|
||||
pModplay->xmpContext = nullptr;
|
||||
return MA_INVALID_FILE;
|
||||
}
|
||||
|
||||
// Set some player properties. These are not critical. So, we will not check the return values
|
||||
// These makes the sound quality much better when devices have sample rates other than 44100
|
||||
xmpError = xmp_set_player(pModplay->xmpContext, XMP_PLAYER_INTERP, XMP_INTERP_SPLINE);
|
||||
xmpError = xmp_set_player(pModplay->xmpContext, XMP_PLAYER_DSP, XMP_DSP_ALL);
|
||||
|
||||
xmp_get_frame_info(pModplay->xmpContext, &pModplay->xmpFrameInfo); // Get the frame information
|
||||
pModplay->loopCount = pModplay->xmpFrameInfo.loop_count; // Save the loop counter
|
||||
|
||||
return MA_SUCCESS;
|
||||
}
|
||||
|
||||
static void ma_modplay_uninit(ma_modplay *pModplay, const ma_allocation_callbacks *pAllocationCallbacks) {
|
||||
if (pModplay == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
(void)pAllocationCallbacks;
|
||||
|
||||
xmp_end_player(pModplay->xmpContext);
|
||||
xmp_release_module(pModplay->xmpContext);
|
||||
xmp_free_context(pModplay->xmpContext);
|
||||
pModplay->xmpContext = nullptr;
|
||||
|
||||
ma_data_source_uninit(&pModplay->ds);
|
||||
}
|
||||
|
||||
static ma_result ma_decoding_backend_init__modplay(void *pUserData, ma_read_proc onRead, ma_seek_proc onSeek, ma_tell_proc onTell, void *pReadSeekTellUserData,
|
||||
const ma_decoding_backend_config *pConfig, const ma_allocation_callbacks *pAllocationCallbacks,
|
||||
ma_data_source **ppBackend) {
|
||||
ma_result result;
|
||||
ma_modplay *pModplay;
|
||||
|
||||
(void)pUserData;
|
||||
|
||||
pModplay = (ma_modplay *)ma_malloc(sizeof(ma_modplay), pAllocationCallbacks);
|
||||
if (pModplay == NULL) {
|
||||
return MA_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
result = ma_modplay_init(onRead, onSeek, onTell, pReadSeekTellUserData, pConfig, pAllocationCallbacks, pModplay);
|
||||
if (result != MA_SUCCESS) {
|
||||
ma_free(pModplay, pAllocationCallbacks);
|
||||
return result;
|
||||
}
|
||||
|
||||
*ppBackend = pModplay;
|
||||
|
||||
return MA_SUCCESS;
|
||||
}
|
||||
|
||||
static ma_result ma_decoding_backend_init_file__modplay(void *pUserData, const char *pFilePath, const ma_decoding_backend_config *pConfig,
|
||||
const ma_allocation_callbacks *pAllocationCallbacks, ma_data_source **ppBackend) {
|
||||
ma_result result;
|
||||
ma_modplay *pModplay;
|
||||
|
||||
(void)pUserData;
|
||||
|
||||
pModplay = (ma_modplay *)ma_malloc(sizeof(ma_modplay), pAllocationCallbacks);
|
||||
if (pModplay == NULL) {
|
||||
return MA_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
result = ma_modplay_init_file(pFilePath, pConfig, pAllocationCallbacks, pModplay);
|
||||
if (result != MA_SUCCESS) {
|
||||
ma_free(pModplay, pAllocationCallbacks);
|
||||
return result;
|
||||
}
|
||||
|
||||
*ppBackend = pModplay;
|
||||
|
||||
return MA_SUCCESS;
|
||||
}
|
||||
|
||||
static void ma_decoding_backend_uninit__modplay(void *pUserData, ma_data_source *pBackend, const ma_allocation_callbacks *pAllocationCallbacks) {
|
||||
ma_modplay *pModplay = (ma_modplay *)pBackend;
|
||||
|
||||
(void)pUserData;
|
||||
|
||||
ma_modplay_uninit(pModplay, pAllocationCallbacks);
|
||||
ma_free(pModplay, pAllocationCallbacks);
|
||||
}
|
||||
|
||||
static ma_decoding_backend_vtable ma_decoding_backend_vtable_modplay = {ma_decoding_backend_init__modplay, ma_decoding_backend_init_file__modplay,
|
||||
NULL, /* onInitFileW() */
|
||||
NULL, /* onInitMemory() */
|
||||
ma_decoding_backend_uninit__modplay};
|
||||
//-----------------------------------------------------------------------------------------------------
|
609
internal/c/parts/audio/extras/miniaudio_radv2.h
Normal file
609
internal/c/parts/audio/extras/miniaudio_radv2.h
Normal file
|
@ -0,0 +1,609 @@
|
|||
//----------------------------------------------------------------------------------------------------
|
||||
// ___ ___ __ _ _ ___ ___ _ _ _ ___ _
|
||||
// / _ \| _ ) / /| | || _ \ __| /_\ _ _ __| (_)___ | __|_ _ __ _(_)_ _ ___
|
||||
// | (_) | _ \/ _ \_ _| _/ _| / _ \ || / _` | / _ \ | _|| ' \/ _` | | ' \/ -_)
|
||||
// \__\_\___/\___/ |_||_| |___| /_/ \_\_,_\__,_|_\___/ |___|_||_\__, |_|_||_\___|
|
||||
// |___/
|
||||
//
|
||||
// QB64-PE Audio Engine powered by miniaudio (https://miniaud.io/)
|
||||
//
|
||||
// This implements a data source that decodes Reality Adlib Tracker 2 tunes
|
||||
// https://realityproductions.itch.io/rad (Public Domain)
|
||||
//
|
||||
// From: Willy Reeve <shayde0@gmail.com>
|
||||
// Sent: Sunday, 7 August, 2022 01:23 PM
|
||||
// To: Samuel Gomes <v_2samg@hotmail.com>
|
||||
// Cc: Carl Pettitt <carl@clonestudios.co.uk>
|
||||
// Subject: Re: Contact from Reality website
|
||||
//
|
||||
// Hi Samuel,
|
||||
//
|
||||
// The player source code is Public Domain.
|
||||
//
|
||||
// Shayde
|
||||
//
|
||||
// On Fri, Aug 5, 2022 at 6:33 AM Reality website <rogue@3eality.com> wrote:
|
||||
// Contact from the Reality website:
|
||||
// Name: Samuel Gomes
|
||||
// Email: v_2samg@hotmail.com
|
||||
// Message:
|
||||
//
|
||||
// RADv2 - great stuff! I am planning to integrate the included player code in my projects. Can you please
|
||||
// let me know the license type for the player code? If there is one, putting it somewhere on the site or
|
||||
// zip would be fantastic!
|
||||
//
|
||||
// Thanks!
|
||||
//
|
||||
// Copyright (c) 2022 Samuel Gomes
|
||||
// https://github.com/a740g
|
||||
//
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
// HEADER FILES
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
#include "../miniaudio.h"
|
||||
#include "radv2/opal.cpp"
|
||||
#define RAD_DETECT_REPEATS 1
|
||||
#include "radv2/player20.cpp"
|
||||
#include "radv2/validate20.cpp"
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
|
||||
struct ma_radv2 {
|
||||
// This part is for miniaudio
|
||||
ma_data_source_base ds; /* The decoder can be used independently as a data source. */
|
||||
ma_read_proc onRead;
|
||||
ma_seek_proc onSeek;
|
||||
ma_tell_proc onTell;
|
||||
void *pReadSeekTellUserData;
|
||||
ma_format format;
|
||||
|
||||
// This part is format specific
|
||||
RADPlayer *player; // RADv2 player object
|
||||
Opal *adlib; // Opal Adlib emulator object
|
||||
ma_uint8 *tune; // The song data (RADv2 needs this to be alive for rendering samples!)
|
||||
uint32_t totalTime; // Total time in seconds
|
||||
int sampleCount; // The number of samples generated in each update
|
||||
int sampleUpdate; // Size of each update in samples after which the player must be updated
|
||||
};
|
||||
|
||||
static ma_result ma_radv2_seek_to_pcm_frame(ma_radv2 *pRadv2, ma_uint64 frameIndex) {
|
||||
if (!pRadv2) {
|
||||
return MA_INVALID_ARGS;
|
||||
}
|
||||
|
||||
// We can only reset the player to the beginning
|
||||
if (frameIndex == 0) {
|
||||
pRadv2->player->Stop();
|
||||
return MA_SUCCESS;
|
||||
}
|
||||
|
||||
return MA_INVALID_OPERATION; // Anything else is not seekable
|
||||
}
|
||||
|
||||
static ma_result ma_radv2_get_data_format(ma_radv2 *pRadv2, ma_format *pFormat, ma_uint32 *pChannels, ma_uint32 *pSampleRate, ma_channel *pChannelMap,
|
||||
size_t channelMapCap) {
|
||||
/* Defaults for safety. */
|
||||
if (pFormat != NULL) {
|
||||
*pFormat = ma_format_unknown;
|
||||
}
|
||||
if (pChannels != NULL) {
|
||||
*pChannels = 0;
|
||||
}
|
||||
if (pSampleRate != NULL) {
|
||||
*pSampleRate = 0;
|
||||
}
|
||||
if (pChannelMap != NULL) {
|
||||
MA_ZERO_MEMORY(pChannelMap, sizeof(*pChannelMap) * channelMapCap);
|
||||
}
|
||||
|
||||
if (!pRadv2) {
|
||||
return MA_INVALID_OPERATION;
|
||||
}
|
||||
|
||||
if (pFormat != NULL) {
|
||||
*pFormat = pRadv2->format;
|
||||
}
|
||||
|
||||
if (pChannels != NULL) {
|
||||
*pChannels = 2; // Stereo
|
||||
}
|
||||
|
||||
if (pSampleRate != NULL) {
|
||||
*pSampleRate = MA_DEFAULT_SAMPLE_RATE;
|
||||
}
|
||||
|
||||
if (pChannelMap != NULL) {
|
||||
ma_channel_map_init_standard(ma_standard_channel_map_default, pChannelMap, channelMapCap, 2);
|
||||
}
|
||||
|
||||
return MA_SUCCESS;
|
||||
}
|
||||
|
||||
static ma_result ma_radv2_read_pcm_frames(ma_radv2 *pRadv2, void *pFramesOut, ma_uint64 frameCount, ma_uint64 *pFramesRead) {
|
||||
if (pFramesRead != NULL) {
|
||||
*pFramesRead = 0;
|
||||
}
|
||||
|
||||
if (frameCount == 0) {
|
||||
return MA_INVALID_ARGS;
|
||||
}
|
||||
|
||||
if (!pRadv2) {
|
||||
return MA_INVALID_ARGS;
|
||||
}
|
||||
|
||||
ma_result result = MA_SUCCESS; /* Must be initialized to MA_SUCCESS. */
|
||||
ma_uint64 totalFramesRead = 0;
|
||||
ma_int16 *buffer = (ma_int16 *)pFramesOut;
|
||||
bool repeat = false;
|
||||
|
||||
while (totalFramesRead < frameCount) {
|
||||
pRadv2->adlib->Sample(&buffer[0], &buffer[1]); // Get the left and right sample
|
||||
buffer += 2; // Increment the buffer pointer twice for 2 channels
|
||||
++totalFramesRead; // Increment the frame counter
|
||||
|
||||
// Time to update player?
|
||||
pRadv2->sampleCount++;
|
||||
if (pRadv2->sampleCount >= pRadv2->sampleUpdate) {
|
||||
pRadv2->sampleCount = 0;
|
||||
repeat = pRadv2->player->Update();
|
||||
}
|
||||
|
||||
if (repeat) {
|
||||
result = MA_AT_END;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pFramesRead != NULL) {
|
||||
*pFramesRead = totalFramesRead;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static ma_result ma_radv2_get_cursor_in_pcm_frames(ma_radv2 *pRadv2, ma_uint64 *pCursor) {
|
||||
if (!pCursor) {
|
||||
return MA_INVALID_ARGS;
|
||||
}
|
||||
|
||||
*pCursor = 0; /* Safety. */
|
||||
|
||||
if (!pRadv2) {
|
||||
return MA_INVALID_ARGS;
|
||||
}
|
||||
|
||||
ma_int64 offset = (ma_int64)pRadv2->player->GetPlayTimeInSeconds() * MA_DEFAULT_SAMPLE_RATE;
|
||||
if (offset < 0) {
|
||||
return MA_INVALID_FILE;
|
||||
}
|
||||
|
||||
*pCursor = (ma_uint64)offset;
|
||||
|
||||
return MA_SUCCESS;
|
||||
}
|
||||
|
||||
static ma_result ma_radv2_get_length_in_pcm_frames(ma_radv2 *pRadv2, ma_uint64 *pLength) {
|
||||
if (!pLength) {
|
||||
return MA_INVALID_ARGS;
|
||||
}
|
||||
|
||||
*pLength = 0; /* Safety. */
|
||||
|
||||
if (!pRadv2) {
|
||||
return MA_INVALID_ARGS;
|
||||
}
|
||||
|
||||
// Total time in seconds * Opal sample rate
|
||||
ma_int64 length = (ma_int64)pRadv2->totalTime * MA_DEFAULT_SAMPLE_RATE;
|
||||
if (length < 0) {
|
||||
return MA_INVALID_FILE;
|
||||
}
|
||||
|
||||
*pLength = (ma_uint64)length;
|
||||
|
||||
return MA_SUCCESS;
|
||||
}
|
||||
|
||||
static ma_result ma_radv2_ds_read(ma_data_source *pDataSource, void *pFramesOut, ma_uint64 frameCount, ma_uint64 *pFramesRead) {
|
||||
return ma_radv2_read_pcm_frames((ma_radv2 *)pDataSource, pFramesOut, frameCount, pFramesRead);
|
||||
}
|
||||
|
||||
static ma_result ma_radv2_ds_seek(ma_data_source *pDataSource, ma_uint64 frameIndex) { return ma_radv2_seek_to_pcm_frame((ma_radv2 *)pDataSource, frameIndex); }
|
||||
|
||||
static ma_result ma_radv2_ds_get_data_format(ma_data_source *pDataSource, ma_format *pFormat, ma_uint32 *pChannels, ma_uint32 *pSampleRate,
|
||||
ma_channel *pChannelMap, size_t channelMapCap) {
|
||||
return ma_radv2_get_data_format((ma_radv2 *)pDataSource, pFormat, pChannels, pSampleRate, pChannelMap, channelMapCap);
|
||||
}
|
||||
|
||||
static ma_result ma_radv2_ds_get_cursor(ma_data_source *pDataSource, ma_uint64 *pCursor) {
|
||||
return ma_radv2_get_cursor_in_pcm_frames((ma_radv2 *)pDataSource, pCursor);
|
||||
}
|
||||
|
||||
static ma_result ma_radv2_ds_get_length(ma_data_source *pDataSource, ma_uint64 *pLength) {
|
||||
return ma_radv2_get_length_in_pcm_frames((ma_radv2 *)pDataSource, pLength);
|
||||
}
|
||||
|
||||
static ma_data_source_vtable ma_data_source_vtable_radv2 = {ma_radv2_ds_read, ma_radv2_ds_seek, ma_radv2_ds_get_data_format, ma_radv2_ds_get_cursor,
|
||||
ma_radv2_ds_get_length};
|
||||
|
||||
static int ma_radv2_of_callback__read(void *pUserData, unsigned char *pBufferOut, int bytesToRead) {
|
||||
ma_radv2 *pRadv2 = (ma_radv2 *)pUserData;
|
||||
ma_result result;
|
||||
size_t bytesRead;
|
||||
|
||||
result = pRadv2->onRead(pRadv2->pReadSeekTellUserData, (void *)pBufferOut, bytesToRead, &bytesRead);
|
||||
|
||||
if (result != MA_SUCCESS) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return (int)bytesRead;
|
||||
}
|
||||
|
||||
static int ma_radv2_of_callback__seek(void *pUserData, ma_int64 offset, int whence) {
|
||||
ma_radv2 *pRadv2 = (ma_radv2 *)pUserData;
|
||||
ma_result result;
|
||||
ma_seek_origin origin;
|
||||
|
||||
if (whence == SEEK_SET) {
|
||||
origin = ma_seek_origin_start;
|
||||
} else if (whence == SEEK_END) {
|
||||
origin = ma_seek_origin_end;
|
||||
} else {
|
||||
origin = ma_seek_origin_current;
|
||||
}
|
||||
|
||||
result = pRadv2->onSeek(pRadv2->pReadSeekTellUserData, offset, origin);
|
||||
if (result != MA_SUCCESS) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ma_int64 ma_radv2_of_callback__tell(void *pUserData) {
|
||||
ma_radv2 *pRadv2 = (ma_radv2 *)pUserData;
|
||||
ma_result result;
|
||||
ma_int64 cursor;
|
||||
|
||||
if (pRadv2->onTell == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
result = pRadv2->onTell(pRadv2->pReadSeekTellUserData, &cursor);
|
||||
if (result != MA_SUCCESS) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return cursor;
|
||||
}
|
||||
|
||||
static ma_result ma_radv2_init_internal(const ma_decoding_backend_config *pConfig, ma_radv2 *pRadv2) {
|
||||
ma_result result;
|
||||
ma_data_source_config dataSourceConfig;
|
||||
|
||||
if (!pRadv2) {
|
||||
return MA_INVALID_ARGS;
|
||||
}
|
||||
|
||||
MA_ZERO_OBJECT(pRadv2);
|
||||
pRadv2->format = ma_format::ma_format_s16; // RADv2 Opal outputs 16-bit signed samples by default
|
||||
|
||||
if (pConfig != NULL && pConfig->preferredFormat == ma_format::ma_format_s16) {
|
||||
pRadv2->format = pConfig->preferredFormat;
|
||||
} else {
|
||||
/* Getting here means something other than s16 was specified. Just leave this unset to use the default format. */
|
||||
}
|
||||
|
||||
dataSourceConfig = ma_data_source_config_init();
|
||||
dataSourceConfig.vtable = &ma_data_source_vtable_radv2;
|
||||
|
||||
result = ma_data_source_init(&dataSourceConfig, &pRadv2->ds);
|
||||
if (result != MA_SUCCESS) {
|
||||
return result; /* Failed to initialize the base data source. */
|
||||
}
|
||||
|
||||
return MA_SUCCESS;
|
||||
}
|
||||
|
||||
static ma_result ma_radv2_init(ma_read_proc onRead, ma_seek_proc onSeek, ma_tell_proc onTell, void *pReadSeekTellUserData,
|
||||
const ma_decoding_backend_config *pConfig, const ma_allocation_callbacks *pAllocationCallbacks, ma_radv2 *pRadv2) {
|
||||
ma_result result;
|
||||
|
||||
(void)pAllocationCallbacks; /* Can't seem to find a way to configure memory allocations in libopus. */
|
||||
|
||||
result = ma_radv2_init_internal(pConfig, pRadv2);
|
||||
if (result != MA_SUCCESS) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if (onRead == NULL || onSeek == NULL) {
|
||||
return MA_INVALID_ARGS; /* onRead and onSeek are mandatory. */
|
||||
}
|
||||
|
||||
pRadv2->onRead = onRead;
|
||||
pRadv2->onSeek = onSeek;
|
||||
pRadv2->onTell = onTell;
|
||||
pRadv2->pReadSeekTellUserData = pReadSeekTellUserData;
|
||||
|
||||
// Find the size of the file
|
||||
if (ma_radv2_of_callback__seek(pRadv2, 0, SEEK_END) != 0) {
|
||||
return MA_BAD_SEEK;
|
||||
}
|
||||
|
||||
// Calculate the length
|
||||
ma_int64 file_size = ma_radv2_of_callback__tell(pRadv2);
|
||||
if (file_size < 1) {
|
||||
return MA_INVALID_FILE;
|
||||
}
|
||||
|
||||
// See to the beginning of the file
|
||||
if (ma_radv2_of_callback__seek(pRadv2, 0, SEEK_SET) != 0) {
|
||||
return MA_BAD_SEEK;
|
||||
}
|
||||
|
||||
// Allocate some memory for the tune
|
||||
pRadv2->tune = new uint8_t[file_size];
|
||||
if (!pRadv2->tune) {
|
||||
return MA_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
// Read the file
|
||||
if (ma_radv2_of_callback__read(pRadv2, pRadv2->tune, (int)file_size) < 1) {
|
||||
delete[] pRadv2->tune;
|
||||
pRadv2->tune = nullptr;
|
||||
return MA_IO_ERROR;
|
||||
}
|
||||
|
||||
// Create the RADv2 Player objects
|
||||
pRadv2->player = new RADPlayer();
|
||||
if (!pRadv2->player) {
|
||||
delete[] pRadv2->tune;
|
||||
pRadv2->tune = nullptr;
|
||||
return MA_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
// Create the RADv2 Opal object
|
||||
pRadv2->adlib = new Opal(MA_DEFAULT_SAMPLE_RATE);
|
||||
if (!pRadv2->adlib) {
|
||||
delete pRadv2->player;
|
||||
pRadv2->player = nullptr;
|
||||
delete[] pRadv2->tune;
|
||||
pRadv2->tune = nullptr;
|
||||
return MA_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
// Check if the file is valid
|
||||
if (RADValidate(pRadv2->tune, file_size)) {
|
||||
delete pRadv2->adlib;
|
||||
pRadv2->adlib = nullptr;
|
||||
delete pRadv2->player;
|
||||
pRadv2->player = nullptr;
|
||||
delete[] pRadv2->tune;
|
||||
pRadv2->tune = nullptr;
|
||||
return MA_INVALID_FILE;
|
||||
}
|
||||
|
||||
// Initialize the player
|
||||
// We'll use a lambda here and pass the pRadv2 pointer using 'arg'
|
||||
pRadv2->player->Init(
|
||||
pRadv2->tune, [](void *arg, uint16_t reg, uint8_t data) { ((ma_radv2 *)arg)->adlib->Port(reg, data); }, pRadv2);
|
||||
|
||||
// Get the playback rate
|
||||
if (pRadv2->player->GetHertz() < 0) {
|
||||
delete pRadv2->adlib;
|
||||
pRadv2->adlib = nullptr;
|
||||
delete pRadv2->player;
|
||||
pRadv2->player = nullptr;
|
||||
delete[] pRadv2->tune;
|
||||
pRadv2->tune = nullptr;
|
||||
return MA_INVALID_FILE;
|
||||
}
|
||||
|
||||
// Get the total playback time
|
||||
pRadv2->totalTime = pRadv2->player->ComputeTotalTime();
|
||||
// Setup some stuff
|
||||
pRadv2->sampleCount = 0;
|
||||
pRadv2->sampleUpdate = MA_DEFAULT_SAMPLE_RATE / pRadv2->player->GetHertz();
|
||||
|
||||
return MA_SUCCESS;
|
||||
}
|
||||
|
||||
static ma_result ma_radv2_init_file(const char *pFilePath, const ma_decoding_backend_config *pConfig, const ma_allocation_callbacks *pAllocationCallbacks,
|
||||
ma_radv2 *pRadv2) {
|
||||
ma_result result;
|
||||
|
||||
(void)pAllocationCallbacks; /* Can't seem to find a way to configure memory allocations in libopus. */
|
||||
|
||||
result = ma_radv2_init_internal(pConfig, pRadv2);
|
||||
if (result != MA_SUCCESS) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// Check the file extension
|
||||
if (!ma_path_extension_equal(pFilePath, "rad")) {
|
||||
return MA_INVALID_FILE;
|
||||
}
|
||||
|
||||
// Open the file for reading
|
||||
FILE *fd = fopen(pFilePath, "rb");
|
||||
if (!fd) {
|
||||
return MA_INVALID_FILE;
|
||||
}
|
||||
|
||||
// Find the size of the file
|
||||
if (fseek(fd, 0, SEEK_END) != 0) {
|
||||
fclose(fd);
|
||||
return MA_BAD_SEEK;
|
||||
}
|
||||
|
||||
// Calculate the length
|
||||
ma_int64 file_size = ftell(fd);
|
||||
if (file_size < 1) {
|
||||
fclose(fd);
|
||||
return MA_INVALID_FILE;
|
||||
}
|
||||
|
||||
// Seek to the beginning of the file
|
||||
if (fseek(fd, 0, SEEK_SET) != 0) {
|
||||
fclose(fd);
|
||||
return MA_BAD_SEEK;
|
||||
}
|
||||
|
||||
// Allocate some memory for the tune
|
||||
pRadv2->tune = new uint8_t[file_size];
|
||||
if (!pRadv2->tune) {
|
||||
fclose(fd);
|
||||
return MA_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
// Read the file
|
||||
if (fread(pRadv2->tune, file_size, sizeof(uint8_t), fd) < 1) {
|
||||
delete[] pRadv2->tune;
|
||||
pRadv2->tune = nullptr;
|
||||
fclose(fd);
|
||||
return MA_IO_ERROR;
|
||||
}
|
||||
|
||||
// Close the file now that we've read it into memory
|
||||
fclose(fd);
|
||||
|
||||
// Create the RADv2 Player objects
|
||||
pRadv2->player = new RADPlayer();
|
||||
if (!pRadv2->player) {
|
||||
delete[] pRadv2->tune;
|
||||
pRadv2->tune = nullptr;
|
||||
return MA_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
// Create the RADv2 Opal object
|
||||
pRadv2->adlib = new Opal(MA_DEFAULT_SAMPLE_RATE);
|
||||
if (!pRadv2->adlib) {
|
||||
delete pRadv2->player;
|
||||
pRadv2->player = nullptr;
|
||||
delete[] pRadv2->tune;
|
||||
pRadv2->tune = nullptr;
|
||||
return MA_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
// Check if the file is valid
|
||||
if (RADValidate(pRadv2->tune, file_size)) {
|
||||
delete pRadv2->adlib;
|
||||
pRadv2->adlib = nullptr;
|
||||
delete pRadv2->player;
|
||||
pRadv2->player = nullptr;
|
||||
delete[] pRadv2->tune;
|
||||
pRadv2->tune = nullptr;
|
||||
return MA_INVALID_FILE;
|
||||
}
|
||||
|
||||
// Initialize the player
|
||||
// We'll use a lambda here and pass the pRadv2 pointer using 'arg'
|
||||
pRadv2->player->Init(
|
||||
pRadv2->tune, [](void *arg, uint16_t reg, uint8_t data) { ((ma_radv2 *)arg)->adlib->Port(reg, data); }, pRadv2);
|
||||
|
||||
// Get the playback rate
|
||||
if (pRadv2->player->GetHertz() < 0) {
|
||||
delete pRadv2->adlib;
|
||||
pRadv2->adlib = nullptr;
|
||||
delete pRadv2->player;
|
||||
pRadv2->player = nullptr;
|
||||
delete[] pRadv2->tune;
|
||||
pRadv2->tune = nullptr;
|
||||
return MA_INVALID_FILE;
|
||||
}
|
||||
|
||||
// Get the total playback time
|
||||
pRadv2->totalTime = pRadv2->player->ComputeTotalTime();
|
||||
// Setup some stuff
|
||||
pRadv2->sampleCount = 0;
|
||||
pRadv2->sampleUpdate = MA_DEFAULT_SAMPLE_RATE / pRadv2->player->GetHertz();
|
||||
|
||||
return MA_SUCCESS;
|
||||
}
|
||||
|
||||
static void ma_radv2_uninit(ma_radv2 *pRadv2, const ma_allocation_callbacks *pAllocationCallbacks) {
|
||||
if (!pRadv2) {
|
||||
return;
|
||||
}
|
||||
|
||||
(void)pAllocationCallbacks;
|
||||
|
||||
// Stop any ongoing playback
|
||||
pRadv2->player->Stop();
|
||||
|
||||
delete pRadv2->adlib;
|
||||
pRadv2->adlib = nullptr;
|
||||
delete pRadv2->player;
|
||||
pRadv2->player = nullptr;
|
||||
delete[] pRadv2->tune;
|
||||
pRadv2->tune = nullptr;
|
||||
|
||||
ma_data_source_uninit(&pRadv2->ds);
|
||||
}
|
||||
|
||||
static ma_result ma_decoding_backend_init__radv2(void *pUserData, ma_read_proc onRead, ma_seek_proc onSeek, ma_tell_proc onTell, void *pReadSeekTellUserData,
|
||||
const ma_decoding_backend_config *pConfig, const ma_allocation_callbacks *pAllocationCallbacks,
|
||||
ma_data_source **ppBackend) {
|
||||
ma_result result;
|
||||
ma_radv2 *pRadv2;
|
||||
|
||||
(void)pUserData;
|
||||
|
||||
pRadv2 = (ma_radv2 *)ma_malloc(sizeof(ma_radv2), pAllocationCallbacks);
|
||||
if (!pRadv2) {
|
||||
return MA_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
result = ma_radv2_init(onRead, onSeek, onTell, pReadSeekTellUserData, pConfig, pAllocationCallbacks, pRadv2);
|
||||
if (result != MA_SUCCESS) {
|
||||
ma_free(pRadv2, pAllocationCallbacks);
|
||||
return result;
|
||||
}
|
||||
|
||||
*ppBackend = pRadv2;
|
||||
|
||||
return MA_SUCCESS;
|
||||
}
|
||||
|
||||
static ma_result ma_decoding_backend_init_file__radv2(void *pUserData, const char *pFilePath, const ma_decoding_backend_config *pConfig,
|
||||
const ma_allocation_callbacks *pAllocationCallbacks, ma_data_source **ppBackend) {
|
||||
ma_result result;
|
||||
ma_radv2 *pRadv2;
|
||||
|
||||
(void)pUserData;
|
||||
|
||||
pRadv2 = (ma_radv2 *)ma_malloc(sizeof(ma_radv2), pAllocationCallbacks);
|
||||
if (!pRadv2) {
|
||||
return MA_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
result = ma_radv2_init_file(pFilePath, pConfig, pAllocationCallbacks, pRadv2);
|
||||
if (result != MA_SUCCESS) {
|
||||
ma_free(pRadv2, pAllocationCallbacks);
|
||||
return result;
|
||||
}
|
||||
|
||||
*ppBackend = pRadv2;
|
||||
|
||||
return MA_SUCCESS;
|
||||
}
|
||||
|
||||
static void ma_decoding_backend_uninit__radv2(void *pUserData, ma_data_source *pBackend, const ma_allocation_callbacks *pAllocationCallbacks) {
|
||||
ma_radv2 *pRadv2 = (ma_radv2 *)pBackend;
|
||||
|
||||
(void)pUserData;
|
||||
|
||||
ma_radv2_uninit(pRadv2, pAllocationCallbacks);
|
||||
ma_free(pRadv2, pAllocationCallbacks);
|
||||
}
|
||||
|
||||
static ma_decoding_backend_vtable ma_decoding_backend_vtable_radv2 = {ma_decoding_backend_init__radv2, ma_decoding_backend_init_file__radv2,
|
||||
NULL, /* onInitFileW() */
|
||||
NULL, /* onInitMemory() */
|
||||
ma_decoding_backend_uninit__radv2};
|
||||
//-----------------------------------------------------------------------------------------------------
|
543
internal/c/parts/audio/extras/miniaudio_tinysoundfont.h
Normal file
543
internal/c/parts/audio/extras/miniaudio_tinysoundfont.h
Normal file
|
@ -0,0 +1,543 @@
|
|||
//----------------------------------------------------------------------------------------------------
|
||||
// ___ ___ __ _ _ ___ ___ _ _ _ ___ _
|
||||
// / _ \| _ ) / /| | || _ \ __| /_\ _ _ __| (_)___ | __|_ _ __ _(_)_ _ ___
|
||||
// | (_) | _ \/ _ \_ _| _/ _| / _ \ || / _` | / _ \ | _|| ' \/ _` | | ' \/ -_)
|
||||
// \__\_\___/\___/ |_||_| |___| /_/ \_\_,_\__,_|_\___/ |___|_||_\__, |_|_||_\___|
|
||||
// |___/
|
||||
//
|
||||
// QB64-PE Audio Engine powered by miniaudio (https://miniaud.io/)
|
||||
//
|
||||
// This implements a data source that decodes MIDI files using TinySoundFont + TinyMidiLoader
|
||||
// https://github.com/schellingb/TinySoundFont (MIT)
|
||||
//
|
||||
// Soundfont (awe32rom.h) from dos-like
|
||||
// https://github.com/mattiasgustavsson/dos-like (MIT)
|
||||
//
|
||||
// Copyright (c) 2022 Samuel Gomes
|
||||
// https://github.com/a740g
|
||||
//
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
// HEADER FILES
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
#include "../miniaudio.h"
|
||||
#include "tinysoundfont/awe32rom.h"
|
||||
#define TSF_IMPLEMENTATION
|
||||
#include "tinysoundfont/tsf.h"
|
||||
#define TML_IMPLEMENTATION
|
||||
#include "tinysoundfont/tml.h"
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
// CONSTANTS
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
#define TSF_DEFAULT_SOUNDFONT_FILENAME "soundfont.sf2"
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
|
||||
struct ma_tsf {
|
||||
// This part is for miniaudio
|
||||
ma_data_source_base ds; /* The decoder can be used independently as a data source. */
|
||||
ma_read_proc onRead;
|
||||
ma_seek_proc onSeek;
|
||||
ma_tell_proc onTell;
|
||||
void *pReadSeekTellUserData;
|
||||
ma_format format;
|
||||
|
||||
// This part is format specific
|
||||
tsf *tinySoundFont; // TinySoundFont context
|
||||
tml_message *tinyMidiLoader; // TinyMidiLoader context
|
||||
ma_uint32 totalTime; // Total duration of the MIDI song in msec
|
||||
double currentTime; // Current song playback time in msec
|
||||
tml_message *midiMessage; // Next message to be played (this is set to NULL once the song is over)
|
||||
};
|
||||
|
||||
static ma_result ma_tsf_seek_to_pcm_frame(ma_tsf *pTsf, ma_uint64 frameIndex) {
|
||||
if (pTsf == NULL) {
|
||||
return MA_INVALID_ARGS;
|
||||
}
|
||||
|
||||
// We can only reset the player to the beginning
|
||||
if (frameIndex == 0) {
|
||||
tsf_reset(pTsf->tinySoundFont); // Stop playing whatever is playing
|
||||
pTsf->midiMessage = pTsf->tinyMidiLoader; // Set up the global MidiMessage pointer to the first MIDI message
|
||||
pTsf->currentTime = 0; // Reset playback time
|
||||
return MA_SUCCESS;
|
||||
}
|
||||
|
||||
return MA_INVALID_OPERATION; // Anything else is not seekable
|
||||
}
|
||||
|
||||
static ma_result ma_tsf_get_data_format(ma_tsf *pTsf, ma_format *pFormat, ma_uint32 *pChannels, ma_uint32 *pSampleRate, ma_channel *pChannelMap,
|
||||
size_t channelMapCap) {
|
||||
/* Defaults for safety. */
|
||||
if (pFormat != NULL) {
|
||||
*pFormat = ma_format_unknown;
|
||||
}
|
||||
if (pChannels != NULL) {
|
||||
*pChannels = 0;
|
||||
}
|
||||
if (pSampleRate != NULL) {
|
||||
*pSampleRate = 0;
|
||||
}
|
||||
if (pChannelMap != NULL) {
|
||||
MA_ZERO_MEMORY(pChannelMap, sizeof(*pChannelMap) * channelMapCap);
|
||||
}
|
||||
|
||||
if (pTsf == NULL) {
|
||||
return MA_INVALID_OPERATION;
|
||||
}
|
||||
|
||||
if (pFormat != NULL) {
|
||||
*pFormat = pTsf->format;
|
||||
}
|
||||
|
||||
if (pChannels != NULL) {
|
||||
*pChannels = 2; // Stereo
|
||||
}
|
||||
|
||||
if (pSampleRate != NULL) {
|
||||
*pSampleRate = MA_DEFAULT_SAMPLE_RATE;
|
||||
}
|
||||
|
||||
if (pChannelMap != NULL) {
|
||||
ma_channel_map_init_standard(ma_standard_channel_map_default, pChannelMap, channelMapCap, 2);
|
||||
}
|
||||
|
||||
return MA_SUCCESS;
|
||||
}
|
||||
|
||||
static ma_result ma_tsf_read_pcm_frames(ma_tsf *pTsf, void *pFramesOut, ma_uint64 frameCount, ma_uint64 *pFramesRead) {
|
||||
if (pFramesRead != NULL) {
|
||||
*pFramesRead = 0;
|
||||
}
|
||||
|
||||
if (frameCount == 0) {
|
||||
return MA_INVALID_ARGS;
|
||||
}
|
||||
|
||||
if (pTsf == NULL) {
|
||||
return MA_INVALID_ARGS;
|
||||
}
|
||||
|
||||
ma_result result = MA_SUCCESS; // Must be initialized to MA_SUCCESS
|
||||
ma_uint64 totalFramesRead = 0;
|
||||
ma_uint8 *buffer = (ma_uint8 *)pFramesOut;
|
||||
ma_int64 SampleBlock, SampleCount = frameCount; // Number of sample frames to process
|
||||
|
||||
for (SampleBlock = TSF_RENDER_EFFECTSAMPLEBLOCK; SampleCount; SampleCount -= SampleBlock, buffer += (SampleBlock * (sizeof(short) * 2))) {
|
||||
// We progress the MIDI playback and then process TSF_RENDER_EFFECTSAMPLEBLOCK samples at once
|
||||
if (SampleBlock > SampleCount)
|
||||
SampleBlock = SampleCount;
|
||||
|
||||
// Loop through all MIDI messages which need to be played up until the current playback time
|
||||
for (pTsf->currentTime += SampleBlock * (1000.0 / MA_DEFAULT_SAMPLE_RATE); pTsf->midiMessage && pTsf->currentTime >= pTsf->midiMessage->time;
|
||||
pTsf->midiMessage = pTsf->midiMessage->next) {
|
||||
switch (pTsf->midiMessage->type) {
|
||||
case TML_PROGRAM_CHANGE: // Channel program (preset) change (special handling for 10th MIDI channel with drums)
|
||||
tsf_channel_set_presetnumber(pTsf->tinySoundFont, pTsf->midiMessage->channel, pTsf->midiMessage->program, (pTsf->midiMessage->channel == 9));
|
||||
tsf_channel_midi_control(pTsf->tinySoundFont, pTsf->midiMessage->channel, TML_ALL_NOTES_OFF,
|
||||
0); // https://github.com/schellingb/TinySoundFont/issues/59
|
||||
break;
|
||||
case TML_NOTE_ON: // Play a note
|
||||
tsf_channel_note_on(pTsf->tinySoundFont, pTsf->midiMessage->channel, pTsf->midiMessage->key, pTsf->midiMessage->velocity / 127.0f);
|
||||
break;
|
||||
case TML_NOTE_OFF: // Stop a note
|
||||
tsf_channel_note_off(pTsf->tinySoundFont, pTsf->midiMessage->channel, pTsf->midiMessage->key);
|
||||
break;
|
||||
case TML_PITCH_BEND: // Pitch wheel modification
|
||||
tsf_channel_set_pitchwheel(pTsf->tinySoundFont, pTsf->midiMessage->channel, pTsf->midiMessage->pitch_bend);
|
||||
break;
|
||||
case TML_CONTROL_CHANGE: // MIDI controller messages
|
||||
tsf_channel_midi_control(pTsf->tinySoundFont, pTsf->midiMessage->channel, pTsf->midiMessage->control, pTsf->midiMessage->control_value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Render the block of audio samples in int16 format
|
||||
tsf_render_short(pTsf->tinySoundFont, (short *)buffer, (int)SampleBlock);
|
||||
totalFramesRead += SampleBlock;
|
||||
|
||||
// Signal end of stream if we have reached the end
|
||||
if (pTsf->midiMessage == NULL) {
|
||||
result = MA_AT_END;
|
||||
// However, also reset the position to the beginning just in case we want to loop
|
||||
pTsf->midiMessage = pTsf->tinyMidiLoader; // Set up the global MidiMessage pointer to the first MIDI message
|
||||
pTsf->currentTime = 0; // Reset playback time
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pFramesRead != NULL) {
|
||||
*pFramesRead = totalFramesRead;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static ma_result ma_tsf_get_cursor_in_pcm_frames(ma_tsf *pTsf, ma_uint64 *pCursor) {
|
||||
if (pCursor == NULL) {
|
||||
return MA_INVALID_ARGS;
|
||||
}
|
||||
|
||||
*pCursor = 0; /* Safety. */
|
||||
|
||||
if (pTsf == NULL) {
|
||||
return MA_INVALID_ARGS;
|
||||
}
|
||||
|
||||
ma_int64 offset = ((ma_int64)pTsf->currentTime * MA_DEFAULT_SAMPLE_RATE) / 1000;
|
||||
if (offset < 0) {
|
||||
return MA_INVALID_FILE;
|
||||
}
|
||||
|
||||
*pCursor = (ma_uint64)offset;
|
||||
|
||||
return MA_SUCCESS;
|
||||
}
|
||||
|
||||
static ma_result ma_tsf_get_length_in_pcm_frames(ma_tsf *pTsf, ma_uint64 *pLength) {
|
||||
if (pLength == NULL) {
|
||||
return MA_INVALID_ARGS;
|
||||
}
|
||||
|
||||
*pLength = 0; /* Safety. */
|
||||
|
||||
if (pTsf == NULL) {
|
||||
return MA_INVALID_ARGS;
|
||||
}
|
||||
|
||||
// Total time in seconds * Opal sample rate
|
||||
ma_int64 length = ((ma_int64)pTsf->totalTime * MA_DEFAULT_SAMPLE_RATE) / 1000;
|
||||
if (length < 0) {
|
||||
return MA_INVALID_FILE;
|
||||
}
|
||||
|
||||
*pLength = (ma_uint64)length;
|
||||
|
||||
return MA_SUCCESS;
|
||||
}
|
||||
|
||||
static ma_result ma_tsf_ds_read(ma_data_source *pDataSource, void *pFramesOut, ma_uint64 frameCount, ma_uint64 *pFramesRead) {
|
||||
return ma_tsf_read_pcm_frames((ma_tsf *)pDataSource, pFramesOut, frameCount, pFramesRead);
|
||||
}
|
||||
|
||||
static ma_result ma_tsf_ds_seek(ma_data_source *pDataSource, ma_uint64 frameIndex) { return ma_tsf_seek_to_pcm_frame((ma_tsf *)pDataSource, frameIndex); }
|
||||
|
||||
static ma_result ma_tsf_ds_get_data_format(ma_data_source *pDataSource, ma_format *pFormat, ma_uint32 *pChannels, ma_uint32 *pSampleRate,
|
||||
ma_channel *pChannelMap, size_t channelMapCap) {
|
||||
return ma_tsf_get_data_format((ma_tsf *)pDataSource, pFormat, pChannels, pSampleRate, pChannelMap, channelMapCap);
|
||||
}
|
||||
|
||||
static ma_result ma_tsf_ds_get_cursor(ma_data_source *pDataSource, ma_uint64 *pCursor) {
|
||||
return ma_tsf_get_cursor_in_pcm_frames((ma_tsf *)pDataSource, pCursor);
|
||||
}
|
||||
|
||||
static ma_result ma_tsf_ds_get_length(ma_data_source *pDataSource, ma_uint64 *pLength) {
|
||||
return ma_tsf_get_length_in_pcm_frames((ma_tsf *)pDataSource, pLength);
|
||||
}
|
||||
|
||||
static ma_data_source_vtable ma_data_source_vtable_tsf = {ma_tsf_ds_read, ma_tsf_ds_seek, ma_tsf_ds_get_data_format, ma_tsf_ds_get_cursor,
|
||||
ma_tsf_ds_get_length};
|
||||
|
||||
static int ma_tsf_of_callback__read(void *pUserData, unsigned char *pBufferOut, int bytesToRead) {
|
||||
ma_tsf *pTsf = (ma_tsf *)pUserData;
|
||||
ma_result result;
|
||||
size_t bytesRead;
|
||||
|
||||
result = pTsf->onRead(pTsf->pReadSeekTellUserData, (void *)pBufferOut, bytesToRead, &bytesRead);
|
||||
|
||||
if (result != MA_SUCCESS) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return (int)bytesRead;
|
||||
}
|
||||
|
||||
static int ma_tsf_of_callback__seek(void *pUserData, ma_int64 offset, int whence) {
|
||||
ma_tsf *pTsf = (ma_tsf *)pUserData;
|
||||
ma_result result;
|
||||
ma_seek_origin origin;
|
||||
|
||||
if (whence == SEEK_SET) {
|
||||
origin = ma_seek_origin_start;
|
||||
} else if (whence == SEEK_END) {
|
||||
origin = ma_seek_origin_end;
|
||||
} else {
|
||||
origin = ma_seek_origin_current;
|
||||
}
|
||||
|
||||
result = pTsf->onSeek(pTsf->pReadSeekTellUserData, offset, origin);
|
||||
if (result != MA_SUCCESS) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ma_int64 ma_tsf_of_callback__tell(void *pUserData) {
|
||||
ma_tsf *pTsf = (ma_tsf *)pUserData;
|
||||
ma_result result;
|
||||
ma_int64 cursor;
|
||||
|
||||
if (pTsf->onTell == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
result = pTsf->onTell(pTsf->pReadSeekTellUserData, &cursor);
|
||||
if (result != MA_SUCCESS) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return cursor;
|
||||
}
|
||||
|
||||
static ma_result ma_tsf_init_internal(const ma_decoding_backend_config *pConfig, ma_tsf *pTsf) {
|
||||
ma_result result;
|
||||
ma_data_source_config dataSourceConfig;
|
||||
|
||||
if (pTsf == NULL) {
|
||||
return MA_INVALID_ARGS;
|
||||
}
|
||||
|
||||
MA_ZERO_OBJECT(pTsf);
|
||||
pTsf->format = ma_format::ma_format_s16; // We'll render 16-bit signed samples by default
|
||||
|
||||
if (pConfig != NULL && pConfig->preferredFormat == ma_format::ma_format_s16) {
|
||||
pTsf->format = pConfig->preferredFormat;
|
||||
} else {
|
||||
/* Getting here means something other than s16 was specified. Just leave this unset to use the default format. */
|
||||
}
|
||||
|
||||
dataSourceConfig = ma_data_source_config_init();
|
||||
dataSourceConfig.vtable = &ma_data_source_vtable_tsf;
|
||||
|
||||
result = ma_data_source_init(&dataSourceConfig, &pTsf->ds);
|
||||
if (result != MA_SUCCESS) {
|
||||
return result; /* Failed to initialize the base data source. */
|
||||
}
|
||||
|
||||
return MA_SUCCESS;
|
||||
}
|
||||
|
||||
static ma_result ma_tsf_init(ma_read_proc onRead, ma_seek_proc onSeek, ma_tell_proc onTell, void *pReadSeekTellUserData,
|
||||
const ma_decoding_backend_config *pConfig, const ma_allocation_callbacks *pAllocationCallbacks, ma_tsf *pTsf) {
|
||||
ma_result result;
|
||||
|
||||
(void)pAllocationCallbacks; /* Can't seem to find a way to configure memory allocations in libopus. */
|
||||
|
||||
result = ma_tsf_init_internal(pConfig, pTsf);
|
||||
if (result != MA_SUCCESS) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if (onRead == NULL || onSeek == NULL) {
|
||||
return MA_INVALID_ARGS; /* onRead and onSeek are mandatory. */
|
||||
}
|
||||
|
||||
pTsf->onRead = onRead;
|
||||
pTsf->onSeek = onSeek;
|
||||
pTsf->onTell = onTell;
|
||||
pTsf->pReadSeekTellUserData = pReadSeekTellUserData;
|
||||
|
||||
// Seek to the end of the file
|
||||
if (ma_tsf_of_callback__seek(pTsf, 0, SEEK_END) != 0) {
|
||||
return MA_BAD_SEEK;
|
||||
}
|
||||
|
||||
// Calculate the length
|
||||
ma_int64 file_size = ma_tsf_of_callback__tell(pTsf);
|
||||
if (file_size < 1) {
|
||||
return MA_INVALID_FILE;
|
||||
}
|
||||
|
||||
// See to the beginning of the file
|
||||
if (ma_tsf_of_callback__seek(pTsf, 0, SEEK_SET) != 0) {
|
||||
return MA_BAD_SEEK;
|
||||
}
|
||||
|
||||
// Allocate some memory for the tune
|
||||
ma_uint8 *tune = new ma_uint8[file_size];
|
||||
if (tune == nullptr) {
|
||||
return MA_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
// Read the file
|
||||
if (ma_tsf_of_callback__read(pTsf, tune, (int)file_size) < 1) {
|
||||
delete[] tune;
|
||||
return MA_IO_ERROR;
|
||||
}
|
||||
|
||||
// Attempt to load a SoundFont from a file
|
||||
pTsf->tinySoundFont = tsf_load_filename(TSF_DEFAULT_SOUNDFONT_FILENAME);
|
||||
|
||||
if (!pTsf->tinySoundFont) {
|
||||
// Attempt to load the soundfont from memory
|
||||
pTsf->tinySoundFont = tsf_load_memory(awe32rom, sizeof(awe32rom));
|
||||
|
||||
// Return failue if loading from memory also failed. This should not happen though
|
||||
if (!pTsf->tinySoundFont) {
|
||||
delete[] tune;
|
||||
return MA_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize preset on special 10th MIDI channel to use percussion sound bank (128) if available
|
||||
tsf_channel_set_bank_preset(pTsf->tinySoundFont, 9, 128, 0);
|
||||
|
||||
// Set the SoundFont rendering output mode
|
||||
tsf_set_output(pTsf->tinySoundFont, TSF_STEREO_INTERLEAVED, MA_DEFAULT_SAMPLE_RATE);
|
||||
|
||||
// Initialize TML
|
||||
pTsf->tinyMidiLoader = tml_load_memory(tune, (int)file_size);
|
||||
if (!pTsf->tinyMidiLoader) {
|
||||
tsf_close(pTsf->tinySoundFont);
|
||||
pTsf->tinySoundFont = TSF_NULL;
|
||||
delete[] tune;
|
||||
return MA_INVALID_FILE;
|
||||
}
|
||||
|
||||
// Free the memory now that we don't need it anymore
|
||||
delete[] tune;
|
||||
|
||||
// Get the total duration of the song ignoring the rest of the stuff
|
||||
tml_get_info(pTsf->tinyMidiLoader, NULL, NULL, NULL, NULL, &pTsf->totalTime);
|
||||
|
||||
// Setup some stuff
|
||||
pTsf->midiMessage = pTsf->tinyMidiLoader; // Set up the global MidiMessage pointer to the first MIDI message
|
||||
pTsf->currentTime = 0; // Reset playback time
|
||||
|
||||
return MA_SUCCESS;
|
||||
}
|
||||
|
||||
static ma_result ma_tsf_init_file(const char *pFilePath, const ma_decoding_backend_config *pConfig, const ma_allocation_callbacks *pAllocationCallbacks,
|
||||
ma_tsf *pTsf) {
|
||||
ma_result result;
|
||||
|
||||
(void)pAllocationCallbacks; /* Can't seem to find a way to configure memory allocations in libopus. */
|
||||
|
||||
result = ma_tsf_init_internal(pConfig, pTsf);
|
||||
if (result != MA_SUCCESS) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// Check the file extension
|
||||
if (!ma_path_extension_equal(pFilePath, "mid") && !ma_path_extension_equal(pFilePath, "midi")) {
|
||||
return MA_INVALID_FILE;
|
||||
}
|
||||
|
||||
// Attempt to load a SoundFont from a file
|
||||
pTsf->tinySoundFont = tsf_load_filename(TSF_DEFAULT_SOUNDFONT_FILENAME);
|
||||
|
||||
if (!pTsf->tinySoundFont) {
|
||||
// Attempt to load the soundfont from memory
|
||||
pTsf->tinySoundFont = tsf_load_memory(awe32rom, sizeof(awe32rom));
|
||||
|
||||
// Return failue if loading from memory also failed. This should not happen though
|
||||
if (!pTsf->tinySoundFont) {
|
||||
return MA_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize preset on special 10th MIDI channel to use percussion sound bank (128) if available
|
||||
tsf_channel_set_bank_preset(pTsf->tinySoundFont, 9, 128, 0);
|
||||
|
||||
// Set the SoundFont rendering output mode
|
||||
tsf_set_output(pTsf->tinySoundFont, TSF_STEREO_INTERLEAVED, MA_DEFAULT_SAMPLE_RATE);
|
||||
|
||||
// Initialize TML
|
||||
pTsf->tinyMidiLoader = tml_load_filename(pFilePath);
|
||||
if (!pTsf->tinyMidiLoader) {
|
||||
tsf_close(pTsf->tinySoundFont);
|
||||
pTsf->tinySoundFont = TSF_NULL;
|
||||
return MA_INVALID_FILE;
|
||||
}
|
||||
|
||||
// Get the total duration of the song ignoring the rest of the stuff
|
||||
tml_get_info(pTsf->tinyMidiLoader, NULL, NULL, NULL, NULL, &pTsf->totalTime);
|
||||
|
||||
// Setup some stuff
|
||||
pTsf->midiMessage = pTsf->tinyMidiLoader; // Set up the global MidiMessage pointer to the first MIDI message
|
||||
pTsf->currentTime = 0; // Reset playback time
|
||||
|
||||
return MA_SUCCESS;
|
||||
}
|
||||
|
||||
static void ma_tsf_uninit(ma_tsf *pTsf, const ma_allocation_callbacks *pAllocationCallbacks) {
|
||||
if (pTsf == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
(void)pAllocationCallbacks;
|
||||
|
||||
tsf_reset(pTsf->tinySoundFont); // Stop playing whatever is playing
|
||||
tml_free(pTsf->tinyMidiLoader); // Free TML resources
|
||||
pTsf->tinyMidiLoader = TML_NULL;
|
||||
tsf_close(pTsf->tinySoundFont);
|
||||
pTsf->tinySoundFont = TSF_NULL;
|
||||
|
||||
ma_data_source_uninit(&pTsf->ds);
|
||||
}
|
||||
|
||||
static ma_result ma_decoding_backend_init__tsf(void *pUserData, ma_read_proc onRead, ma_seek_proc onSeek, ma_tell_proc onTell, void *pReadSeekTellUserData,
|
||||
const ma_decoding_backend_config *pConfig, const ma_allocation_callbacks *pAllocationCallbacks,
|
||||
ma_data_source **ppBackend) {
|
||||
ma_result result;
|
||||
ma_tsf *pTsf;
|
||||
|
||||
(void)pUserData;
|
||||
|
||||
pTsf = (ma_tsf *)ma_malloc(sizeof(ma_tsf), pAllocationCallbacks);
|
||||
if (pTsf == NULL) {
|
||||
return MA_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
result = ma_tsf_init(onRead, onSeek, onTell, pReadSeekTellUserData, pConfig, pAllocationCallbacks, pTsf);
|
||||
if (result != MA_SUCCESS) {
|
||||
ma_free(pTsf, pAllocationCallbacks);
|
||||
return result;
|
||||
}
|
||||
|
||||
*ppBackend = pTsf;
|
||||
|
||||
return MA_SUCCESS;
|
||||
}
|
||||
|
||||
static ma_result ma_decoding_backend_init_file__tsf(void *pUserData, const char *pFilePath, const ma_decoding_backend_config *pConfig,
|
||||
const ma_allocation_callbacks *pAllocationCallbacks, ma_data_source **ppBackend) {
|
||||
ma_result result;
|
||||
ma_tsf *pTsf;
|
||||
|
||||
(void)pUserData;
|
||||
|
||||
pTsf = (ma_tsf *)ma_malloc(sizeof(ma_tsf), pAllocationCallbacks);
|
||||
if (pTsf == NULL) {
|
||||
return MA_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
result = ma_tsf_init_file(pFilePath, pConfig, pAllocationCallbacks, pTsf);
|
||||
if (result != MA_SUCCESS) {
|
||||
ma_free(pTsf, pAllocationCallbacks);
|
||||
return result;
|
||||
}
|
||||
|
||||
*ppBackend = pTsf;
|
||||
|
||||
return MA_SUCCESS;
|
||||
}
|
||||
|
||||
static void ma_decoding_backend_uninit__tsf(void *pUserData, ma_data_source *pBackend, const ma_allocation_callbacks *pAllocationCallbacks) {
|
||||
ma_tsf *pTsf = (ma_tsf *)pBackend;
|
||||
|
||||
(void)pUserData;
|
||||
|
||||
ma_tsf_uninit(pTsf, pAllocationCallbacks);
|
||||
ma_free(pTsf, pAllocationCallbacks);
|
||||
}
|
||||
|
||||
static ma_decoding_backend_vtable ma_decoding_backend_vtable_tsf = {ma_decoding_backend_init__tsf, ma_decoding_backend_init_file__tsf, NULL, /* onInitFileW() */
|
||||
NULL, /* onInitMemory() */
|
||||
ma_decoding_backend_uninit__tsf};
|
||||
//-----------------------------------------------------------------------------------------------------
|
1330
internal/c/parts/audio/extras/radv2/opal.cpp
Normal file
1330
internal/c/parts/audio/extras/radv2/opal.cpp
Normal file
File diff suppressed because it is too large
Load diff
1266
internal/c/parts/audio/extras/radv2/player20.cpp
Normal file
1266
internal/c/parts/audio/extras/radv2/player20.cpp
Normal file
File diff suppressed because it is too large
Load diff
298
internal/c/parts/audio/extras/radv2/validate20.cpp
Normal file
298
internal/c/parts/audio/extras/radv2/validate20.cpp
Normal file
|
@ -0,0 +1,298 @@
|
|||
/*
|
||||
|
||||
Code to check a RAD V2 tune file is valid. That is, it will check the tune
|
||||
can be played without crashing the player. It doesn't exhaustively check
|
||||
the tune except where needed to prevent a possible player crash.
|
||||
|
||||
Call RADValidate with a pointer to your tune and the size in bytes. It
|
||||
will return either NULL for all okay, or a pointer to a null-terminated
|
||||
string describing what is wrong with the data.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
|
||||
//==================================================================================================
|
||||
// The error strings are all supplied here in case you want to translate them to another language
|
||||
// (or supply your own more descriptive error messages).
|
||||
//==================================================================================================
|
||||
const char *g_RADNotATuneFile = "Not a RAD tune file.";
|
||||
const char *g_RADNotAVersion21Tune = "Not a version 2.1 file format RAD tune.";
|
||||
const char *g_RADTruncated = "Tune file has been truncated and is incomplete.";
|
||||
const char *g_RADBadFlags = "Tune file has invalid flags.";
|
||||
const char *g_RADBadBPMValue = "Tune's BPM value is out of range.";
|
||||
const char *g_RADBadInstrument = "Tune file contains a bad instrument definition.";
|
||||
const char *g_RADUnknownMIDIVersion = "Tune file contains an unknown MIDI instrument version.";
|
||||
const char *g_RADOrderListTooLarge = "Order list in tune file is an invalid size.";
|
||||
const char *g_RADBadJumpMarker = "Order list jump marker is invalid.";
|
||||
const char *g_RADBadOrderEntry = "Order list entry is invalid.";
|
||||
const char *g_RADBadPattNum = "Tune file contains a bad pattern index.";
|
||||
const char *g_RADPattTruncated = "Tune file contains a truncated pattern.";
|
||||
const char *g_RADPattExtraData = "Tune file contains a pattern with extraneous data.";
|
||||
const char *g_RADPattBadLineNum = "Tune file contains a pattern with a bad line definition.";
|
||||
const char *g_RADPattBadChanNum = "Tune file contains a pattern with a bad channel definition.";
|
||||
const char *g_RADPattBadNoteNum = "Pattern contains a bad note number.";
|
||||
const char *g_RADPattBadInstNum = "Pattern contains a bad instrument number.";
|
||||
const char *g_RADPattBadEffect = "Pattern contains a bad effect and/or parameter.";
|
||||
const char *g_RADBadRiffNum = "Tune file contains a bad riff index.";
|
||||
const char *g_RADExtraBytes = "Tune file contains extra bytes.";
|
||||
|
||||
|
||||
|
||||
//==================================================================================================
|
||||
// Validate a RAD V2 (file format 2.1) tune file. Note, this uses no C++ standard library code.
|
||||
//==================================================================================================
|
||||
static const char *RADCheckPattern(const uint8_t *&s, const uint8_t *e, bool riff) {
|
||||
|
||||
// Get pattern size
|
||||
if (s + 2 > e)
|
||||
return g_RADTruncated;
|
||||
uint16_t pattsize = s[0] | (uint16_t(s[1]) << 8);
|
||||
s += 2;
|
||||
|
||||
// Calculate end of pattern
|
||||
const uint8_t *pe = s + pattsize;
|
||||
if (pe > e)
|
||||
return g_RADTruncated;
|
||||
|
||||
uint8_t linedef, chandef;
|
||||
do {
|
||||
|
||||
// Check line of pattern
|
||||
if (s >= pe)
|
||||
return g_RADPattTruncated;
|
||||
linedef = *s++;
|
||||
uint8_t linenum = linedef & 0x7F;
|
||||
if (linenum >= 64)
|
||||
return g_RADPattBadLineNum;
|
||||
|
||||
do {
|
||||
|
||||
// Check channel of pattern
|
||||
if (s >= pe)
|
||||
return g_RADPattTruncated;
|
||||
chandef = *s++;
|
||||
uint8_t channum = chandef & 0x0F;
|
||||
if (!riff && channum >= 9)
|
||||
return g_RADPattBadChanNum;
|
||||
|
||||
// Check note
|
||||
if (chandef & 0x40) {
|
||||
if (s >= pe)
|
||||
return g_RADPattTruncated;
|
||||
uint8_t note = *s++;
|
||||
uint8_t notenum = note & 15;
|
||||
uint8_t octave = (note >> 4) & 7;
|
||||
if (notenum == 0 || notenum == 13 || notenum == 14)
|
||||
return g_RADPattBadNoteNum;
|
||||
}
|
||||
|
||||
// Check instrument. This shouldn't be supplied if bit 7 of the note byte is set,
|
||||
// but it doesn't break anything if it is so we don't check for it
|
||||
if (chandef & 0x20) {
|
||||
if (s >= pe)
|
||||
return g_RADPattTruncated;
|
||||
uint8_t inst = *s++;
|
||||
if (inst == 0 || inst >= 128)
|
||||
return g_RADPattBadInstNum;
|
||||
}
|
||||
|
||||
// Check effect. A non-existent effect could be supplied, but it'll just be
|
||||
// ignored by the player so we don't care
|
||||
if (chandef & 0x10) {
|
||||
if (s + 2 > pe)
|
||||
return g_RADPattTruncated;
|
||||
uint8_t effect = *s++;
|
||||
uint8_t param = *s++;
|
||||
if (effect > 31 || param > 99)
|
||||
return g_RADPattBadEffect;
|
||||
}
|
||||
|
||||
} while (!(chandef & 0x80));
|
||||
|
||||
} while (!(linedef & 0x80));
|
||||
|
||||
if (s != pe)
|
||||
return g_RADPattExtraData;
|
||||
|
||||
return 0;
|
||||
}
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
const char *RADValidate(const void *data, size_t data_size) {
|
||||
|
||||
const uint8_t *s = (const uint8_t *)data;
|
||||
const uint8_t *e = s + data_size;
|
||||
|
||||
// Check header
|
||||
if (data_size < 16)
|
||||
return g_RADNotATuneFile;
|
||||
|
||||
const char *hdrtxt = "RAD by REALiTY!!";
|
||||
for (int i = 0; i < 16; i++)
|
||||
if (char(*s++) != *hdrtxt++)
|
||||
return g_RADNotATuneFile;
|
||||
|
||||
// Check version
|
||||
if (s >= e || *s++ != 0x21)
|
||||
return g_RADNotAVersion21Tune;
|
||||
|
||||
// Check flags
|
||||
if (s >= e)
|
||||
return g_RADTruncated;
|
||||
|
||||
uint8_t flags = *s++;
|
||||
if (flags & 0x80)
|
||||
return g_RADBadFlags; // Bit 7 is unused
|
||||
|
||||
if (flags & 0x40) {
|
||||
if (s + 2 > e)
|
||||
return g_RADTruncated;
|
||||
uint16_t bpm = s[0] | (uint16_t(s[1]) << 8);
|
||||
s += 2;
|
||||
if (bpm < 46 || bpm > 300)
|
||||
return g_RADBadBPMValue;
|
||||
}
|
||||
|
||||
// Check description. This is actually freeform text so there's not a lot to check, just that
|
||||
// it's a null-terminated string
|
||||
do {
|
||||
if (s >= e)
|
||||
return g_RADTruncated;
|
||||
} while (*s++);
|
||||
|
||||
// Check instruments. We don't actually validate the individual instrument fields as the tune
|
||||
// file will still play with bad instrument data. We're only concerned that the tune file
|
||||
// doesn't crash the player
|
||||
uint8_t last_inst = 0;
|
||||
while (1) {
|
||||
|
||||
// Get instrument number, or 0 for end of instrument list
|
||||
if (s >= e)
|
||||
return g_RADTruncated;
|
||||
uint8_t inst = *s++;
|
||||
if (inst == 0)
|
||||
break;
|
||||
|
||||
// RAD always saves the instruments out in order
|
||||
if (inst > 127 || inst <= last_inst)
|
||||
return g_RADBadInstrument;
|
||||
last_inst = inst;
|
||||
|
||||
// Check the name
|
||||
if (s >= e)
|
||||
return g_RADTruncated;
|
||||
uint8_t namelen = *s++;
|
||||
s += namelen;
|
||||
|
||||
// Get algorithm
|
||||
if (s > e)
|
||||
return g_RADTruncated;
|
||||
uint8_t alg = *s;
|
||||
|
||||
if ((alg & 7) == 7) {
|
||||
|
||||
// MIDI instrument. We need to check the version as this can affect the following
|
||||
// data size
|
||||
if (s + 6 > e)
|
||||
return g_RADTruncated;
|
||||
if (s[2] >> 4)
|
||||
return g_RADUnknownMIDIVersion;
|
||||
s += 6;
|
||||
|
||||
} else {
|
||||
|
||||
s += 24;
|
||||
if (s > e)
|
||||
return g_RADTruncated;
|
||||
}
|
||||
|
||||
// Riff track supplied?
|
||||
if (alg & 0x80) {
|
||||
|
||||
const char *err = RADCheckPattern(s, e, false);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the order list
|
||||
if (s >= e)
|
||||
return g_RADTruncated;
|
||||
uint8_t order_size = *s++;
|
||||
const uint8_t *order_list = s;
|
||||
if (order_size > 128)
|
||||
return g_RADOrderListTooLarge;
|
||||
s += order_size;
|
||||
|
||||
for (uint8_t i = 0; i < order_size; i++) {
|
||||
uint8_t order = order_list[i];
|
||||
|
||||
if (order & 0x80) {
|
||||
|
||||
// Check jump marker
|
||||
order &= 0x7F;
|
||||
if (order >= order_size)
|
||||
return g_RADBadJumpMarker;
|
||||
} else {
|
||||
|
||||
// Check pattern number. It doesn't matter if there is no pattern with this number
|
||||
// defined later, as missing patterns are treated as empty
|
||||
if (order >= 100)
|
||||
return g_RADBadOrderEntry;
|
||||
}
|
||||
}
|
||||
|
||||
// Check the patterns
|
||||
while (1) {
|
||||
|
||||
// Get pattern number
|
||||
if (s >= e)
|
||||
return g_RADTruncated;
|
||||
uint8_t pattnum = *s++;
|
||||
|
||||
// Last pattern?
|
||||
if (pattnum == 0xFF)
|
||||
break;
|
||||
|
||||
if (pattnum >= 100)
|
||||
return g_RADBadPattNum;
|
||||
|
||||
const char *err = RADCheckPattern(s, e, false);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
// Check the riffs
|
||||
while (1) {
|
||||
|
||||
// Get riff number
|
||||
if (s >= e)
|
||||
return g_RADTruncated;
|
||||
uint8_t riffnum = *s++;
|
||||
|
||||
// Last riff?
|
||||
if (riffnum == 0xFF)
|
||||
break;
|
||||
|
||||
uint8_t riffpatt = riffnum >> 4;
|
||||
uint8_t riffchan = riffnum & 15;
|
||||
if (riffpatt > 9 || riffchan == 0 || riffchan > 9)
|
||||
return g_RADBadRiffNum;
|
||||
|
||||
const char *err = RADCheckPattern(s, e, true);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
// We should be at the end of the file now. Note, you can safely remove this check if you
|
||||
// like - extra bytes won't affect playback
|
||||
if (s != e)
|
||||
return g_RADExtraBytes;
|
||||
|
||||
// Tune file is all good
|
||||
return 0;
|
||||
}
|
5584
internal/c/parts/audio/extras/stb_vorbis.c
Normal file
5584
internal/c/parts/audio/extras/stb_vorbis.c
Normal file
File diff suppressed because it is too large
Load diff
2737
internal/c/parts/audio/extras/tinysoundfont/awe32rom.h
Normal file
2737
internal/c/parts/audio/extras/tinysoundfont/awe32rom.h
Normal file
File diff suppressed because it is too large
Load diff
531
internal/c/parts/audio/extras/tinysoundfont/tml.h
Normal file
531
internal/c/parts/audio/extras/tinysoundfont/tml.h
Normal file
|
@ -0,0 +1,531 @@
|
|||
/* TinyMidiLoader - v0.7 - Minimalistic midi parsing library - https://github.com/schellingb/TinySoundFont
|
||||
no warranty implied; use at your own risk
|
||||
Do this:
|
||||
#define TML_IMPLEMENTATION
|
||||
before you include this file in *one* C or C++ file to create the implementation.
|
||||
// i.e. it should look like this:
|
||||
#include ...
|
||||
#include ...
|
||||
#define TML_IMPLEMENTATION
|
||||
#include "tml.h"
|
||||
|
||||
[OPTIONAL] #define TML_NO_STDIO to remove stdio dependency
|
||||
[OPTIONAL] #define TML_MALLOC, TML_REALLOC, and TML_FREE to avoid stdlib.h
|
||||
[OPTIONAL] #define TML_MEMCPY to avoid string.h
|
||||
|
||||
LICENSE (ZLIB)
|
||||
|
||||
Copyright (C) 2017, 2018, 2020 Bernhard Schelling
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef TML_INCLUDE_TML_INL
|
||||
#define TML_INCLUDE_TML_INL
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Define this if you want the API functions to be static
|
||||
#ifdef TML_STATIC
|
||||
#define TMLDEF static
|
||||
#else
|
||||
#define TMLDEF extern
|
||||
#endif
|
||||
|
||||
// Channel message type
|
||||
enum TMLMessageType
|
||||
{
|
||||
TML_NOTE_OFF = 0x80, TML_NOTE_ON = 0x90, TML_KEY_PRESSURE = 0xA0, TML_CONTROL_CHANGE = 0xB0, TML_PROGRAM_CHANGE = 0xC0, TML_CHANNEL_PRESSURE = 0xD0, TML_PITCH_BEND = 0xE0, TML_SET_TEMPO = 0x51
|
||||
};
|
||||
|
||||
// Midi controller numbers
|
||||
enum TMLController
|
||||
{
|
||||
TML_BANK_SELECT_MSB, TML_MODULATIONWHEEL_MSB, TML_BREATH_MSB, TML_FOOT_MSB = 4, TML_PORTAMENTO_TIME_MSB, TML_DATA_ENTRY_MSB, TML_VOLUME_MSB,
|
||||
TML_BALANCE_MSB, TML_PAN_MSB = 10, TML_EXPRESSION_MSB, TML_EFFECTS1_MSB, TML_EFFECTS2_MSB, TML_GPC1_MSB = 16, TML_GPC2_MSB, TML_GPC3_MSB, TML_GPC4_MSB,
|
||||
TML_BANK_SELECT_LSB = 32, TML_MODULATIONWHEEL_LSB, TML_BREATH_LSB, TML_FOOT_LSB = 36, TML_PORTAMENTO_TIME_LSB, TML_DATA_ENTRY_LSB, TML_VOLUME_LSB,
|
||||
TML_BALANCE_LSB, TML_PAN_LSB = 42, TML_EXPRESSION_LSB, TML_EFFECTS1_LSB, TML_EFFECTS2_LSB, TML_GPC1_LSB = 48, TML_GPC2_LSB, TML_GPC3_LSB, TML_GPC4_LSB,
|
||||
TML_SUSTAIN_SWITCH = 64, TML_PORTAMENTO_SWITCH, TML_SOSTENUTO_SWITCH, TML_SOFT_PEDAL_SWITCH, TML_LEGATO_SWITCH, TML_HOLD2_SWITCH,
|
||||
TML_SOUND_CTRL1, TML_SOUND_CTRL2, TML_SOUND_CTRL3, TML_SOUND_CTRL4, TML_SOUND_CTRL5, TML_SOUND_CTRL6,
|
||||
TML_SOUND_CTRL7, TML_SOUND_CTRL8, TML_SOUND_CTRL9, TML_SOUND_CTRL10, TML_GPC5, TML_GPC6, TML_GPC7, TML_GPC8,
|
||||
TML_PORTAMENTO_CTRL, TML_FX_REVERB = 91, TML_FX_TREMOLO, TML_FX_CHORUS, TML_FX_CELESTE_DETUNE, TML_FX_PHASER,
|
||||
TML_DATA_ENTRY_INCR, TML_DATA_ENTRY_DECR, TML_NRPN_LSB, TML_NRPN_MSB, TML_RPN_LSB, TML_RPN_MSB,
|
||||
TML_ALL_SOUND_OFF = 120, TML_ALL_CTRL_OFF, TML_LOCAL_CONTROL, TML_ALL_NOTES_OFF, TML_OMNI_OFF, TML_OMNI_ON, TML_POLY_OFF, TML_POLY_ON
|
||||
};
|
||||
|
||||
// A single MIDI message linked to the next message in time
|
||||
typedef struct tml_message
|
||||
{
|
||||
// Time of the message in milliseconds
|
||||
unsigned int time;
|
||||
|
||||
// Type (see TMLMessageType) and channel number
|
||||
unsigned char type, channel;
|
||||
|
||||
// 2 byte of parameter data based on the type:
|
||||
// - key, velocity for TML_NOTE_ON and TML_NOTE_OFF messages
|
||||
// - key, key_pressure for TML_KEY_PRESSURE messages
|
||||
// - control, control_value for TML_CONTROL_CHANGE messages (see TMLController)
|
||||
// - program for TML_PROGRAM_CHANGE messages
|
||||
// - channel_pressure for TML_CHANNEL_PRESSURE messages
|
||||
// - pitch_bend for TML_PITCH_BEND messages
|
||||
union
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4201) //nonstandard extension used: nameless struct/union
|
||||
#elif defined(__GNUC__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wpedantic" //ISO C++ prohibits anonymous structs
|
||||
#endif
|
||||
|
||||
struct { union { char key, control, program, channel_pressure; }; union { char velocity, key_pressure, control_value; }; };
|
||||
struct { unsigned short pitch_bend; };
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning( pop )
|
||||
#elif defined(__GNUC__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
};
|
||||
|
||||
// The pointer to the next message in time following this event
|
||||
struct tml_message* next;
|
||||
} tml_message;
|
||||
|
||||
// The load functions will return a pointer to a struct tml_message.
|
||||
// Normally the linked list gets traversed by following the next pointers.
|
||||
// Make sure to keep the pointer to the first message to free the memory.
|
||||
// On error the tml_load* functions will return NULL most likely due to an
|
||||
// invalid MIDI stream (or if the file did not exist in tml_load_filename).
|
||||
|
||||
#ifndef TML_NO_STDIO
|
||||
// Directly load a MIDI file from a .mid file path
|
||||
TMLDEF tml_message* tml_load_filename(const char* filename);
|
||||
#endif
|
||||
|
||||
// Load a MIDI file from a block of memory
|
||||
TMLDEF tml_message* tml_load_memory(const void* buffer, int size);
|
||||
|
||||
// Get infos about this loaded MIDI file, returns the note count
|
||||
// NULL can be passed for any output value pointer if not needed.
|
||||
// used_channels: Will be set to how many channels play notes
|
||||
// (i.e. 1 if channel 15 is used but no other)
|
||||
// used_programs: Will be set to how many different programs are used
|
||||
// total_notes: Will be set to the total number of note on messages
|
||||
// time_first_note: Will be set to the time of the first note on message
|
||||
// time_length: Will be set to the total time in milliseconds
|
||||
TMLDEF int tml_get_info(tml_message* first_message, int* used_channels, int* used_programs, int* total_notes, unsigned int* time_first_note, unsigned int* time_length);
|
||||
|
||||
// Read the tempo (microseconds per quarter note) value from a message with the type TML_SET_TEMPO
|
||||
TMLDEF int tml_get_tempo_value(tml_message* set_tempo_message);
|
||||
|
||||
// Free all the memory of the linked message list (can also call free() manually)
|
||||
TMLDEF void tml_free(tml_message* f);
|
||||
|
||||
// Stream structure for the generic loading
|
||||
struct tml_stream
|
||||
{
|
||||
// Custom data given to the functions as the first parameter
|
||||
void* data;
|
||||
|
||||
// Function pointer will be called to read 'size' bytes into ptr (returns number of read bytes)
|
||||
int (*read)(void* data, void* ptr, unsigned int size);
|
||||
};
|
||||
|
||||
// Generic Midi loading method using the stream structure above
|
||||
TMLDEF tml_message* tml_load(struct tml_stream* stream);
|
||||
|
||||
// If this library is used together with TinySoundFont, tsf_stream (equivalent to tml_stream) can also be used
|
||||
struct tsf_stream;
|
||||
TMLDEF tml_message* tml_load_tsf_stream(struct tsf_stream* stream);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
// end header
|
||||
// ---------------------------------------------------------------------------------------------------------
|
||||
#endif //TML_INCLUDE_TML_INL
|
||||
|
||||
#ifdef TML_IMPLEMENTATION
|
||||
|
||||
#if !defined(TML_MALLOC) || !defined(TML_FREE) || !defined(TML_REALLOC)
|
||||
# include <stdlib.h>
|
||||
# define TML_MALLOC malloc
|
||||
# define TML_FREE free
|
||||
# define TML_REALLOC realloc
|
||||
#endif
|
||||
|
||||
#if !defined(TML_MEMCPY)
|
||||
# include <string.h>
|
||||
# define TML_MEMCPY memcpy
|
||||
#endif
|
||||
|
||||
#ifndef TML_NO_STDIO
|
||||
# include <stdio.h>
|
||||
#endif
|
||||
|
||||
#define TML_NULL 0
|
||||
|
||||
////crash on errors and warnings to find broken midi files while debugging
|
||||
//#define TML_ERROR(msg) *(int*)0 = 0xbad;
|
||||
//#define TML_WARN(msg) *(int*)0 = 0xf00d;
|
||||
|
||||
////print errors and warnings
|
||||
//#define TML_ERROR(msg) printf("ERROR: %s\n", msg);
|
||||
//#define TML_WARN(msg) printf("WARNING: %s\n", msg);
|
||||
|
||||
#ifndef TML_ERROR
|
||||
#define TML_ERROR(msg)
|
||||
#endif
|
||||
|
||||
#ifndef TML_WARN
|
||||
#define TML_WARN(msg)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef TML_NO_STDIO
|
||||
static int tml_stream_stdio_read(FILE* f, void* ptr, unsigned int size) { return (int)fread(ptr, 1, size, f); }
|
||||
TMLDEF tml_message* tml_load_filename(const char* filename)
|
||||
{
|
||||
struct tml_message* res;
|
||||
struct tml_stream stream = { TML_NULL, (int(*)(void*,void*,unsigned int))&tml_stream_stdio_read };
|
||||
#if __STDC_WANT_SECURE_LIB__
|
||||
FILE* f = TML_NULL; fopen_s(&f, filename, "rb");
|
||||
#else
|
||||
FILE* f = fopen(filename, "rb");
|
||||
#endif
|
||||
if (!f) { TML_ERROR("File not found"); return 0; }
|
||||
stream.data = f;
|
||||
res = tml_load(&stream);
|
||||
fclose(f);
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct tml_stream_memory { const char* buffer; unsigned int total, pos; };
|
||||
static int tml_stream_memory_read(struct tml_stream_memory* m, void* ptr, unsigned int size) { if (size > m->total - m->pos) size = m->total - m->pos; TML_MEMCPY(ptr, m->buffer+m->pos, size); m->pos += size; return size; }
|
||||
TMLDEF struct tml_message* tml_load_memory(const void* buffer, int size)
|
||||
{
|
||||
struct tml_stream stream = { TML_NULL, (int(*)(void*,void*,unsigned int))&tml_stream_memory_read };
|
||||
struct tml_stream_memory f = { 0, 0, 0 };
|
||||
f.buffer = (const char*)buffer;
|
||||
f.total = size;
|
||||
stream.data = &f;
|
||||
return tml_load(&stream);
|
||||
}
|
||||
|
||||
struct tml_track
|
||||
{
|
||||
unsigned int Idx, End, Ticks;
|
||||
};
|
||||
|
||||
struct tml_tempomsg
|
||||
{
|
||||
unsigned int time;
|
||||
unsigned char type, Tempo[3];
|
||||
tml_message* next;
|
||||
};
|
||||
|
||||
struct tml_parser
|
||||
{
|
||||
unsigned char *buf, *buf_end;
|
||||
int last_status, message_array_size, message_count;
|
||||
};
|
||||
|
||||
enum TMLSystemType
|
||||
{
|
||||
TML_TEXT = 0x01, TML_COPYRIGHT = 0x02, TML_TRACK_NAME = 0x03, TML_INST_NAME = 0x04, TML_LYRIC = 0x05, TML_MARKER = 0x06, TML_CUE_POINT = 0x07,
|
||||
TML_EOT = 0x2f, TML_SMPTE_OFFSET = 0x54, TML_TIME_SIGNATURE = 0x58, TML_KEY_SIGNATURE = 0x59, TML_SEQUENCER_EVENT = 0x7f,
|
||||
TML_SYSEX = 0xf0, TML_TIME_CODE = 0xf1, TML_SONG_POSITION = 0xf2, TML_SONG_SELECT = 0xf3, TML_TUNE_REQUEST = 0xf6, TML_EOX = 0xf7, TML_SYNC = 0xf8,
|
||||
TML_TICK = 0xf9, TML_START = 0xfa, TML_CONTINUE = 0xfb, TML_STOP = 0xfc, TML_ACTIVE_SENSING = 0xfe, TML_SYSTEM_RESET = 0xff
|
||||
};
|
||||
|
||||
static int tml_readbyte(struct tml_parser* p)
|
||||
{
|
||||
return (p->buf == p->buf_end ? -1 : *(p->buf++));
|
||||
}
|
||||
|
||||
static int tml_readvariablelength(struct tml_parser* p)
|
||||
{
|
||||
unsigned int res = 0, i = 0;
|
||||
unsigned char c;
|
||||
for (; i != 4; i++)
|
||||
{
|
||||
if (p->buf == p->buf_end) { TML_WARN("Unexpected end of file"); return -1; }
|
||||
c = *(p->buf++);
|
||||
if (c & 0x80) res = ((res | (c & 0x7F)) << 7);
|
||||
else return (int)(res | c);
|
||||
}
|
||||
TML_WARN("Invalid variable length byte count"); return -1;
|
||||
}
|
||||
|
||||
static int tml_parsemessage(tml_message** f, struct tml_parser* p)
|
||||
{
|
||||
int deltatime = tml_readvariablelength(p), status = tml_readbyte(p);
|
||||
tml_message* evt;
|
||||
|
||||
if (deltatime & 0xFFF00000) deltatime = 0; //throw away delays that are insanely high for malformatted midis
|
||||
if (status < 0) { TML_WARN("Unexpected end of file"); return -1; }
|
||||
if ((status & 0x80) == 0)
|
||||
{
|
||||
// Invalid, use same status as before
|
||||
if ((p->last_status & 0x80) == 0) { TML_WARN("Undefined status and invalid running status"); return -1; }
|
||||
p->buf--;
|
||||
status = p->last_status;
|
||||
}
|
||||
else p->last_status = status;
|
||||
|
||||
if (p->message_array_size == p->message_count)
|
||||
{
|
||||
//start allocated memory size of message array at 64, double each time until 8192, then add 1024 entries until done
|
||||
p->message_array_size += (!p->message_array_size ? 64 : (p->message_array_size > 4096 ? 1024 : p->message_array_size));
|
||||
*f = (tml_message*)TML_REALLOC(*f, p->message_array_size * sizeof(tml_message));
|
||||
if (!*f) { TML_ERROR("Out of memory"); return -1; }
|
||||
}
|
||||
evt = *f + p->message_count;
|
||||
|
||||
//check what message we have
|
||||
if ((status == TML_SYSEX) || (status == TML_EOX)) //sysex
|
||||
{
|
||||
//sysex messages are not handled
|
||||
p->buf += tml_readvariablelength(p);
|
||||
if (p->buf > p->buf_end) { TML_WARN("Unexpected end of file"); p->buf = p->buf_end; return -1; }
|
||||
evt->type = 0;
|
||||
}
|
||||
else if (status == 0xFF) //meta events
|
||||
{
|
||||
int meta_type = tml_readbyte(p), buflen = tml_readvariablelength(p);
|
||||
unsigned char* metadata = p->buf;
|
||||
if (meta_type < 0) { TML_WARN("Unexpected end of file"); return -1; }
|
||||
if (buflen > 0 && (p->buf += buflen) > p->buf_end) { TML_WARN("Unexpected end of file"); p->buf = p->buf_end; return -1; }
|
||||
|
||||
switch (meta_type)
|
||||
{
|
||||
case TML_EOT:
|
||||
if (buflen != 0) { TML_WARN("Invalid length for EndOfTrack event"); return -1; }
|
||||
if (!deltatime) return TML_EOT; //no need to store this message
|
||||
evt->type = TML_EOT;
|
||||
break;
|
||||
|
||||
case TML_SET_TEMPO:
|
||||
if (buflen != 3) { TML_WARN("Invalid length for SetTempo meta event"); return -1; }
|
||||
evt->type = TML_SET_TEMPO;
|
||||
((struct tml_tempomsg*)evt)->Tempo[0] = metadata[0];
|
||||
((struct tml_tempomsg*)evt)->Tempo[1] = metadata[1];
|
||||
((struct tml_tempomsg*)evt)->Tempo[2] = metadata[2];
|
||||
break;
|
||||
|
||||
default:
|
||||
evt->type = 0;
|
||||
}
|
||||
}
|
||||
else //channel message
|
||||
{
|
||||
int param;
|
||||
if ((param = tml_readbyte(p)) < 0) { TML_WARN("Unexpected end of file"); return -1; }
|
||||
evt->key = (param & 0x7f);
|
||||
evt->channel = (status & 0x0f);
|
||||
switch (evt->type = (status & 0xf0))
|
||||
{
|
||||
case TML_NOTE_OFF:
|
||||
case TML_NOTE_ON:
|
||||
case TML_KEY_PRESSURE:
|
||||
case TML_CONTROL_CHANGE:
|
||||
if ((param = tml_readbyte(p)) < 0) { TML_WARN("Unexpected end of file"); return -1; }
|
||||
evt->velocity = (param & 0x7f);
|
||||
break;
|
||||
|
||||
case TML_PITCH_BEND:
|
||||
if ((param = tml_readbyte(p)) < 0) { TML_WARN("Unexpected end of file"); return -1; }
|
||||
evt->pitch_bend = ((param & 0x7f) << 7) | evt->key;
|
||||
break;
|
||||
|
||||
case TML_PROGRAM_CHANGE:
|
||||
case TML_CHANNEL_PRESSURE:
|
||||
evt->velocity = 0;
|
||||
break;
|
||||
|
||||
default: //ignore system/manufacture messages
|
||||
evt->type = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (deltatime || evt->type)
|
||||
{
|
||||
evt->time = deltatime;
|
||||
p->message_count++;
|
||||
}
|
||||
return evt->type;
|
||||
}
|
||||
|
||||
TMLDEF tml_message* tml_load(struct tml_stream* stream)
|
||||
{
|
||||
int num_tracks, division, trackbufsize = 0;
|
||||
unsigned char midi_header[14], *trackbuf = TML_NULL;
|
||||
struct tml_message* messages = TML_NULL;
|
||||
struct tml_track *tracks, *t, *tracksEnd;
|
||||
struct tml_parser p = { TML_NULL, TML_NULL, 0, 0, 0 };
|
||||
|
||||
// Parse MIDI header
|
||||
if (stream->read(stream->data, midi_header, 14) != 14) { TML_ERROR("Unexpected end of file"); return messages; }
|
||||
if (midi_header[0] != 'M' || midi_header[1] != 'T' || midi_header[2] != 'h' || midi_header[3] != 'd' ||
|
||||
midi_header[7] != 6 || midi_header[9] > 2) { TML_ERROR("Doesn't look like a MIDI file: invalid MThd header"); return messages; }
|
||||
if (midi_header[12] & 0x80) { TML_ERROR("File uses unsupported SMPTE timing"); return messages; }
|
||||
num_tracks = (int)(midi_header[10] << 8) | midi_header[11];
|
||||
division = (int)(midi_header[12] << 8) | midi_header[13]; //division is ticks per beat (quarter-note)
|
||||
if (num_tracks <= 0 && division <= 0) { TML_ERROR("Doesn't look like a MIDI file: invalid track or division values"); return messages; }
|
||||
|
||||
// Allocate temporary tracks array for parsing
|
||||
tracks = (struct tml_track*)TML_MALLOC(sizeof(struct tml_track) * num_tracks);
|
||||
tracksEnd = &tracks[num_tracks];
|
||||
for (t = tracks; t != tracksEnd; t++) t->Idx = t->End = t->Ticks = 0;
|
||||
|
||||
// Read all messages for all tracks
|
||||
for (t = tracks; t != tracksEnd; t++)
|
||||
{
|
||||
unsigned char track_header[8];
|
||||
int track_length;
|
||||
if (stream->read(stream->data, track_header, 8) != 8) { TML_WARN("Unexpected end of file"); break; }
|
||||
if (track_header[0] != 'M' || track_header[1] != 'T' || track_header[2] != 'r' || track_header[3] != 'k')
|
||||
{ TML_WARN("Invalid MTrk header"); break; }
|
||||
|
||||
// Get size of track data and read into buffer (allocate bigger buffer if needed)
|
||||
track_length = track_header[7] | (track_header[6] << 8) | (track_header[5] << 16) | (track_header[4] << 24);
|
||||
if (track_length < 0) { TML_WARN("Invalid MTrk header"); break; }
|
||||
if (trackbufsize < track_length) { TML_FREE(trackbuf); trackbuf = (unsigned char*)TML_MALLOC(trackbufsize = track_length); }
|
||||
if (stream->read(stream->data, trackbuf, track_length) != track_length) { TML_WARN("Unexpected end of file"); break; }
|
||||
|
||||
t->Idx = p.message_count;
|
||||
for (p.buf_end = (p.buf = trackbuf) + track_length; p.buf != p.buf_end;)
|
||||
{
|
||||
int type = tml_parsemessage(&messages, &p);
|
||||
if (type == TML_EOT || type < 0) break; //file end or illegal data encountered
|
||||
}
|
||||
if (p.buf != p.buf_end) { TML_WARN( "Track length did not match data length"); }
|
||||
t->End = p.message_count;
|
||||
}
|
||||
TML_FREE(trackbuf);
|
||||
|
||||
// Change message time signature from delta ticks to actual msec values and link messages ordered by time
|
||||
if (p.message_count)
|
||||
{
|
||||
tml_message *PrevMessage = TML_NULL, *Msg, *MsgEnd, Swap;
|
||||
unsigned int ticks = 0, tempo_ticks = 0; //tick counter and value at last tempo change
|
||||
int step_smallest, msec, tempo_msec = 0; //msec value at last tempo change
|
||||
double ticks2time = 500000 / (1000.0 * division); //milliseconds per tick
|
||||
|
||||
// Loop through all messages over all tracks ordered by time
|
||||
for (step_smallest = 0; step_smallest != 0x7fffffff; ticks += step_smallest)
|
||||
{
|
||||
step_smallest = 0x7fffffff;
|
||||
msec = tempo_msec + (int)((ticks - tempo_ticks) * ticks2time);
|
||||
for (t = tracks; t != tracksEnd; t++)
|
||||
{
|
||||
if (t->Idx == t->End) continue;
|
||||
for (Msg = &messages[t->Idx], MsgEnd = &messages[t->End]; Msg != MsgEnd && t->Ticks + Msg->time == ticks; Msg++, t->Idx++)
|
||||
{
|
||||
t->Ticks += Msg->time;
|
||||
if (Msg->type == TML_SET_TEMPO)
|
||||
{
|
||||
unsigned char* Tempo = ((struct tml_tempomsg*)Msg)->Tempo;
|
||||
ticks2time = ((Tempo[0]<<16)|(Tempo[1]<<8)|Tempo[2])/(1000.0 * division);
|
||||
tempo_msec = msec;
|
||||
tempo_ticks = ticks;
|
||||
}
|
||||
if (Msg->type)
|
||||
{
|
||||
Msg->time = msec;
|
||||
if (PrevMessage) { PrevMessage->next = Msg; PrevMessage = Msg; }
|
||||
else { Swap = *Msg; *Msg = *messages; *messages = Swap; PrevMessage = messages; }
|
||||
}
|
||||
}
|
||||
if (Msg != MsgEnd && t->Ticks + Msg->time > ticks)
|
||||
{
|
||||
int step = (int)(t->Ticks + Msg->time - ticks);
|
||||
if (step < step_smallest) step_smallest = step;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (PrevMessage) PrevMessage->next = TML_NULL;
|
||||
else p.message_count = 0;
|
||||
}
|
||||
TML_FREE(tracks);
|
||||
|
||||
if (p.message_count == 0)
|
||||
{
|
||||
TML_FREE(messages);
|
||||
messages = TML_NULL;
|
||||
}
|
||||
|
||||
return messages;
|
||||
}
|
||||
|
||||
TMLDEF tml_message* tml_load_tsf_stream(struct tsf_stream* stream)
|
||||
{
|
||||
return tml_load((struct tml_stream*)stream);
|
||||
}
|
||||
|
||||
TMLDEF int tml_get_info(tml_message* Msg, int* out_used_channels, int* out_used_programs, int* out_total_notes, unsigned int* out_time_first_note, unsigned int* out_time_length)
|
||||
{
|
||||
int used_programs = 0, used_channels = 0, total_notes = 0;
|
||||
unsigned int time_first_note = 0xffffffff, time_length = 0;
|
||||
unsigned char channels[16] = { 0 }, programs[128] = { 0 };
|
||||
for (;Msg; Msg = Msg->next)
|
||||
{
|
||||
time_length = Msg->time;
|
||||
if (Msg->type == TML_PROGRAM_CHANGE && !programs[(int)Msg->program]) { programs[(int)Msg->program] = 1; used_programs++; }
|
||||
if (Msg->type != TML_NOTE_ON) continue;
|
||||
if (time_first_note == 0xffffffff) time_first_note = time_length;
|
||||
if (!channels[Msg->channel]) { channels[Msg->channel] = 1; used_channels++; }
|
||||
total_notes++;
|
||||
}
|
||||
if (time_first_note == 0xffffffff) time_first_note = 0;
|
||||
if (out_used_channels ) *out_used_channels = used_channels;
|
||||
if (out_used_programs ) *out_used_programs = used_programs;
|
||||
if (out_total_notes ) *out_total_notes = total_notes;
|
||||
if (out_time_first_note) *out_time_first_note = time_first_note;
|
||||
if (out_time_length ) *out_time_length = time_length;
|
||||
return total_notes;
|
||||
}
|
||||
|
||||
TMLDEF int tml_get_tempo_value(tml_message* msg)
|
||||
{
|
||||
unsigned char* Tempo;
|
||||
if (!msg || msg->type != TML_SET_TEMPO) return 0;
|
||||
Tempo = ((struct tml_tempomsg*)msg)->Tempo;
|
||||
return ((Tempo[0]<<16)|(Tempo[1]<<8)|Tempo[2]);
|
||||
}
|
||||
|
||||
TMLDEF void tml_free(tml_message* f)
|
||||
{
|
||||
TML_FREE(f);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //TML_IMPLEMENTATION
|
1898
internal/c/parts/audio/extras/tinysoundfont/tsf.h
Normal file
1898
internal/c/parts/audio/extras/tinysoundfont/tsf.h
Normal file
File diff suppressed because it is too large
Load diff
90463
internal/c/parts/audio/miniaudio.h
Normal file
90463
internal/c/parts/audio/miniaudio.h
Normal file
File diff suppressed because it is too large
Load diff
63
internal/c/parts/audio/miniaudio_impl.cpp
Normal file
63
internal/c/parts/audio/miniaudio_impl.cpp
Normal file
|
@ -0,0 +1,63 @@
|
|||
//----------------------------------------------------------------------------------------------------
|
||||
// ___ ___ __ _ _ ___ ___ _ _ _ ___ _
|
||||
// / _ \| _ ) / /| | || _ \ __| /_\ _ _ __| (_)___ | __|_ _ __ _(_)_ _ ___
|
||||
// | (_) | _ \/ _ \_ _| _/ _| / _ \ || / _` | / _ \ | _|| ' \/ _` | | ' \/ -_)
|
||||
// \__\_\___/\___/ |_||_| |___| /_/ \_\_,_\__,_|_\___/ |___|_||_\__, |_|_||_\___|
|
||||
// |___/
|
||||
//
|
||||
// QB64-PE Audio Engine powered by miniaudio (https://miniaud.io/)
|
||||
//
|
||||
// Copyright (c) 2022 Samuel Gomes
|
||||
// https://github.com/a740g
|
||||
//
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
// HEADER FILES
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
// Enable Ogg Vorbis decoding
|
||||
#define STB_VORBIS_HEADER_ONLY
|
||||
#include "extras/stb_vorbis.c"
|
||||
// PulseAudio has serious stuttering issues in ChromeOS Linux (Crostini) and possibly others
|
||||
// This may be due to this - https://github.com/mackron/miniaudio/issues/427
|
||||
// And https://wiki.archlinux.org/title/PulseAudio/Troubleshooting#Glitches,_skips_or_crackling
|
||||
// We'll have to look at this closely later. If this is fixed, then remove this define from here & audio.cpp
|
||||
#define MA_NO_PULSEAUDIO
|
||||
// The main miniaudio header
|
||||
#define MINIAUDIO_IMPLEMENTATION
|
||||
#include "miniaudio.h"
|
||||
// The stb_vorbis implementation must come after the implementation of miniaudio
|
||||
#undef STB_VORBIS_HEADER_ONLY
|
||||
#include "extras/stb_vorbis.c"
|
||||
// RADv2 format support
|
||||
#include "extras/miniaudio_radv2.h"
|
||||
// MIDI format support
|
||||
// #include "extras/miniaudio_tinysoundfont.h"
|
||||
// MOD, S3M, XM & IT support
|
||||
#include "extras/miniaudio_libxmp-lite.h"
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
// GLOBAL VARIABLES
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
// Add custom backend (format) vtables here
|
||||
// The order in the array defines the order of priority
|
||||
// The vtables will be passed in to the resource manager config
|
||||
ma_decoding_backend_vtable *maCustomBackendVTables[] = {&ma_decoding_backend_vtable_radv2, // &ma_decoding_backend_vtable_tsf,
|
||||
&ma_decoding_backend_vtable_modplay};
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
// FUNCTIONS
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// This simply attaches the format decode VTables array to ma_resource_manager_config
|
||||
/// </summary>
|
||||
/// <param name="maResourceManagerConfig">Pointer to a miniaudio resource manager config object. This cannot be NULL</param>
|
||||
void AudioEngineAttachCustomBackendVTables(ma_resource_manager_config *maResourceManagerConfig) {
|
||||
// Attach the VTable
|
||||
maResourceManagerConfig->ppCustomDecodingBackendVTables = maCustomBackendVTables;
|
||||
maResourceManagerConfig->customDecodingBackendCount = ma_countof(maCustomBackendVTables);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------------------------------
|
28
internal/c/parts/audio/stub_audio.cpp
Normal file
28
internal/c/parts/audio/stub_audio.cpp
Normal file
|
@ -0,0 +1,28 @@
|
|||
//----------------------------------------------------------------------------------------------------
|
||||
// ___ ___ __ _ _ ___ ___ _ _ _ ___ _
|
||||
// / _ \| _ ) / /| | || _ \ __| /_\ _ _ __| (_)___ | __|_ _ __ _(_)_ _ ___
|
||||
// | (_) | _ \/ _ \_ _| _/ _| / _ \ || / _` | / _ \ | _|| ' \/ _` | | ' \/ -_)
|
||||
// \__\_\___/\___/ |_||_| |___| /_/ \_\_,_\__,_|_\___/ |___|_||_\__, |_|_||_\___|
|
||||
// |___/
|
||||
//
|
||||
// QB64-PE Audio Engine powered by miniaudio (https://miniaud.io/)
|
||||
//
|
||||
// Copyright (c) 2022 Samuel Gomes
|
||||
// https://github.com/a740g
|
||||
//
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
// HEADER FILES
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
#include "audio.h"
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
// FUNCTIONS
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
void snd_mainloop() { return; }
|
||||
void snd_init() { return; }
|
||||
void snd_un_init() { return; }
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------------------------------
|
|
@ -1,102 +0,0 @@
|
|||
=== IMPORTANT LICENSING NOTE FOR QB64 PROGRAMMERS ===
|
||||
All executables which perform any kind of sound operation are subject to the LGPL license (due to incorporation of mpglibdll and OpenAL).
|
||||
Other components are licensed under various permissive licences.
|
||||
When sound components are included (thus the LGPL is in effect), the easiest way to meet terms of the LGPL is to make your program's source code (.BAS) available.
|
||||
If you are not using sound components, you do not need to release the program's source.
|
||||
If you are using fonts, you are bound by the terms of FreeType's license. Somewhere in your software package should include a notice that your program includes the FreeType library (see licence_freetype_ftl.txt for details)
|
||||
In all cases, you should distribute the licenses folder with your program.
|
||||
|
||||
It should be noted that providing source code is not the only way to meet the conditions of the LGPL (eg dynamic linking) but it is by far the easiest from a technical point of view at this current time.
|
||||
=====================================================
|
||||
|
||||
The license requirements for components of QB64 are as follows:
|
||||
|
||||
Software/Library Name: QB64 Phoenix Edition (inclusive of all parts of this distribution not covered by separate licence below)
|
||||
Website(s): https://qb64phoenix.com
|
||||
License: MIT
|
||||
License Website: https://opensource.org/licenses/MIT
|
||||
License:
|
||||
Copyright 2007-2020 Galleon & The QB64 Team
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
|
||||
Software/Library Name: MinGW 64
|
||||
Website: http://mingw-w64.sourceforge.net/
|
||||
License: (see below)
|
||||
Each of the various packages, which is distributed by MinGW.org, is governed by its own individual copyright and licensing terms. In summary, for the most commonly deployed packages:
|
||||
MinGW runtime: The MinGW base runtime package has been placed in the public domain, and is not governed by copyright. This basically means that you can do what you like with the code.
|
||||
w32api: You are free to use, modify and copy this package. No restrictions are imposed on programs or object files linked with this library. You may not restrict the the usage of this library. You may distribute this library as part of another package or as a modified package if, and only if, you do not restrict the usage of the portions consisting of this (optionally modified) library. If distributed as a modified package, then a copy of this notice must be included.
|
||||
This library is distributed in the hope that it will be useful, but WITHOUT WARRANTY OF ANY KIND; without even the implied warranties of MERCHANTABILITY or of FITNESS FOR A PARTICULAR PURPOSE.
|
||||
MinGW profiling code: MinGW profiling code is distributed under the terms of the GNU General Public License.
|
||||
Binutils, GCC, GDB, GNU Make: All of the GNU development tools, such as GNU binutils, GCC, GDB and GNU Make, are governed by the terms of the GNU General Public License.
|
||||
License Website: http://www.gnu.org/licenses/licenses.html#GPL
|
||||
License File: license_gnu_gpl_3.txt
|
||||
Location in QB64 distribution: internal/c/c_compiler/
|
||||
|
||||
Software/Library Name: Opus Tools
|
||||
Website: http://www.opus-codec.org/
|
||||
License: BSD 2-clause license
|
||||
License Website: http://opensource.org/licenses/BSD-2-Clause
|
||||
License File: license_opus.txt
|
||||
Location in QB64 distribution: internal/c/parts/audio/conversion/
|
||||
OpusInfo, which is under a GPL licence, was included in Opus Tools but has been removed from the QB64 distribution.
|
||||
|
||||
Software/Library Name: mpglibdll
|
||||
Website(s):
|
||||
http://www.rz.uni-frankfurt.de/~pesch
|
||||
http://www.mpg123.de
|
||||
http://www.sulaco.org/mp3
|
||||
License: LGPL 2.1
|
||||
License Website: http://www.gnu.org/licenses/licenses.html#LGPL
|
||||
License File: license_gnu_lgpl_2_1.txt
|
||||
Location in QB64 distribution: internal/c/parts/audio/decode/mp3/
|
||||
|
||||
Software/Library Name: Ogg Vorbis I audio decoder version 1.05
|
||||
Website:http://nothings.org/stb_vorbis/
|
||||
Date:Written in April 2007
|
||||
Author:Sean Barrett, sponsored by RAD Game Tools
|
||||
License: Placed in the public domain April 2007 by the author: no copyright is claimed, and you may use it for any purpose you like.
|
||||
License Website: N/A - public domain
|
||||
License File: license_stbvorbis.txt
|
||||
Location in QB64 distribution: internal/c/parts/audio/decode/ogg/
|
||||
|
||||
Software/Library Name: OpenAL-soft
|
||||
Website:http://kcat.strangesoft.net/openal.html
|
||||
License: LGPL 2
|
||||
License Website: http://www.gnu.org/licenses/licenses.html#LGPL
|
||||
License File: license_gnu_lgpl_2.txt
|
||||
Location in QB64 distribution: internal/c/parts/audio/out/
|
||||
|
||||
Software/Library Name: FreeGLUT
|
||||
Website: http://freeglut.sourceforge.net/
|
||||
License: LGPL (note: website states LGPL, license file is not a copy of GNU LGPL)
|
||||
License Website: http://www.gnu.org/licenses/licenses.html#LGPL
|
||||
License File: license_freeglut.txt
|
||||
Location in QB64 distribution: internal/c/parts/core/
|
||||
|
||||
Software/Library Name: FreeTYPE
|
||||
Website: http://www.freetype.org/
|
||||
License: GPL or FreeTYPE's FTL (programs must abide by one of these licenses)
|
||||
License Website(s): (see below)
|
||||
http://www.freetype.org/license.html
|
||||
http://www.gnu.org/licenses/licenses.html#GPL
|
||||
License File(s): (see below)
|
||||
license_freetype_ftl.txt
|
||||
license_gnu_gpl_2.txt
|
||||
Location in QB64 distribution: internal/c/parts/video/font/ttf/
|
||||
|
||||
Software/Library Name: NanoJPEG - KeyJ's Tiny Baseline JPEG Decoder
|
||||
Author: Martin J. Fiedler <martin.fiedler@gmx.net>
|
||||
License: MIT
|
||||
License File: license_nanojpeg.txt
|
||||
Location in QB64 distribution: internal/c/parts/video/image/decode/jpg
|
||||
|
||||
Software/Library Name: LodePNG
|
||||
License: (refer to license file)
|
||||
License File: license_lodepng.txt
|
||||
Location in QB64 distribution: internal/c/parts/video/image/decode/png
|
103
licenses/COPYING.md
Normal file
103
licenses/COPYING.md
Normal file
|
@ -0,0 +1,103 @@
|
|||
QB64 Phoenix Edition Licensing information
|
||||
==========================================
|
||||
|
||||
QB64-PE makes extensive use of third party libraries to provide
|
||||
functionality. These third party libraries have their own licenses that you
|
||||
must respect when distributing any programs compiled by QB64-PE.
|
||||
|
||||
As a general note, almost third party libraries used by QB64-PE are either MIT,
|
||||
Public Domain, or some other permissive license. Meeting their requirements can
|
||||
be done by simply distributing the licenses in the `./licenses` folder with
|
||||
your compiled program.
|
||||
|
||||
A few of the libraries are LGPL and require more careful handling to meet their
|
||||
license requirements (either by providing source code or object files before
|
||||
linking). Those are noted on this page and avoidable. Note that QB64-PE does
|
||||
not give the option of using dynamic linking, all third party libraries are
|
||||
statically linked.
|
||||
|
||||
Additionally, QB64-PE contains logic to avoid compiling in third party libraries
|
||||
if they are not used by the program, those situations are noted on this page.
|
||||
If a component is not compiled into your program then you do not need to meet
|
||||
its license requirements.
|
||||
|
||||
## QB64 Phoenix Edition Runtime
|
||||
|
||||
This is the licensing of the provided QB64-PE runtime that compiled programs make use of.
|
||||
|
||||
| Library | License | License file | Location |
|
||||
| :------ | :-----: | :----------- | :------- |
|
||||
| libqb | MIT | license_qb64.txt | internal/c/libqb.cpp, internal/c/libqb/, internal/c/qbx.cpp |
|
||||
|
||||
## Windows C and C++ Runtime
|
||||
|
||||
On Windows MinGW-w64 is used to compiled the C++ code produced by QB64-PE, and some runtime components are compiled into your code. On Linux and Mac OS this section does not apply.
|
||||
|
||||
| Library | License | License file | Location |
|
||||
| :------ | :-----: | :----------- | :------- |
|
||||
| MinGW-w64 C and C++ runtime | Various Permissive Licenses | license_mingw-base-runtime.txt | internal/c/c_compiler |
|
||||
| libstdc++ | GPLv3 with Exception | license_libstdc++.txt | internal/c/c_compiler |
|
||||
|
||||
## Display Support
|
||||
|
||||
This is always used unless you use `$CONSOLE:ONLY`. On Mac OS the system's own GLUT implementation is used rather than `FreeGLUT`.
|
||||
|
||||
| Library | License | License file | Location |
|
||||
| :------ | :-----: | :----------- | :------- |
|
||||
| FreeGLUT | MIT | license_freeglut.txt | internal/c/parts/core |
|
||||
|
||||
## Image Support
|
||||
|
||||
These libraries are pulled in if `_LOADIMAGE()` functionality is used.
|
||||
|
||||
| Library | License | License file | Location |
|
||||
| :------ | :-----: | :----------- | :------- |
|
||||
| NanoJPEG | MIT | license_nanojpeg.txt | internal/c/parts/video/image/decode/jpg |
|
||||
| LodePNG | ZLIB | license_lodepng.txt | internal/c/parts/video/image/decode/png |
|
||||
|
||||
## Font Support
|
||||
|
||||
These libraries are pulled in if `_LOADFONT()` functionality is used.
|
||||
|
||||
| Library | License | License file | Location |
|
||||
| :------ | :-----: | :----------- | :------- |
|
||||
| FreeTYPE | FLT | license_freetype_ftl.txt | internal/c/parts/video/font/tff/ |
|
||||
|
||||
## Compression Support
|
||||
|
||||
These libraries are pulled in if `_INFLATE$()` or `_DEFLATE$()` are used.
|
||||
|
||||
| Library | License | License file | Location |
|
||||
| :------ | :-----: | :----------- | :------- |
|
||||
| ZLib | ZLIB | license_zlib.txt | internal/c/c_compiler (provide by MinGW on Windows, system library otherwise) |
|
||||
|
||||
## Sound Support
|
||||
|
||||
These libraries are pulled in when using any sound-related functionality.
|
||||
|
||||
| Library | License | License file | Location |
|
||||
| :------ | :-----: | :----------- | :------- |
|
||||
| Miniaudio | MIT | license_miniaudio.txt | internal/c/parts/audio/miniaudio.h |
|
||||
| libxmp-lite | MIT | license_libxmp-lite.txt | internal/c/parts/audio/extras/libxmp-lite/ |
|
||||
| RADv2 | Public Domain | license_radv2.txt | internal/c/parts/audio/extras/radv2/ |
|
||||
| std_vorbus | Public Domain | license_stdvorbis.txt | internal/c/parts/audio/extras/std_vorbis.c |
|
||||
|
||||
## MIDI Support
|
||||
|
||||
These are used if you make use of MIDI support.
|
||||
|
||||
| Library | License | License file | Location |
|
||||
| :------ | :-----: | :----------- | :------- |
|
||||
| TinySoundFont | MIT | license_tinysoundfont.txt | internal/c/parts/audio/extras/tinysoundfont/tsf.h
|
||||
| TinyMidiLoader | ZLIB | license_tinymidiloader.txt | internal/c/parts/audio/extras/tinysoundfont.tml.h |
|
||||
|
||||
## Legacy OpenAL audio backend
|
||||
|
||||
The below licenses apply when making use of the legacy OpenAL audio backend (can be enabled in `Compiler Settings`). These replace all other sound related libraries:
|
||||
|
||||
| Library | License | License file | Location |
|
||||
| :------ | :-----: | :----------- | :------- |
|
||||
| mpg123 | LGPL 2.1 | license_mpg123.txt | internal/c/parts/audio/decode/mp3/ |
|
||||
| OpenAL-soft | LGPL 2 | license_openal.txt | internal/c/parts/audio/out/ |
|
||||
| Opus Tools | BSD 2-clause | license_opus.txt | internal/c/parts/audio/conversion/ |
|
||||
| stb_vorbis | Public Domain | license_stdvorbis.txt | internal/c/parts/audio/decode/ogg/ |
|
|
@ -1,340 +0,0 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Library General
|
||||
Public License instead of this License.
|
|
@ -1,674 +0,0 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
72
licenses/license_libstdc++.txt
Normal file
72
licenses/license_libstdc++.txt
Normal file
|
@ -0,0 +1,72 @@
|
|||
GCC RUNTIME LIBRARY EXCEPTION
|
||||
|
||||
Version 3.1, 31 March 2009
|
||||
|
||||
Copyright (C) 2009 Free Software Foundation, Inc.
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim copies of this
|
||||
license document, but changing it is not allowed.
|
||||
|
||||
This GCC Runtime Library Exception ("Exception") is an additional
|
||||
permission under section 7 of the GNU General Public License, version
|
||||
3 ("GPLv3"). It applies to a given file (the "Runtime Library") that
|
||||
bears a notice placed by the copyright holder of the file stating that
|
||||
the file is governed by GPLv3 along with this Exception.
|
||||
|
||||
When you use GCC to compile a program, GCC may combine portions of
|
||||
certain GCC header files and runtime libraries with the compiled
|
||||
program. The purpose of this Exception is to allow compilation of
|
||||
non-GPL (including proprietary) programs to use, in this way, the
|
||||
header files and runtime libraries covered by this Exception.
|
||||
|
||||
0. Definitions.
|
||||
|
||||
A file is an "Independent Module" if it either requires the Runtime
|
||||
Library for execution after a Compilation Process, or makes use of an
|
||||
interface provided by the Runtime Library, but is not otherwise based
|
||||
on the Runtime Library.
|
||||
|
||||
"GCC" means a version of the GNU Compiler Collection, with or without
|
||||
modifications, governed by version 3 (or a specified later version) of
|
||||
the GNU General Public License (GPL) with the option of using any
|
||||
subsequent versions published by the FSF.
|
||||
|
||||
"GPL-compatible Software" is software whose conditions of propagation,
|
||||
modification and use would permit combination with GCC in accord with
|
||||
the license of GCC.
|
||||
|
||||
"Target Code" refers to output from any compiler for a real or virtual
|
||||
target processor architecture, in executable form or suitable for
|
||||
input to an assembler, loader, linker and/or execution
|
||||
phase. Notwithstanding that, Target Code does not include data in any
|
||||
format that is used as a compiler intermediate representation, or used
|
||||
for producing a compiler intermediate representation.
|
||||
|
||||
The "Compilation Process" transforms code entirely represented in
|
||||
non-intermediate languages designed for human-written code, and/or in
|
||||
Java Virtual Machine byte code, into Target Code. Thus, for example,
|
||||
use of source code generators and preprocessors need not be considered
|
||||
part of the Compilation Process, since the Compilation Process can be
|
||||
understood as starting with the output of the generators or
|
||||
preprocessors.
|
||||
|
||||
A Compilation Process is "Eligible" if it is done using GCC, alone or
|
||||
with other GPL-compatible software, or if it is done without using any
|
||||
work based on GCC. For example, using non-GPL-compatible Software to
|
||||
optimize any GCC intermediate representations would not qualify as an
|
||||
Eligible Compilation Process.
|
||||
|
||||
1. Grant of Additional Permission.
|
||||
|
||||
You have permission to propagate a work of Target Code formed by
|
||||
combining the Runtime Library with Independent Modules, even if such
|
||||
propagation would otherwise violate the terms of GPLv3, provided that
|
||||
all Target Code was generated by Eligible Compilation Processes. You
|
||||
may then convey such a combination under terms of your choice,
|
||||
consistent with the licensing of the Independent Modules.
|
||||
|
||||
2. No Weakening of GCC Copyleft.
|
||||
|
||||
The availability of this Exception does not imply any general
|
||||
presumption that third-party software is unaffected by the copyleft
|
||||
requirements of the license of GCC.
|
42
licenses/license_libxmp-lite.txt
Normal file
42
licenses/license_libxmp-lite.txt
Normal file
|
@ -0,0 +1,42 @@
|
|||
__ _ __ ___ __
|
||||
/ / (_) / __ __ __ _ ___ ____/ (_) /____
|
||||
/ /__/ / _ \\ \ // ' \/ _ \/___/ / / __/ -_)
|
||||
/____/_/_.__/_\_\/_/_/_/ .__/ /_/_/\__/\__/
|
||||
/_/
|
||||
|
||||
Libxmp-lite is a lean and lightweight subset of Libxmp that plays MOD, S3M,
|
||||
XM, and IT modules and retains full compatibility with the original API.
|
||||
It's intended for games and small or embedded applications where module
|
||||
format diversity and file depacking are not required.
|
||||
|
||||
Library size can be further reduced by disabling Impulse Tracker format
|
||||
support (configure with --disable-it). This option will also disable IT
|
||||
effects and lowpass filtering.
|
||||
|
||||
Please refer to http://xmp.sf.net/libxmp.html for details on the current
|
||||
Libxmp API.
|
||||
|
||||
|
||||
LICENSE
|
||||
|
||||
Extended Module Player Lite
|
||||
Copyright (C) 1996-2021 Claudio Matsuoka and Hipolito Carraro Jr
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
240
licenses/license_mingw-base-runtime.txt
Normal file
240
licenses/license_mingw-base-runtime.txt
Normal file
|
@ -0,0 +1,240 @@
|
|||
MinGW-w64 runtime licensing
|
||||
***************************
|
||||
|
||||
This program or library was built using MinGW-w64 and statically
|
||||
linked against the MinGW-w64 runtime. Some parts of the runtime
|
||||
are under licenses which require that the copyright and license
|
||||
notices are included when distributing the code in binary form.
|
||||
These notices are listed below.
|
||||
|
||||
|
||||
========================
|
||||
Overall copyright notice
|
||||
========================
|
||||
|
||||
Copyright (c) 2009, 2010, 2011, 2012, 2013 by the mingw-w64 project
|
||||
|
||||
This license has been certified as open source. It has also been designated
|
||||
as GPL compatible by the Free Software Foundation (FSF).
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions in source code must retain the accompanying copyright
|
||||
notice, this list of conditions, and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the accompanying
|
||||
copyright notice, this list of conditions, and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
3. Names of the copyright holders must not be used to endorse or promote
|
||||
products derived from this software without prior written permission
|
||||
from the copyright holders.
|
||||
4. The right to distribute this software or to use it for any purpose does
|
||||
not give you the right to use Servicemarks (sm) or Trademarks (tm) of
|
||||
the copyright holders. Use of them is covered by separate agreement
|
||||
with the copyright holders.
|
||||
5. If any files are modified, you must cause the modified files to carry
|
||||
prominent notices stating that you changed the files and the date of
|
||||
any change.
|
||||
|
||||
Disclaimer
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESSED
|
||||
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 COPYRIGHT HOLDERS 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.
|
||||
|
||||
========================================
|
||||
getopt, getopt_long, and getop_long_only
|
||||
========================================
|
||||
|
||||
Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
|
||||
Permission to use, copy, modify, and distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
Sponsored in part by the Defense Advanced Research Projects
|
||||
Agency (DARPA) and Air Force Research Laboratory, Air Force
|
||||
Materiel Command, USAF, under agreement number F39502-99-1-0512.
|
||||
|
||||
* * * * * * *
|
||||
|
||||
Copyright (c) 2000 The NetBSD Foundation, Inc.
|
||||
All rights reserved.
|
||||
|
||||
This code is derived from software contributed to The NetBSD Foundation
|
||||
by Dieter Baron and Thomas Klausner.
|
||||
|
||||
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.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
``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 FOUNDATION OR CONTRIBUTORS
|
||||
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.
|
||||
|
||||
|
||||
===============================================================
|
||||
gdtoa: Converting between IEEE floating point numbers and ASCII
|
||||
===============================================================
|
||||
|
||||
The author of this software is David M. Gay.
|
||||
|
||||
Copyright (C) 1997, 1998, 1999, 2000, 2001 by Lucent Technologies
|
||||
All Rights Reserved
|
||||
|
||||
Permission to use, copy, modify, and distribute this software and
|
||||
its documentation for any purpose and without fee is hereby
|
||||
granted, provided that the above copyright notice appear in all
|
||||
copies and that both that the copyright notice and this
|
||||
permission notice and warranty disclaimer appear in supporting
|
||||
documentation, and that the name of Lucent or any of its entities
|
||||
not be used in advertising or publicity pertaining to
|
||||
distribution of the software without specific, written prior
|
||||
permission.
|
||||
|
||||
LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
||||
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
|
||||
IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
|
||||
SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
|
||||
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
||||
THIS SOFTWARE.
|
||||
|
||||
* * * * * * *
|
||||
|
||||
The author of this software is David M. Gay.
|
||||
|
||||
Copyright (C) 2005 by David M. Gay
|
||||
All Rights Reserved
|
||||
|
||||
Permission to use, copy, modify, and distribute this software and its
|
||||
documentation for any purpose and without fee is hereby granted,
|
||||
provided that the above copyright notice appear in all copies and that
|
||||
both that the copyright notice and this permission notice and warranty
|
||||
disclaimer appear in supporting documentation, and that the name of
|
||||
the author or any of his current or former employers not be used in
|
||||
advertising or publicity pertaining to distribution of the software
|
||||
without specific, written prior permission.
|
||||
|
||||
THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
||||
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||
NO EVENT SHALL THE AUTHOR OR ANY OF HIS CURRENT OR FORMER EMPLOYERS BE
|
||||
LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
|
||||
DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
|
||||
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
|
||||
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
||||
SOFTWARE.
|
||||
|
||||
* * * * * * *
|
||||
|
||||
The author of this software is David M. Gay.
|
||||
|
||||
Copyright (C) 2004 by David M. Gay.
|
||||
All Rights Reserved
|
||||
Based on material in the rest of /netlib/fp/gdota.tar.gz,
|
||||
which is copyright (C) 1998, 2000 by Lucent Technologies.
|
||||
|
||||
Permission to use, copy, modify, and distribute this software and
|
||||
its documentation for any purpose and without fee is hereby
|
||||
granted, provided that the above copyright notice appear in all
|
||||
copies and that both that the copyright notice and this
|
||||
permission notice and warranty disclaimer appear in supporting
|
||||
documentation, and that the name of Lucent or any of its entities
|
||||
not be used in advertising or publicity pertaining to
|
||||
distribution of the software without specific, written prior
|
||||
permission.
|
||||
|
||||
LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
||||
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
|
||||
IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
|
||||
SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
|
||||
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
||||
THIS SOFTWARE.
|
||||
|
||||
|
||||
=========================
|
||||
Parts of the math library
|
||||
=========================
|
||||
|
||||
Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
|
||||
|
||||
Developed at SunSoft, a Sun Microsystems, Inc. business.
|
||||
Permission to use, copy, modify, and distribute this
|
||||
software is freely granted, provided that this notice
|
||||
is preserved.
|
||||
|
||||
* * * * * * *
|
||||
|
||||
Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
|
||||
|
||||
Developed at SunPro, a Sun Microsystems, Inc. business.
|
||||
Permission to use, copy, modify, and distribute this
|
||||
software is freely granted, provided that this notice
|
||||
is preserved.
|
||||
|
||||
* * * * * * *
|
||||
|
||||
FIXME: Cephes math lib
|
||||
Copyright (C) 1984-1998 Stephen L. Moshier
|
||||
|
||||
It sounds vague, but as to be found at
|
||||
<http://lists.debian.org/debian-legal/2004/12/msg00295.html>, it gives an
|
||||
impression that the author could be willing to give an explicit
|
||||
permission to distribute those files e.g. under a BSD style license. So
|
||||
probably there is no problem here, although it could be good to get a
|
||||
permission from the author and then add a license into the Cephes files
|
||||
in MinGW runtime. At least on follow-up it is marked that debian sees the
|
||||
version a-like BSD one. As MinGW.org (where those cephes parts are coming
|
||||
from) distributes them now over 6 years, it should be fine.
|
||||
|
||||
===================================
|
||||
Headers and IDLs imported from Wine
|
||||
===================================
|
||||
|
||||
Some header and IDL files were imported from the Wine project. These files
|
||||
are prominent maked in source. Their copyright belongs to contributors and
|
||||
they are distributed under LGPL license.
|
||||
|
||||
Disclaimer
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
47
licenses/license_miniaudio.txt
Normal file
47
licenses/license_miniaudio.txt
Normal file
|
@ -0,0 +1,47 @@
|
|||
This software is available as a choice of the following licenses. Choose
|
||||
whichever you prefer.
|
||||
|
||||
===============================================================================
|
||||
ALTERNATIVE 1 - Public Domain (www.unlicense.org)
|
||||
===============================================================================
|
||||
This is free and unencumbered software released into the public domain.
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
|
||||
software, either in source code form or as a compiled binary, for any purpose,
|
||||
commercial or non-commercial, and by any means.
|
||||
|
||||
In jurisdictions that recognize copyright laws, the author or authors of this
|
||||
software dedicate any and all copyright interest in the software to the public
|
||||
domain. We make this dedication for the benefit of the public at large and to
|
||||
the detriment of our heirs and successors. We intend this dedication to be an
|
||||
overt act of relinquishment in perpetuity of all present and future rights to
|
||||
this software under copyright law.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
For more information, please refer to <http://unlicense.org/>
|
||||
|
||||
===============================================================================
|
||||
ALTERNATIVE 2 - MIT No Attribution
|
||||
===============================================================================
|
||||
Copyright 2020 David Reid
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
|
@ -1,8 +1,13 @@
|
|||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 2.1, February 1999
|
||||
=======================
|
||||
1. The LGPL version 2.1
|
||||
=======================
|
||||
|
||||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 2.1, February 1999
|
||||
|
||||
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
|
@ -10,7 +15,7 @@
|
|||
as the successor of the GNU Library Public License, version 2, hence
|
||||
the version number 2.1.]
|
||||
|
||||
Preamble
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
|
@ -112,7 +117,7 @@ modification follow. Pay close attention to the difference between a
|
|||
former contains code derived from the library, whereas the latter must
|
||||
be combined with the library in order to run.
|
||||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License Agreement applies to any software library or other
|
||||
|
@ -432,7 +437,7 @@ decision will be guided by the two goals of preserving the free status
|
|||
of all derivatives of our free software and of promoting the sharing
|
||||
and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
NO WARRANTY
|
||||
|
||||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||
|
@ -455,50 +460,291 @@ FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
|||
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Libraries
|
||||
|
||||
If you develop a new library, and you want it to be of the greatest
|
||||
possible use to the public, we recommend making it free software that
|
||||
everyone can redistribute and change. You can do so by permitting
|
||||
redistribution under these terms (or, alternatively, under the terms of the
|
||||
ordinary General Public License).
|
||||
|
||||
To apply these terms, attach the following notices to the library. It is
|
||||
safest to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least the
|
||||
"copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the library's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the library, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the
|
||||
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1990
|
||||
Ty Coon, President of Vice
|
||||
|
||||
That's all there is to it!
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
|
||||
====================
|
||||
2. The GPL version 2
|
||||
====================
|
||||
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
|
@ -1,17 +1,15 @@
|
|||
|
||||
GNU LIBRARY GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
GNU LIBRARY GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1991 Free Software Foundation, Inc.
|
||||
675 Mass Ave, Cambridge, MA 02139, USA
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
[This is the first released version of the library GPL. It is
|
||||
numbered 2 because it goes with version 2 of the ordinary GPL.]
|
||||
|
||||
Preamble
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
|
@ -53,7 +51,7 @@ library. If the library is modified by someone else and passed on, we
|
|||
want its recipients to know that what they have is not the original
|
||||
version, so that any problems introduced by others will not reflect on
|
||||
the original authors' reputations.
|
||||
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that companies distributing free
|
||||
software will individually obtain patent licenses, thus in effect
|
||||
|
@ -100,8 +98,8 @@ works together with the library.
|
|||
|
||||
Note that it is possible for a library to be covered by the ordinary
|
||||
General Public License rather than by this special one.
|
||||
|
||||
GNU LIBRARY GENERAL PUBLIC LICENSE
|
||||
|
||||
GNU LIBRARY GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License Agreement applies to any software library which
|
||||
|
@ -147,7 +145,7 @@ Library.
|
|||
You may charge a fee for the physical act of transferring a copy,
|
||||
and you may at your option offer warranty protection in exchange for a
|
||||
fee.
|
||||
|
||||
|
||||
2. You may modify your copy or copies of the Library or any portion
|
||||
of it, thus forming a work based on the Library, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
|
@ -205,7 +203,7 @@ instead of to this License. (If a newer version than version 2 of the
|
|||
ordinary GNU General Public License has appeared, then you can specify
|
||||
that version instead if you wish.) Do not make any other change in
|
||||
these notices.
|
||||
|
||||
|
||||
Once this change is made in a given copy, it is irreversible for
|
||||
that copy, so the ordinary GNU General Public License applies to all
|
||||
subsequent copies and derivative works made from that copy.
|
||||
|
@ -256,7 +254,7 @@ Library will still fall under Section 6.)
|
|||
distribute the object code for the work under the terms of Section 6.
|
||||
Any executables containing that work also fall under Section 6,
|
||||
whether or not they are linked directly with the Library itself.
|
||||
|
||||
|
||||
6. As an exception to the Sections above, you may also compile or
|
||||
link a "work that uses the Library" with the Library to produce a
|
||||
work containing portions of the Library, and distribute that work
|
||||
|
@ -310,7 +308,7 @@ restrictions of other proprietary libraries that do not normally
|
|||
accompany the operating system. Such a contradiction means you cannot
|
||||
use both them and the Library together in an executable that you
|
||||
distribute.
|
||||
|
||||
|
||||
7. You may place library facilities that are a work based on the
|
||||
Library side-by-side in a single library together with other library
|
||||
facilities not covered by this License, and distribute such a combined
|
||||
|
@ -351,7 +349,7 @@ subject to these terms and conditions. You may not impose any further
|
|||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
|
||||
11. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
|
@ -403,7 +401,7 @@ conditions either of that version or of any later version published by
|
|||
the Free Software Foundation. If the Library does not specify a
|
||||
license version number, you may choose any version ever published by
|
||||
the Free Software Foundation.
|
||||
|
||||
|
||||
14. If you wish to incorporate parts of the Library into other free
|
||||
programs whose distribution conditions are incompatible with these,
|
||||
write to the author to ask for permission. For software which is
|
||||
|
@ -413,7 +411,7 @@ decision will be guided by the two goals of preserving the free status
|
|||
of all derivatives of our free software and of promoting the sharing
|
||||
and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
NO WARRANTY
|
||||
|
||||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||
|
@ -436,49 +434,4 @@ FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
|||
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Appendix: How to Apply These Terms to Your New Libraries
|
||||
|
||||
If you develop a new library, and you want it to be of the greatest
|
||||
possible use to the public, we recommend making it free software that
|
||||
everyone can redistribute and change. You can do so by permitting
|
||||
redistribution under these terms (or, alternatively, under the terms of the
|
||||
ordinary General Public License).
|
||||
|
||||
To apply these terms, attach the following notices to the library. It is
|
||||
safest to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least the
|
||||
"copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the library's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the library, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the
|
||||
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1990
|
||||
Ty Coon, President of Vice
|
||||
|
||||
That's all there is to it!
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
8
licenses/license_qb64.txt
Normal file
8
licenses/license_qb64.txt
Normal file
|
@ -0,0 +1,8 @@
|
|||
Copyright 2007-2022 Galleon & The QB64 Team
|
||||
Copyright 2022-2023 QB64 Phoenix Edition Team
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
23
licenses/license_radv2.txt
Normal file
23
licenses/license_radv2.txt
Normal file
|
@ -0,0 +1,23 @@
|
|||
From: Willy Reeve <shayde0@gmail.com>
|
||||
Sent: Sunday, 7 August, 2022 01:23 PM
|
||||
To: Samuel Gomes <v_2samg@hotmail.com>
|
||||
Cc: Carl Pettitt <carl@clonestudios.co.uk>
|
||||
Subject: Re: Contact from Reality website
|
||||
|
||||
Hi Samuel,
|
||||
|
||||
The player source code is Public Domain.
|
||||
|
||||
Shayde
|
||||
|
||||
On Fri, Aug 5, 2022 at 6:33 AM Reality website <rogue@3eality.com> wrote:
|
||||
Contact from the Reality website:
|
||||
Name: Samuel Gomes
|
||||
Email: v_2samg@hotmail.com
|
||||
Message:
|
||||
|
||||
RADv2 - great stuff! I am planning to integrate the included player code in my projects. Can you please
|
||||
let me know the license type for the player code? If there is one, putting it somewhere on the site or
|
||||
zip would be fantastic!
|
||||
|
||||
Thanks!
|
|
@ -1,11 +1,37 @@
|
|||
// Ogg Vorbis audio decoder - v1.05 - public domain
|
||||
// http://nothings.org/stb_vorbis/
|
||||
//
|
||||
// Written by Sean Barrett in 2007, last updated in 2014
|
||||
// Sponsored by RAD Game Tools.
|
||||
//
|
||||
// Placed in the public domain April 2007 by the author: no copyright
|
||||
// is claimed, and you may use it for any purpose you like.
|
||||
//
|
||||
// No warranty for any purpose is expressed or implied by the author (nor
|
||||
// by RAD Game Tools). Report bugs and send enhancements to the author.
|
||||
This software is available under 2 licenses -- choose whichever you prefer.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE A - MIT License
|
||||
Copyright (c) 2017 Sean Barrett
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE B - Public Domain (www.unlicense.org)
|
||||
This is free and unencumbered software released into the public domain.
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
|
||||
software, either in source code form or as a compiled binary, for any purpose,
|
||||
commercial or non-commercial, and by any means.
|
||||
In jurisdictions that recognize copyright laws, the author or authors of this
|
||||
software dedicate any and all copyright interest in the software to the public
|
||||
domain. We make this dedication for the benefit of the public at large and to
|
||||
the detriment of our heirs and successors. We intend this dedication to be an
|
||||
overt act of relinquishment in perpetuity of all present and future rights to
|
||||
this software under copyright law.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
|
17
licenses/license_tinymidiloader.txt
Normal file
17
licenses/license_tinymidiloader.txt
Normal file
|
@ -0,0 +1,17 @@
|
|||
Copyright (C) 2017, 2018, 2020 Bernhard Schelling
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
19
licenses/license_tinysoundfont.txt
Normal file
19
licenses/license_tinysoundfont.txt
Normal file
|
@ -0,0 +1,19 @@
|
|||
Copyright (C) 2017-2018 Bernhard Schelling (Based on SFZero, Copyright (C) 2012 Steve Folta, https://github.com/stevefolta/SFZero)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
|
@ -25,6 +25,7 @@ DIM SHARED MaxParallelProcesses AS _UNSIGNED LONG
|
|||
DIM SHARED ExtraCppFlags AS STRING, ExtraLinkerFlags AS STRING
|
||||
DIM SHARED StripDebugSymbols AS _UNSIGNED LONG
|
||||
DIM SHARED OptimizeCppProgram AS _UNSIGNED LONG
|
||||
DIM SHARED UseMiniaudioBackend AS _UNSIGNED LONG
|
||||
|
||||
ConfigFile$ = "internal/config.ini"
|
||||
iniFolderIndex$ = STR$(tempfolderindex)
|
||||
|
@ -535,5 +536,7 @@ MaxParallelProcesses = ReadWriteLongSettingValue&(compilerSettingsSection$, "Max
|
|||
ExtraCppFlags = ReadWriteStringSettingValue$(compilerSettingsSection$, "ExtraCppFlags", "")
|
||||
ExtraLinkerFlags = ReadWriteStringSettingValue$(compilerSettingsSection$, "ExtraLinkerFlags", "")
|
||||
|
||||
UseMiniaudioBackend = ReadWriteBooleanSettingValue%(compilerSettingsSection$, "UseMiniaudioBackend", -1)
|
||||
|
||||
'End of initial settings ------------------------------------------------------
|
||||
|
||||
|
|
|
@ -399,8 +399,8 @@ FUNCTION ide2 (ignore)
|
|||
menuDesc$(m, i - 1) = "Changes or customizes IDE color scheme"
|
||||
menu$(m, i) = "#Code Layout...": i = i + 1
|
||||
menuDesc$(m, i - 1) = "Changes auto-format features"
|
||||
menu$(m, i) = "C++ Co#mpiler Settings...": i = i + 1
|
||||
menuDesc$(m, i - 1) = "Change settings for compiling the C++ code"
|
||||
menu$(m, i) = "Co#mpiler Settings...": i = i + 1
|
||||
menuDesc$(m, i - 1) = "Change settings for compiling your code"
|
||||
menu$(m, i) = "-": i = i + 1
|
||||
menu$(m, i) = "#Language...": i = i + 1
|
||||
menuDesc$(m, i - 1) = "Changes code page to use with TTF fonts"
|
||||
|
@ -5103,7 +5103,7 @@ FUNCTION ide2 (ignore)
|
|||
GOTO ideloop
|
||||
END IF
|
||||
|
||||
IF menu$(m, s) = "C++ Co#mpiler Settings..." THEN
|
||||
IF menu$(m, s) = "Co#mpiler Settings..." THEN
|
||||
PCOPY 2, 0
|
||||
retval = ideCompilerSettingsBox
|
||||
IF retval THEN idechangemade = 1: idelayoutallow = 2: startPausedPending = 0 'recompile if options changed
|
||||
|
@ -15123,6 +15123,7 @@ FUNCTION ideCompilerSettingsBox
|
|||
DIM maxParallelTextBox AS LONG
|
||||
DIM extraCppFlagsTextBox AS LONG
|
||||
DIM extraLinkerFlagsTextBox AS LONG
|
||||
DIM useOldAudioBackend AS LONG
|
||||
sep = CHR$(0)
|
||||
'-------- end of generic dialog box header --------
|
||||
|
||||
|
@ -15185,6 +15186,15 @@ FUNCTION ideCompilerSettingsBox
|
|||
|
||||
y = y + 1 ' Blank line
|
||||
|
||||
i = i + 1
|
||||
useOldAudioBackend = i
|
||||
o(i).typ = 4 'check box
|
||||
y = y + 1: o(i).y = y
|
||||
o(i).nam = idenewtxt("#Use old audio backend (LGPL)")
|
||||
o(i).sel = NOT UseMiniaudioBackend
|
||||
|
||||
y = y + 1 ' Blank line
|
||||
|
||||
i = i + 1
|
||||
buttonsid = i
|
||||
o(i).typ = 3
|
||||
|
@ -15192,7 +15202,7 @@ FUNCTION ideCompilerSettingsBox
|
|||
o(i).txt = idenewtxt("#OK" + sep + "#Cancel")
|
||||
o(i).dft = 1
|
||||
|
||||
idepar p, 60, y, "C++ Compiler Settings"
|
||||
idepar p, 60, y, "Compiler Settings"
|
||||
'-------- end of init --------
|
||||
|
||||
'-------- generic init --------
|
||||
|
@ -15289,6 +15299,12 @@ FUNCTION ideCompilerSettingsBox
|
|||
WriteConfigSetting generalSettingsSection$, "DebugInfo", BoolToTFString$(Include_GDB_Debugging_Info)
|
||||
END IF
|
||||
|
||||
v% = o(useOldAudioBackend).sel: IF v% <> 0 THEN v% = -1
|
||||
IF UseMiniaudioBackend <> NOT v% THEN
|
||||
UseMiniaudioBackend = NOT v%
|
||||
WriteConfigSetting compilerSettingsSection$, "UseMiniaudioBackend", BoolToTFString$(UseMiniaudioBackend)
|
||||
END IF
|
||||
|
||||
v% = VAL(idetxt(o(maxParallelTextBox).txt))
|
||||
IF v% > 0 AND v% <> MaxParallelProcesses THEN
|
||||
MaxParallelProcesses = v%
|
||||
|
|
|
@ -12366,15 +12366,21 @@ IF DEPENDENCY(DEPENDENCY_ICON) THEN makedeps$ = makedeps$ + " DEP_ICON=y"
|
|||
IF DEPENDENCY(DEPENDENCY_SCREENIMAGE) THEN makedeps$ = makedeps$ + " DEP_SCREENIMAGE=y"
|
||||
IF DEPENDENCY(DEPENDENCY_LOADFONT) THEN makedeps$ = makedeps$ + " DEP_FONT=y"
|
||||
IF DEPENDENCY(DEPENDENCY_DEVICEINPUT) THEN makedeps$ = makedeps$ + " DEP_DEVICEINPUT=y"
|
||||
IF DEPENDENCY(DEPENDENCY_AUDIO_DECODE) THEN makedeps$ = makedeps$ + " DEP_AUDIO_DECODE=y"
|
||||
IF DEPENDENCY(DEPENDENCY_AUDIO_CONVERSION) THEN makedeps$ = makedeps$ + " DEP_AUDIO_CONVERSION=y"
|
||||
IF DEPENDENCY(DEPENDENCY_AUDIO_DECODE) THEN makedeps$ = makedeps$ + " DEP_AUDIO_DECODE=y"
|
||||
IF DEPENDENCY(DEPENDENCY_AUDIO_OUT) THEN makedeps$ = makedeps$ + " DEP_AUDIO_OUT=y"
|
||||
IF DEPENDENCY(DEPENDENCY_ZLIB) THEN makedeps$ = makedeps$ + " DEP_ZLIB=y"
|
||||
IF inline_DATA = 0 AND DataOffset THEN makedeps$ = makedeps$ + " DEP_DATA=y"
|
||||
IF Console THEN makedeps$ = makedeps$ + " DEP_CONSOLE=y"
|
||||
IF ExeIconSet OR VersionInfoSet THEN makedeps$ = makedeps$ + " DEP_ICON_RC=y"
|
||||
|
||||
IF UseMiniaudioBackend = 0 THEN
|
||||
IF DEPENDENCY(DEPENDENCY_AUDIO_DECODE) THEN makedeps$ = makedeps$ + " DEP_AUDIO_DECODE=y"
|
||||
IF DEPENDENCY(DEPENDENCY_AUDIO_CONVERSION) THEN makedeps$ = makedeps$ + " DEP_AUDIO_CONVERSION=y"
|
||||
IF DEPENDENCY(DEPENDENCY_AUDIO_OUT) THEN makedeps$ = makedeps$ + " DEP_AUDIO_OUT=y"
|
||||
ELSE
|
||||
IF DEPENDENCY(DEPENDENCY_AUDIO_DECODE) OR DEPENDENCY(DEPENDENCY_AUDIO_CONVERSION) OR DEPENDENCY(DEPENDENCY_AUDIO_OUT) THEN
|
||||
makedeps$ = makedeps$ + " DEP_AUDIO_MINIAUDIO=y"
|
||||
END IF
|
||||
END IF
|
||||
|
||||
IF tempfolderindex > 1 THEN makedeps$ = makedeps$ + " TEMP_ID=" + str2$(tempfolderindex)
|
||||
|
||||
CxxFlagsExtra$ = ExtraCppFlags
|
||||
|
|
Loading…
Reference in a new issue