1
1
Fork 0
mirror of https://github.com/QB64-Phoenix-Edition/QB64pe.git synced 2024-06-26 17:10:38 +00:00

Add initial MIDI language support

This adds MIDI support to the language as a new unstable feature. There
are two new metacommands that come with this:

$Unstable: Midi
$MidiSoundFont: [Default|"filename"]

The $Unstable command is required to be able to use any of the other
commands, and just signifies that this is not a full part of the
language yet and may change in breaking ways before the API is
finalized.

The $MidiSoundFont command enables MIDI support in the compiled program,
and also specifies what sound font to use to play MIDI files. "Default"
will make use of the soundfont placed at
'./internal/support/default_soundfont.sf2', and otherwise a filename can
be specified to use any soundfont wanted.

In either case, the selected sound font is compiled into the executable
and then loaded at runtime.

Fixes: #115
This commit is contained in:
Matthew Kilgore 2022-08-30 21:29:33 -04:00
parent 65db95c876
commit 2b3403745c
31 changed files with 464 additions and 2904 deletions

View file

@ -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/extras/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

View file

@ -27,13 +27,12 @@
# define uint8 uint8_t
# endif
# define ptrszint intptr_t
# define uptrszint uintptr_t
# ifdef QB64_64
# define ptrszint int64
# define uptrszint uint64
# define ptrsz 8
# else
# define ptrszint int32
# define uptrszint uint32
# define ptrsz 4
# endif
#endif

View file

@ -3,48 +3,24 @@ 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)
MINIAUDIO_OBJS := $(MINIAUDIO_REAL_OBJS) $(MA_VTABLES_OBJS) $(LIBXMP_LIB)
ifdef DEP_AUDIO_DECODE_MIDI
MINIAUDIO_OBJS += $(MIDI_MA_VTABLES_OBJS)
else
MINIAUDIO_OBJS += $(MIDI_MA_VTABLES_STUB_OBJS)
endif
else
MINIAUDIO_OBJS := $(MINIAUDIO_STUB_OBJS)
endif
@ -52,7 +28,4 @@ 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)

View file

@ -0,0 +1,82 @@
LIBXMP_SRCS := \
common.c \
control.c \
dataio.c \
effects.c \
filter.c \
format.c \
hio.c \
it_load.c \
itsex.c \
lfo.c \
load.c \
load_helpers.c \
md5.c \
memio.c \
misc.c \
mix_all.c \
mixer.c \
mod_load.c \
period.c \
player.c \
read_event.c \
s3m_load.c \
sample.c \
scan.c \
smix.c \
virtual.c \
win32.c \
xm_load.c
LIBXMP_OBJS += $(patsubst %.c,$(PATH_INTERNAL_C)/parts/audio/extras/libxmp-lite/%.o,$(LIBXMP_SRCS))
LIBXMP_LIB := $(PATH_INTERNAL_C)/parts/audio/extras/libxmp-lite.a
$(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 $@
$(LIBXMP_LIB): $(LIBXMP_OBJS)
$(AR) rcs $@ $^
MA_VTABLES_SRCS := \
mod_ma_vtable.cpp \
radv2_ma_vtable.cpp
MA_VTABLES_OBJS := $(patsubst %.cpp,$(PATH_INTERNAL_C)/parts/audio/extras/%.o,$(MA_VTABLES_SRCS))
MIDI_MA_VTABLE_SRCS := midi_ma_vtable.cpp
MIDI_MA_VTABLE_STUB_SRCS := midi_ma_vtable_stub.cpp
MIDI_MA_VTABLES_OBJS := $(patsubst %.cpp,$(PATH_INTERNAL_C)/parts/audio/extras/%.o,$(MIDI_MA_VTABLE_SRCS))
MIDI_MA_VTABLES_STUB_OBJS := $(patsubst %.cpp,$(PATH_INTERNAL_C)/parts/audio/extras/%.o,$(MIDI_MA_VTABLE_STUB_SRCS))
# If we're using MIDI, then there should be a soundfont available to be linked in
MIDI_MA_VTABLES_OBJS += $(PATH_INTERNAL_TEMP)/soundfont.o
# Turn the soundfont into a linkable object
ifeq ($(OS),win)
# Fairly ugly, but we have to get the right relative path to objcopy on Windows
# to make the whole thing work out
$(PATH_INTERNAL_TEMP)/soundfont.o: $(PATH_INTERNAL_TEMP)/soundfont.sf2
cd $(call FIXPATH,$(PATH_INTERNAL_TEMP)) && ..\..\$(OBJCOPY) -Ibinary $(OBJCOPY_FLAGS) soundfont.sf2 soundfont.o
else
ifeq ($(OS),osx)
# Mac OS does not ship an objcopy implementation for some reason
# We're instead using xxd to produce a source file, and compiling it
$(PATH_INTERNAL_TEMP)/soundfont.c: $(PATH_INTERNAL_TEMP)/soundfont.sf2
cd $(call FIXPATH,$(PATH_INTERNAL_TEMP)) && xxd --include soundfont.sf2 > soundfont.c
$(PATH_INTERNAL_TEMP)/soundfont.o: $(PATH_INTERNAL_TEMP)/soundfont.c
$(CC) $< -c -o $@
else
# The "cd" is used to make the symbol name predictable and not dependent upon
# the "PATH_INTERNAL_TEMP" value
$(PATH_INTERNAL_TEMP)/soundfont.o: $(PATH_INTERNAL_TEMP)/soundfont.sf2
cd $(call FIXPATH,$(PATH_INTERNAL_TEMP)) && $(OBJCOPY) -Ibinary $(OBJCOPY_FLAGS) soundfont.sf2 soundfont.o
endif
endif
CLEAN_LIST += $(LIBXMP_LIB) $(LIBXMP_OBJS) $(MA_VTABLES_OBJS) $(MIDI_MA_VTABLES_OBJS) $(MIDI_MA_VTABLES_STUB_OBJS)

View file

@ -18,23 +18,55 @@
//
//-----------------------------------------------------------------------------------------------------
#pragma once
//-----------------------------------------------------------------------------------------------------
// HEADER FILES
//-----------------------------------------------------------------------------------------------------
#include "libqb-common.h"
#include <string.h>
#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"
#include "vtables.h"
extern "C" {
// These symbols reference a soundfont compiled into the program
//
// We provide a macro to expand to the correct symbol name
#if defined(QB64_WINDOWS) && defined(QB64_32)
// On 32-bit Windows, we use objcopy, and the symbols do not have an
// underscore prefix
extern char binary_soundfont_sf2_start[];
extern char binary_soundfont_sf2_end[];
# define SOUNDFONT_BIN binary_soundfont_sf2_start
# define SOUNDFONT_SIZE (binary_soundfont_sf2_end - binary_soundfont_sf2_start)
#elif defined(QB64_WINDOWS) || defined(QB64_LINUX)
// On Linux and 64-bit Windows, we use objcopy, and the symbols do have an
// underscore prefix.
extern char _binary_soundfont_sf2_start[];
extern char _binary_soundfont_sf2_end[];
# define SOUNDFONT_BIN _binary_soundfont_sf2_start
# define SOUNDFONT_SIZE (_binary_soundfont_sf2_end - _binary_soundfont_sf2_start)
#else
// On Mac OS we use xxd, which gives an array and size
extern unsigned char soundfont_sf2[];
extern unsigned int soundfont_sf2_len;
# define SOUNDFONT_BIN soundfont_sf2
# define SOUNDFONT_SIZE soundfont_sf2_len
#endif
}
//-----------------------------------------------------------------------------------------------------
struct ma_tsf {
@ -83,7 +115,7 @@ static ma_result ma_tsf_get_data_format(ma_tsf *pTsf, ma_format *pFormat, ma_uin
*pSampleRate = 0;
}
if (pChannelMap != NULL) {
MA_ZERO_MEMORY(pChannelMap, sizeof(*pChannelMap) * channelMapCap);
memset(pChannelMap, 0, sizeof(*pChannelMap) * channelMapCap);
}
if (pTsf == NULL) {
@ -302,7 +334,7 @@ static ma_result ma_tsf_init_internal(const ma_decoding_backend_config *pConfig,
return MA_INVALID_ARGS;
}
MA_ZERO_OBJECT(pTsf);
memset(pTsf, 0, sizeof(&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) {
@ -322,6 +354,15 @@ static ma_result ma_tsf_init_internal(const ma_decoding_backend_config *pConfig,
return MA_SUCCESS;
}
ma_result ma_tsf_load_memory(ma_tsf *pTsf)
{
// Attempt to load a SoundFont from memory
pTsf->tinySoundFont = tsf_load_memory(SOUNDFONT_BIN, SOUNDFONT_SIZE);
// Return failue if loading from memory also failed. This should not happen though
return pTsf->tinySoundFont? MA_SUCCESS: MA_OUT_OF_MEMORY;
}
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;
@ -370,18 +411,11 @@ static ma_result ma_tsf_init(ma_read_proc onRead, ma_seek_proc onSeek, ma_tell_p
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;
}
// Load soundfont
result = ma_tsf_load_memory(pTsf);
if (result != MA_SUCCESS) {
delete[] tune;
return result;
}
// Initialize preset on special 10th MIDI channel to use percussion sound bank (128) if available
@ -428,18 +462,10 @@ static ma_result ma_tsf_init_file(const char *pFilePath, const ma_decoding_backe
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;
}
}
// Load soundfont
result = ma_tsf_load_memory(pTsf);
if (result != MA_SUCCESS)
return result;
// 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);
@ -540,4 +566,6 @@ static void ma_decoding_backend_uninit__tsf(void *pUserData, ma_data_source *pBa
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};
ma_decoding_backend_vtable *midi_ma_vtable = &ma_decoding_backend_vtable_tsf;
//-----------------------------------------------------------------------------------------------------

View file

@ -0,0 +1,4 @@
#include "vtables.h"
ma_decoding_backend_vtable *midi_ma_vtable = NULL;

View file

@ -15,14 +15,18 @@
//
//-----------------------------------------------------------------------------------------------------
#pragma once
//-----------------------------------------------------------------------------------------------------
// HEADER FILES
//-----------------------------------------------------------------------------------------------------
#include <stdio.h>
#include <string.h>
#include "../miniaudio.h"
#define BUILDING_STATIC 1
#include "libxmp-lite/xmp.h"
#include "vtables.h"
//-----------------------------------------------------------------------------------------------------
struct ma_modplay {
@ -65,7 +69,7 @@ static ma_result ma_modplay_get_data_format(ma_modplay *pModplay, ma_format *pFo
*pSampleRate = 0;
}
if (pChannelMap != NULL) {
MA_ZERO_MEMORY(pChannelMap, sizeof(*pChannelMap) * channelMapCap);
memset(pChannelMap, 0, sizeof(*pChannelMap) * channelMapCap);
}
if (pModplay == NULL) {
@ -254,7 +258,7 @@ static ma_result ma_modplay_init_internal(const ma_decoding_backend_config *pCon
return MA_INVALID_ARGS;
}
MA_ZERO_OBJECT(pModplay);
memset(pModplay, 0, sizeof(*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) {
@ -498,8 +502,10 @@ static void ma_decoding_backend_uninit__modplay(void *pUserData, ma_data_source
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,
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};
ma_decoding_backend_vtable *mod_ma_vtable = &ma_decoding_backend_vtable_modplay;
//-----------------------------------------------------------------------------------------------------

View file

@ -39,16 +39,19 @@
//
//-----------------------------------------------------------------------------------------------------
#pragma once
//-----------------------------------------------------------------------------------------------------
// HEADER FILES
//-----------------------------------------------------------------------------------------------------
#include <string.h>
#include <stdio.h>
#include "../miniaudio.h"
#include "radv2/opal.cpp"
#define RAD_DETECT_REPEATS 1
#include "radv2/player20.cpp"
#include "radv2/validate20.cpp"
#include "vtables.h"
//-----------------------------------------------------------------------------------------------------
struct ma_radv2 {
@ -96,7 +99,7 @@ static ma_result ma_radv2_get_data_format(ma_radv2 *pRadv2, ma_format *pFormat,
*pSampleRate = 0;
}
if (pChannelMap != NULL) {
MA_ZERO_MEMORY(pChannelMap, sizeof(*pChannelMap) * channelMapCap);
memset(pChannelMap, 0, sizeof(*pChannelMap) * channelMapCap);
}
if (!pRadv2) {
@ -290,7 +293,7 @@ static ma_result ma_radv2_init_internal(const ma_decoding_backend_config *pConfi
return MA_INVALID_ARGS;
}
MA_ZERO_OBJECT(pRadv2);
memset(pRadv2, 0, sizeof(*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) {
@ -606,4 +609,6 @@ static ma_decoding_backend_vtable ma_decoding_backend_vtable_radv2 = {ma_decodin
NULL, /* onInitFileW() */
NULL, /* onInitMemory() */
ma_decoding_backend_uninit__radv2};
ma_decoding_backend_vtable *radv2_ma_vtable = &ma_decoding_backend_vtable_radv2;
//-----------------------------------------------------------------------------------------------------

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,10 @@
#ifndef INCLUDE_PARTS_AUDIO_EXTRAS_VTABLES_H
#define INCLUDE_PARTS_AUDIO_EXTRAS_VTABLES_H
#include "../miniaudio.h"
extern ma_decoding_backend_vtable *midi_ma_vtable;
extern ma_decoding_backend_vtable *mod_ma_vtable;
extern ma_decoding_backend_vtable *radv2_ma_vtable;
#endif

View file

@ -4234,6 +4234,7 @@ Retrieves the version of miniaudio as a string which can be useful for logging p
MA_API const char* ma_version_string(void);
/**************************************************************************************************************************************************************
Logging
@ -11017,6 +11018,89 @@ MA_API ma_bool32 ma_sound_group_is_playing(const ma_sound_group* pGroup);
MA_API ma_uint64 ma_sound_group_get_time_in_pcm_frames(const ma_sound_group* pGroup);
#endif /* MA_NO_ENGINE */
/*
* The below functions used to be private to miniaudio. They were moved out of
* the implementation section to allow us to make use of them in our decoders.
*/
#if !defined(_MSC_VER) && !defined(__DMC__)
#include <strings.h> /* For strcasecmp(). */
#endif
static const char* ma_path_file_name(const char* path)
{
const char* fileName;
if (path == NULL) {
return NULL;
}
fileName = path;
/* We just loop through the path until we find the last slash. */
while (path[0] != '\0') {
if (path[0] == '/' || path[0] == '\\') {
fileName = path;
}
path += 1;
}
/* At this point the file name is sitting on a slash, so just move forward. */
while (fileName[0] != '\0' && (fileName[0] == '/' || fileName[0] == '\\')) {
fileName += 1;
}
return fileName;
}
static const char* ma_path_extension(const char* path)
{
const char* extension;
const char* lastOccurance;
if (path == NULL) {
path = "";
}
extension = ma_path_file_name(path);
lastOccurance = NULL;
/* Just find the last '.' and return. */
while (extension[0] != '\0') {
if (extension[0] == '.') {
extension += 1;
lastOccurance = extension;
}
extension += 1;
}
return (lastOccurance != NULL) ? lastOccurance : extension;
}
static ma_bool32 ma_path_extension_equal(const char* path, const char* extension)
{
const char* ext1;
const char* ext2;
if (path == NULL || extension == NULL) {
return MA_FALSE;
}
ext1 = extension;
ext2 = ma_path_extension(path);
#if defined(_MSC_VER) || defined(__DMC__)
return _stricmp(ext1, ext2) == 0;
#else
return strcasecmp(ext1, ext2) == 0;
#endif
}
#ifndef MA_DEFAULT_SAMPLE_RATE
#define MA_DEFAULT_SAMPLE_RATE 48000
#endif
#ifdef __cplusplus
}
#endif
@ -61739,34 +61823,6 @@ MA_API ma_result ma_decoder_init_memory(const void* pData, size_t dataSize, cons
#define MA_HAS_PATH_API
#endif
#if defined(MA_HAS_PATH_API)
static const char* ma_path_file_name(const char* path)
{
const char* fileName;
if (path == NULL) {
return NULL;
}
fileName = path;
/* We just loop through the path until we find the last slash. */
while (path[0] != '\0') {
if (path[0] == '/' || path[0] == '\\') {
fileName = path;
}
path += 1;
}
/* At this point the file name is sitting on a slash, so just move forward. */
while (fileName[0] != '\0' && (fileName[0] == '/' || fileName[0] == '\\')) {
fileName += 1;
}
return fileName;
}
static const wchar_t* ma_path_file_name_w(const wchar_t* path)
{
const wchar_t* fileName;
@ -61794,32 +61850,6 @@ static const wchar_t* ma_path_file_name_w(const wchar_t* path)
return fileName;
}
static const char* ma_path_extension(const char* path)
{
const char* extension;
const char* lastOccurance;
if (path == NULL) {
path = "";
}
extension = ma_path_file_name(path);
lastOccurance = NULL;
/* Just find the last '.' and return. */
while (extension[0] != '\0') {
if (extension[0] == '.') {
extension += 1;
lastOccurance = extension;
}
extension += 1;
}
return (lastOccurance != NULL) ? lastOccurance : extension;
}
static const wchar_t* ma_path_extension_w(const wchar_t* path)
{
const wchar_t* extension;
@ -61845,26 +61875,6 @@ static const wchar_t* ma_path_extension_w(const wchar_t* path)
return (lastOccurance != NULL) ? lastOccurance : extension;
}
static ma_bool32 ma_path_extension_equal(const char* path, const char* extension)
{
const char* ext1;
const char* ext2;
if (path == NULL || extension == NULL) {
return MA_FALSE;
}
ext1 = extension;
ext2 = ma_path_extension(path);
#if defined(_MSC_VER) || defined(__DMC__)
return _stricmp(ext1, ext2) == 0;
#else
return strcasecmp(ext1, ext2) == 0;
#endif
}
static ma_bool32 ma_path_extension_equal_w(const wchar_t* path, const wchar_t* extension)
{
const wchar_t* ext1;
@ -61906,7 +61916,6 @@ static ma_bool32 ma_path_extension_equal_w(const wchar_t* path, const wchar_t* e
}
#endif
}
#endif /* MA_HAS_PATH_API */

View file

@ -29,12 +29,8 @@
// 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"
#include "extras/vtables.h"
//-----------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------
@ -43,8 +39,11 @@
// 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};
static ma_decoding_backend_vtable *maCustomBackendVTables[] = {
radv2_ma_vtable,
midi_ma_vtable,
mod_ma_vtable,
};
//-----------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------

Binary file not shown.

View file

@ -898,6 +898,13 @@ DIM controlvalue(1000) AS LONG
DIM controlstate(1000) AS INTEGER
DIM SHARED controlref(1000) AS LONG 'the line number the control was created on
'
' Collection of flags indicating which unstable features should be used during compilation
'
REDIM SHARED unstableFlags(1) AS _BYTE
DIM UNSTABLE_MIDI AS LONG
UNSTABLE_MIDI = 1
@ -1612,7 +1619,18 @@ udtetypesize(i2) = 0 'tsize
udtenext(i3) = i2
udtenext(i2) = 0
' Reset all unstable flags
REDIM SHARED unstableFlags(1) AS _BYTE
' Indicates if a MIDI sound font was selected
'
' Captures both the line number and line contents for error reporting later-on
' in the compilation process
MidiSoundFontSet = 0
MidiSoundFontLine$ = ""
' If MidiSoundFont$ is blank, then the default is used
MidiSoundFont$ = ""
@ -1891,6 +1909,25 @@ DO
GOTO finishedlinepp
END IF
' We check for Unstable flags during the preprocessing step because it
' impacts what valid commands there are in all the other steps
IF LEFT$(temp$, 10) = "$UNSTABLE:" THEN
token$ = UCASE$(LTRIM$(RTRIM$(MID$(temp$, 11))))
SELECT CASE token$
CASE "MIDI"
IF NOT UseMiniaudioBackend THEN
a$ = "Midi is not supported with the old OpenAL audio backend."
GOTO errmes
END IF
unstableFlags(UNSTABLE_MIDI) = -1
CASE ELSE
a$ = "Unrecognized unstable flag " + AddQuotes$(token$)
GOTO errmes
END SELECT
END IF
cwholeline$ = wholeline$
wholeline$ = eleucase$(wholeline$) '********REMOVE THIS LINE LATER********
@ -3403,6 +3440,72 @@ DO
GOTO finishedline2
END IF
IF LEFT$(a3u$, 10) = "$UNSTABLE:" THEN
layout$ = SCase("$Unstable:")
token$ = LTRIM$(RTRIM$(MID$(a3u$, 11)))
SELECT CASE token$
CASE "MIDI"
layout$ = layout$ + SCase$("Midi")
END SELECT
GOTO finishednonexec
END IF
IF unstableFlags(UNSTABLE_MIDI) THEN
IF LEFT$(a3u$, 15) = "$MIDISOUNDFONT:" THEN
IF MidiSoundFontSet THEN
a$ = "$MIDISOUNDFONT already defined"
GOTO errmes
END IF
layout$ = SCase$("$MidiSoundFont:")
MidiSoundFont$ = LTRIM$(RTRIM$(MID$(a3$, 16)))
IF MID$(MidiSoundFont$, 1, 1) = CHR$(34) THEN
' We have a quoted filename, verify it is valid
' We don't touch the filename in the formatting
layout$ = layout$ + MidiSoundFont$
' Strip the leading quote
MidiSoundFont$ = MID$(MidiSoundFont$, 2)
' Verify that there is a quote character at the end
IF INSTR(MidiSoundFont$, CHR$(34)) = 0 THEN a$ = "Expected " + CHR$(34) + " character at the end of the file name": GOTO errmes
' Verify there are no extra characters after end quote
IF INSTR(MidiSoundFont$, CHR$(34)) <> LEN(MidiSoundFont$) THEN a$ = "Unexpected characters after the quoted file name": GOTO errmes
MidiSoundFont$ = MID$(MidiSoundFont$, 1, LEN(MidiSoundFont$) - 1)
IF NOT _FILEEXISTS(MidiSoundFont$) THEN
a$ = "Soundfont file " + AddQuotes$(MidiSoundFont$) + " could not be found!"
GOTO errmes
END IF
ELSE
' Constant values, only one for now
SELECT CASE UCASE$(MidiSoundFont$)
CASE "DEFAULT"
layout$ = layout$ + SCase$("Default")
' Clear MidiSoundFont$ to indicate the default should be used
MidiSoundFont$ = ""
CASE ELSE
a$ = "Unrecognized Soundfont option " + AddQuotes$(MidiSoundFont$)
GOTO errmes
END SELECT
END IF
MidiSoundFontSet = linenumber
MidiSoundFontLine$ = layout$
GOTO finishednonexec
END IF
END IF
END IF 'QB64 Metacommands
IF ExecLevel(ExecCounter) THEN
@ -12342,6 +12445,22 @@ END IF
'actions are performed on the disk based files
WriteBuffers ""
IF MidiSoundFontSet THEN
linenumber = MidiSoundFontSet
wholeline = MidiSoundFontLine$
IF MidiSoundFont$ = "" THEN
MidiSoundFont$ = "internal/support/default_soundfont.sf2"
END IF
ON ERROR GOTO qberror_test
errNo = CopyFile&(MidiSoundFont$, tmpdir$ + "soundfont.sf2")
IF errNo <> 0 THEN a$ = "Error copying " + QuotedFilename$(MidiSoundFont$) + " to temp directory": GOTO errmes
ON ERROR GOTO qberror
END IF
'Update dependencies
o$ = LCASE$(os$)
@ -12371,7 +12490,7 @@ 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 NOT UseMiniaudioBackend 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"
@ -12381,6 +12500,8 @@ ELSE
END IF
END IF
IF MidiSoundFontSet THEN makedeps$ = makedeps$ + " DEP_AUDIO_DECODE_MIDI=y"
IF tempfolderindex > 1 THEN makedeps$ = makedeps$ + " TEMP_ID=" + str2$(tempfolderindex)
CxxFlagsExtra$ = ExtraCppFlags

View file

@ -4,5 +4,5 @@ listOfKeywords$ = listOfKeywords$ + "_ERRORLINE@_ERRORMESSAGE$@_EXIT@_EXPLICIT@_
listOfKeywords$ = listOfKeywords$ + "_GLCOPYTEXSUBIMAGE2D@_GLCULLFACE@_GLDELETELISTS@_GLDELETETEXTURES@_GLDEPTHFUNC@_GLDEPTHMASK@_GLDEPTHRANGE@_GLDISABLE@_GLDISABLECLIENTSTATE@_GLDRAWARRAYS@_GLDRAWBUFFER@_GLDRAWELEMENTS@_GLDRAWPIXELS@_GLEDGEFLAG@_GLEDGEFLAGPOINTER@_GLEDGEFLAGV@_GLENABLE@_GLENABLECLIENTSTATE@_GLEND@_GLENDLIST@_GLEVALCOORD1D@_GLEVALCOORD1DV@_GLEVALCOORD1F@_GLEVALCOORD1FV@_GLEVALCOORD2D@_GLEVALCOORD2DV@_GLEVALCOORD2F@_GLEVALCOORD2FV@_GLEVALMESH1@_GLEVALMESH2@_GLEVALPOINT1@_GLEVALPOINT2@_GLFEEDBACKBUFFER@_GLFINISH@_GLFLUSH@_GLFOGF@_GLFOGFV@_GLFOGI@_GLFOGIV@_GLFRONTFACE@_GLFRUSTUM@_GLGENLISTS@_GLGENTEXTURES@_GLGETBOOLEANV@_GLGETCLIPPLANE@_GLGETDOUBLEV@_GLGETERROR@_GLGETFLOATV@_GLGETINTEGERV@_GLGETLIGHTFV@_GLGETLIGHTIV@_GLGETMAPDV@_GLGETMAPFV@_GLGETMAPIV@_GLGETMATERIALFV@_GLGETMATERIALIV@_GLGETPIXELMAPFV@_GLGETPIXELMAPUIV@_GLGETPIXELMAPUSV@_GLGETPOINTERV@_GLGETPOLYGONSTIPPLE@_GLGETSTRING@_GLGETTEXENVFV@_GLGETTEXENVIV@_GLGETTEXGENDV@_GLGETTEXGENFV@_GLGETTEXGENIV@_GLGETTEXIMAGE@_GLGETTEXLEVELPARAMETERFV@_GLGETTEXLEVELPARAMETERIV@_GLGETTEXPARAMETERFV@_GLGETTEXPARAMETERIV@_GLHINT@_GLINDEXMASK@_GLINDEXPOINTER@_GLINDEXD@_GLINDEXDV@_GLINDEXF@_GLINDEXFV@_GLINDEXI@_GLINDEXIV@_GLINDEXS@_GLINDEXSV@_GLINDEXUB@_GLINDEXUBV@_GLINITNAMES@_GLINTERLEAVEDARRAYS@_GLISENABLED@_GLISLIST@_GLISTEXTURE@_GLLIGHTMODELF@_GLLIGHTMODELFV@_GLLIGHTMODELI@_GLLIGHTMODELIV@_GLLIGHTF@_GLLIGHTFV@_GLLIGHTI@_GLLIGHTIV@_GLLINESTIPPLE@_GLLINEWIDTH@_GLLISTBASE@_GLLOADIDENTITY@_GLLOADMATRIXD@_GLLOADMATRIXF@_GLLOADNAME@_GLLOGICOP@_GLMAP1D@_GLMAP1F@_GLMAP2D@_GLMAP2F@_GLMAPGRID1D@_GLMAPGRID1F@_GLMAPGRID2D@_GLMAPGRID2F@_GLMATERIALF@_GLMATERIALFV@_GLMATERIALI@_GLMATERIALIV@_GLMATRIXMODE@_GLMULTMATRIXD@_GLMULTMATRIXF@_GLNEWLIST@_GLNORMAL3B@_GLNORMAL3BV@_GLNORMAL3D@_GLNORMAL3DV@_GLNORMAL3F@_GLNORMAL3FV@_GLNORMAL3I@_GLNORMAL3IV@_GLNORMAL3S@_GLNORMAL3SV@_GLNORMALPOINTER@_GLORTHO@_GLPASSTHROUGH@_GLPIXELMAPFV@_GLPIXELMAPUIV@_GLPIXELMAPUSV@_GLPIXELSTOREF@_GLPIXELSTOREI@_GLPIXELTRANSFERF@_GLPIXELTRANSFERI@_GLPIXELZOOM@_GLPOINTSIZE@_GLPOLYGONMODE@_GLPOLYGONOFFSET@_GLPOLYGONSTIPPLE@"
listOfKeywords$ = listOfKeywords$ + "_GLPOPATTRIB@_GLPOPCLIENTATTRIB@_GLPOPMATRIX@_GLPOPNAME@_GLPRIORITIZETEXTURES@_GLPUSHATTRIB@_GLPUSHCLIENTATTRIB@_GLPUSHMATRIX@_GLPUSHNAME@_GLRASTERPOS2D@_GLRASTERPOS2DV@_GLRASTERPOS2F@_GLRASTERPOS2FV@_GLRASTERPOS2I@_GLRASTERPOS2IV@_GLRASTERPOS2S@_GLRASTERPOS2SV@_GLRASTERPOS3D@_GLRASTERPOS3DV@_GLRASTERPOS3F@_GLRASTERPOS3FV@_GLRASTERPOS3I@_GLRASTERPOS3IV@_GLRASTERPOS3S@_GLRASTERPOS3SV@_GLRASTERPOS4D@_GLRASTERPOS4DV@_GLRASTERPOS4F@_GLRASTERPOS4FV@_GLRASTERPOS4I@_GLRASTERPOS4IV@_GLRASTERPOS4S@_GLRASTERPOS4SV@_GLREADBUFFER@_GLREADPIXELS@_GLRECTD@_GLRECTDV@_GLRECTF@_GLRECTFV@_GLRECTI@_GLRECTIV@_GLRECTS@_GLRECTSV@_GLRENDERMODE@_GLROTATED@_GLROTATEF@_GLSCALED@_GLSCALEF@_GLSCISSOR@_GLSELECTBUFFER@_GLSHADEMODEL@_GLSTENCILFUNC@_GLSTENCILMASK@_GLSTENCILOP@_GLTEXCOORD1D@_GLTEXCOORD1DV@_GLTEXCOORD1F@_GLTEXCOORD1FV@_GLTEXCOORD1I@_GLTEXCOORD1IV@_GLTEXCOORD1S@_GLTEXCOORD1SV@_GLTEXCOORD2D@_GLTEXCOORD2DV@_GLTEXCOORD2F@_GLTEXCOORD2FV@_GLTEXCOORD2I@_GLTEXCOORD2IV@_GLTEXCOORD2S@_GLTEXCOORD2SV@_GLTEXCOORD3D@_GLTEXCOORD3DV@_GLTEXCOORD3F@_GLTEXCOORD3FV@_GLTEXCOORD3I@_GLTEXCOORD3IV@_GLTEXCOORD3S@_GLTEXCOORD3SV@_GLTEXCOORD4D@_GLTEXCOORD4DV@_GLTEXCOORD4F@_GLTEXCOORD4FV@_GLTEXCOORD4I@_GLTEXCOORD4IV@_GLTEXCOORD4S@_GLTEXCOORD4SV@_GLTEXCOORDPOINTER@_GLTEXENVF@_GLTEXENVFV@_GLTEXENVI@_GLTEXENVIV@_GLTEXGEND@_GLTEXGENDV@_GLTEXGENF@_GLTEXGENFV@_GLTEXGENI@_GLTEXGENIV@_GLTEXIMAGE1D@_GLTEXIMAGE2D@_GLTEXPARAMETERF@_GLTEXPARAMETERFV@_GLTEXPARAMETERI@_GLTEXPARAMETERIV@_GLTEXSUBIMAGE1D@_GLTEXSUBIMAGE2D@_GLTRANSLATED@_GLTRANSLATEF@_GLVERTEX2D@_GLVERTEX2DV@_GLVERTEX2F@_GLVERTEX2FV@_GLVERTEX2I@_GLVERTEX2IV@_GLVERTEX2S@_GLVERTEX2SV@_GLVERTEX3D@_GLVERTEX3DV@_GLVERTEX3F@_GLVERTEX3FV@_GLVERTEX3I@_GLVERTEX3IV@_GLVERTEX3S@_GLVERTEX3SV@_GLVERTEX4D@_GLVERTEX4DV@_GLVERTEX4F@_GLVERTEX4FV@_GLVERTEX4I@_GLVERTEX4IV@_GLVERTEX4S@_GLVERTEX4SV@_GLVERTEXPOINTER@_GLVIEWPORT@SMOOTH@STRETCH@_ANTICLOCKWISE@_BEHIND@_CLEAR@_FILLBACKGROUND@_GLUPERSPECTIVE@_HARDWARE@_HARDWARE1@_KEEPBACKGROUND@_NONE@_OFF@_ONLY@_ONLYBACKGROUND@_ONTOP@_SEAMLESS@_SMOOTH@_SMOOTHSHRUNK@_SMOOTHSTRETCHED@"
listOfKeywords$ = listOfKeywords$ + "_SOFTWARE@_SQUAREPIXELS@_STRETCH@_ALLOWFULLSCREEN@_ALL@_ECHO@_INSTRREV@_TRIM$@_ACCEPTFILEDROP@_FINISHDROP@_TOTALDROPPEDFILES@_DROPPEDFILE@_DROPPEDFILE$@_SHR@_SHL@_ROR@_ROL@" ' a740g: added ROR & ROL
listOfKeywords$ = listOfKeywords$ + "_DEFLATE$@_INFLATE$@_READBIT@_RESETBIT@_SETBIT@_TOGGLEBIT@$ASSERTS@_ASSERT@_CAPSLOCK@_NUMLOCK@_SCROLLLOCK@_TOGGLE@_CONSOLEFONT@_CONSOLECURSOR@_CONSOLEINPUT@_CINP@$NOPREFIX@$COLOR@$DEBUG@_ENVIRONCOUNT@"
listOfKeywords$ = listOfKeywords$ + "_DEFLATE$@_INFLATE$@_READBIT@_RESETBIT@_SETBIT@_TOGGLEBIT@$ASSERTS@_ASSERT@_CAPSLOCK@_NUMLOCK@_SCROLLLOCK@_TOGGLE@_CONSOLEFONT@_CONSOLECURSOR@_CONSOLEINPUT@_CINP@$NOPREFIX@$COLOR@$DEBUG@_ENVIRONCOUNT@$UNSTABLE@$MIDISOUNDFONT@"

View file

@ -0,0 +1,12 @@
$CONSOLE
$SCREENHIDE
_DEST _CONSOLE
CHDIR _STARTDIR$
$Unstable: Midi
$MidiSoundFont: "tests/compile_tests/midi/test-soundfont.sf2"
handle = _SndOpen("./midi.mid")
print handle;
SYSTEM

View file

@ -0,0 +1 @@
1

Binary file not shown.

View file

@ -0,0 +1,3 @@
$UNSTABLE:MIDI
$MIDISOUNDFONT: "test-soundfont.sf2" extra

View file

@ -0,0 +1,4 @@
Unexpected characters after the quoted file name
Caused by (or after):[INFORMATION UNAVAILABLE]
LINE 3:$MIDISOUNDFONT: "test-soundfont.sf2" extra

View file

@ -0,0 +1,3 @@
$UNSTABLE:MIDI
$MIDISOUNDFONT: test-soundfont.sf2"

View file

@ -0,0 +1,4 @@
Unrecognized Soundfont option "test-soundfont.sf2""
Caused by (or after):[INFORMATION UNAVAILABLE]
LINE 3:$MIDISOUNDFONT: test-soundfont.sf2"

View file

@ -0,0 +1,3 @@
$UNSTABLE:MIDI
$MIDISOUNDFONT: "test-soundfont.sf2

View file

@ -0,0 +1,4 @@
Expected " character at the end of the file name
Caused by (or after):[INFORMATION UNAVAILABLE]
LINE 3:$MIDISOUNDFONT: "test-soundfont.sf2

View file

@ -0,0 +1,3 @@
$Unstable: Midi
$MidiSoundFont: test-soundfont.sf2

View file

@ -0,0 +1,4 @@
Unrecognized Soundfont option "test-soundfont.sf2"
Caused by (or after):[INFORMATION UNAVAILABLE]
LINE 3:$MidiSoundFont: test-soundfont.sf2

View file

@ -0,0 +1,2 @@
$MIDISOUNDFONT: "test-soundfont.sf2"

View file

@ -0,0 +1,4 @@
Syntax error
Caused by (or after):$ MIDISOUNDFONT
LINE 2:$MIDISOUNDFONT: "test-soundfont.sf2"

Binary file not shown.

View file

@ -0,0 +1,12 @@
$CONSOLE
$SCREENHIDE
_DEST _CONSOLE
CHDIR _STARTDIR$
$Unstable: Midi
$MidiSoundFont: Default
handle = _SndOpen("./midi.mid")
print handle;
SYSTEM

View file

@ -0,0 +1 @@
1