1
1
Fork 0
mirror of https://github.com/QB64-Phoenix-Edition/QB64pe.git synced 2024-09-28 11:17:46 +00:00

Merge pull request #164 from mkilgore/midi-support-new

Add MIDI support and `Compiler Settings` command line options
This commit is contained in:
Matt Kilgore 2022-09-09 08:05:03 -04:00 committed by GitHub
commit 7390a089d3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
41 changed files with 764 additions and 2877 deletions

View file

@ -41,7 +41,13 @@ jobs:
- name: Install dependencies
if: ${{ matrix.os == 'ubuntu-latest' }}
run: sudo apt update && sudo apt install build-essential x11-utils mesa-common-dev libglu1-mesa-dev libasound2-dev zlib1g-dev
run: sudo apt update && sudo apt install build-essential x11-utils mesa-common-dev libglu1-mesa-dev libasound2-dev zlib1g-dev pulseaudio dbus-x11 libportaudio2
# Pulseaudio puts a dummy ALSA device in place, which allows us to do
# audio testing on Linux
- name: Start Pulseaudio
if: ${{ matrix.os == 'ubuntu-latest' }}
run: dbus-launch pulseaudio --start
- name: Calculate Version
shell: bash

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

@ -66,6 +66,8 @@ Repository Layout
- `tests/` - Contains the tests run on QB64-PE during CI to verify changes.
- `compile_tests/`
- Testcases related to specific dependencies that QB64 can pull in. These tests are largely intended to test that QB64-PE and the Makefile correctly pulls in the proper dependencies.
- `c`
- The source for the C++-based tests.
- `qbasic_testcases/`
- A variety of collected QB64 sample programs
- `dist/`
@ -80,6 +82,8 @@ Repository Layout
- Runs the distribution test collecitons.
- `run_tests.sh`
- Runs all individual test collections.
- `run_c_tests.sh`
- Runs all the C++ test cases.
- `setup_lnx.sh`
- Used as part of the Linux release to install dependencies and compile QB64-PE.
- `setup_osx.command`

54
docs/testing.md Normal file
View file

@ -0,0 +1,54 @@
QB64-PE Testing Framework
=========================
QB64-PE features two separate testing frameworks, one for QB64-based tests
(mainly for the compiler and language functionality), and one for C++-based
tests (for `libqb`).
QB64-based Tests
----------------
The QB64-based tests live in `./tests/compile_tests`. Each folder in that
directory represents a different category of tests, and within each of those
category folders are `*.bas` files. Accompanying each `*.bas` file is either an
`*.output` or `*.err` file with the same base name as a coresponding `.bas`
file. For test with an `*.output`, the `*.output` file contains the text that
the program compiled from the `*.bas` file should produce. For `*.err` tests,
the `*.err` file contains the text of the error the QB64-PE compiler should
produce when attempting to compile that code.
Tests can also have an optional `*.flags` file. The contents of this file will
be provide as command line arguments to QB64-PE when compiling the test source.
These tests are run via the `./tests/compile_tests.sh` script. The script
searches the `./tests/compile_tests` directory for any `*.bas` files, and then
uses the provide QB64-PE compiler to test them.
C++-based Tests
---------------
The C++-based testing lives in `./tests/c/`. The tests themselves exist as
`.cpp` files that compile into individual programs (each has its own `main()`).
The tests make use of `test.h` to run their tests and give proper output, and
failure is reported via the exit code.
The C++ tests are compiled using the `./tests/build.mk` make build logic. It's
fairly straight forward, each test executable gets its own name and then its
own combination of source/object files necessary to produce it. If you're
testing functionality from `libqb`, then you need to link the proper object
files into your test. Additionally, any extra compiler flags can be defined
individually for each test.
`./tests/run_c_tests.sh` is a script that runs all of the C++ tests during the
build. Internally it has a list of the names of all the test executables (to
avoid having to use `make` to discover them). It expects the tests to have
already been built via a `make build-tests` call, and runs the executables one
at a time and checks their exit code for errors.
QBasic Testcases
----------------
The QBasic testcases are a selection of QBasic programs that live in
`./tests/qb64_testcases`. During the build process all of these programs are
tested to verify that QB64-PE is still capable of compiling them with no
errors. The behavior of the compiled programs is not verified.

View file

@ -1,6 +1,7 @@
libqb-objs-y += $(PATH_LIBQB)/src/threading.o
libqb-objs-y += $(PATH_LIBQB)/src/buffer.o
libqb-objs-y += $(PATH_LIBQB)/src/filepath.o
libqb-objs-y += $(PATH_LIBQB)/src/threading-$(PLATFORM).o

View file

@ -41,6 +41,9 @@
# endif
# define AUDIO_DEBUG_CHECK(_exp_) // Don't do anything in release builds
#endif
// We always use 48000
#define MA_DEFAULT_SAMPLE_RATE 48000
//-----------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------

View file

@ -0,0 +1,15 @@
#ifndef INCLUDE_LIBQB_FILEPATH_H
#define INCLUDE_LIBQB_FILEPATH_H
// Takes a path + filename, and returns just the filename portion
// Returns either NULL or empty string if it has none.
const char *filepath_get_filename(const char *path);
// Takes a filename and returns just the extension at the end
// Returns either NULL or empty string if it has none.
const char *filepath_get_extension(const char *fliename);
// Returns true if the path is to a file that matches the provided extension
bool filepath_has_extension(const char *path, const char *extension);
#endif

View file

@ -0,0 +1,77 @@
// Implementation of these functions was pulled from miniaudio.h (MIT)
#include "libqb-common.h"
#include <string.h>
const char *filepath_get_filename(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;
}
const char *filepath_get_extension(const char *path)
{
const char *extension;
const char *lastOccurance;
if (path == NULL) {
path = "";
}
extension = filepath_get_filename(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;
}
bool filepath_has_extension(const char *path, const char *extension)
{
const char *ext1;
const char *ext2;
if (path == NULL || extension == NULL) {
return false;
}
ext1 = extension;
ext2 = filepath_get_extension(path);
#if defined(_MSC_VER) || defined(__DMC__)
return _stricmp(ext1, ext2) == 0;
#else
return strcasecmp(ext1, ext2) == 0;
#endif
}

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,58 @@
//
//-----------------------------------------------------------------------------------------------------
#pragma once
//-----------------------------------------------------------------------------------------------------
// HEADER FILES
//-----------------------------------------------------------------------------------------------------
#include "libqb-common.h"
#include "audio.h"
#include "filepath.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 +118,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 +337,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 +357,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 +414,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
@ -424,22 +461,14 @@ static ma_result ma_tsf_init_file(const char *pFilePath, const ma_decoding_backe
}
// Check the file extension
if (!ma_path_extension_equal(pFilePath, "mid") && !ma_path_extension_equal(pFilePath, "midi")) {
if (!filepath_has_extension(pFilePath, "mid") && !filepath_has_extension(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;
}
}
// 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);
@ -537,7 +566,11 @@ static void ma_decoding_backend_uninit__tsf(void *pUserData, ma_data_source *pBa
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};
ma_decoding_backend_vtable ma_vtable_midi = {
ma_decoding_backend_init__tsf,
ma_decoding_backend_init_file__tsf,
NULL, /* onInitFileW() */
NULL, /* onInitMemory() */
ma_decoding_backend_uninit__tsf
};
//-----------------------------------------------------------------------------------------------------

View file

@ -0,0 +1,4 @@
#include "vtables.h"
ma_decoding_backend_vtable ma_vtable_midi = { };

View file

@ -15,14 +15,22 @@
//
//-----------------------------------------------------------------------------------------------------
#pragma once
//-----------------------------------------------------------------------------------------------------
// HEADER FILES
//-----------------------------------------------------------------------------------------------------
#include "libqb-common.h"
#include "audio.h"
#include "filepath.h"
#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 +73,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 +262,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) {
@ -381,8 +389,8 @@ static ma_result ma_modplay_init_file(const char *pFilePath, const ma_decoding_b
}
// 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")) {
if (!filepath_has_extension(pFilePath, "it") && !filepath_has_extension(pFilePath, "xm") && !filepath_has_extension(pFilePath, "s3m") &&
!filepath_has_extension(pFilePath, "mod")) {
return MA_INVALID_FILE;
}
@ -498,8 +506,12 @@ 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,
NULL, /* onInitFileW() */
NULL, /* onInitMemory() */
ma_decoding_backend_uninit__modplay};
ma_decoding_backend_vtable ma_vtable_modplay = {
ma_decoding_backend_init__modplay,
ma_decoding_backend_init_file__modplay,
NULL, /* onInitFileW() */
NULL, /* onInitMemory() */
ma_decoding_backend_uninit__modplay
};
//-----------------------------------------------------------------------------------------------------

View file

@ -39,16 +39,23 @@
//
//-----------------------------------------------------------------------------------------------------
#pragma once
//-----------------------------------------------------------------------------------------------------
// HEADER FILES
//-----------------------------------------------------------------------------------------------------
#include "libqb-common.h"
#include "audio.h"
#include "filepath.h"
#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 +103,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 +297,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) {
@ -425,7 +432,7 @@ static ma_result ma_radv2_init_file(const char *pFilePath, const ma_decoding_bac
}
// Check the file extension
if (!ma_path_extension_equal(pFilePath, "rad")) {
if (!filepath_has_extension(pFilePath, "rad")) {
return MA_INVALID_FILE;
}
@ -602,8 +609,11 @@ static void ma_decoding_backend_uninit__radv2(void *pUserData, ma_data_source *p
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};
ma_decoding_backend_vtable ma_vtable_radv2 = {
ma_decoding_backend_init__radv2,
ma_decoding_backend_init_file__radv2,
NULL, /* onInitFileW() */
NULL, /* onInitMemory() */
ma_decoding_backend_uninit__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 ma_vtable_midi;
extern ma_decoding_backend_vtable ma_vtable_modplay;
extern ma_decoding_backend_vtable ma_vtable_radv2;
#endif

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[] = {
&ma_vtable_radv2,
&ma_vtable_midi,
&ma_vtable_modplay,
};
//-----------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------

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
@ -12708,7 +12829,7 @@ IF os$ = "LNX" THEN
PRINT #ffh, makeline$ + CHR$(10);
PRINT #ffh, "read -p " + CHR_QUOTE + "Press ENTER to exit..." + CHR_QUOTE + CHR$(10);
CLOSE ffh
SHELL _HIDE "chmod +x " + tmpdir$ + "recompile_osx.command"
SHELL _HIDE "chmod +x " + AddQuotes$(tmpdir$ + "recompile_osx.command")
ffh = FREEFILE
OPEN tmpdir$ + "debug_osx.command" FOR OUTPUT AS #ffh
@ -12728,7 +12849,7 @@ IF os$ = "LNX" THEN
PRINT #ffh, "gdb " + CHR$(34) + path.exe$ + file$ + extension$ + CHR$(34) + CHR$(10);
PRINT #ffh, "Pause" + CHR$(10);
CLOSE ffh
SHELL _HIDE "chmod +x " + tmpdir$ + "debug_osx.command"
SHELL _HIDE "chmod +x " + AddQuotes$(tmpdir$ + "debug_osx.command")
ELSE
@ -12748,7 +12869,7 @@ IF os$ = "LNX" THEN
PRINT #ffh, "echo " + CHR_QUOTE + "Press ENTER to exit..." + CHR_QUOTE + CHR$(10);
PRINT #ffh, "Pause" + CHR$(10);
CLOSE ffh
SHELL _HIDE "chmod +x " + tmpdir$ + "recompile_lnx.sh"
SHELL _HIDE "chmod +x " + AddQuotes$(tmpdir$ + "recompile_lnx.sh")
ffh = FREEFILE
OPEN tmpdir$ + "debug_lnx.sh" FOR OUTPUT AS #ffh
@ -12768,7 +12889,7 @@ IF os$ = "LNX" THEN
PRINT #ffh, "gdb " + CHR$(34) + path.exe$ + file$ + extension$ + CHR$(34) + CHR$(10);
PRINT #ffh, "Pause" + CHR$(10);
CLOSE ffh
SHELL _HIDE "chmod +x " + tmpdir$ + "debug_lnx.sh"
SHELL _HIDE "chmod +x " + AddQuotes$(tmpdir$ + "debug_lnx.sh")
END IF
@ -12795,7 +12916,7 @@ IF os$ = "LNX" THEN
PRINT #ff, "exit";
PRINT #ff, CHR$(10);
CLOSE #ff
SHELL _HIDE "chmod +x " + path.exe$ + file$ + extension$ + "_start.command"
SHELL _HIDE "chmod +x " + AddQuotes$(path.exe$ + file$ + extension$ + "_start.command")
END IF
END IF
@ -12985,6 +13106,7 @@ FUNCTION ParseCMDLineArgs$ ()
PRINT
PRINT "Options:"
PRINT " <file> Source file to load" ' '80 columns
PRINT " -v Print version"
PRINT " -c Compile instead of edit"
PRINT " -o <output file> Write output executable to <output file>"
PRINT " -x Compile instead of edit and output the result to the"
@ -12999,8 +13121,15 @@ FUNCTION ParseCMDLineArgs$ ()
PRINT " -l:<line number> Start the IDE at the specified line number"
PRINT " -p Purge all pre-compiled content first"
PRINT " -z Generate C code without compiling to executable"
PRINT " -f[:setting=value] compiler settings to use"
PRINT
SYSTEM
CASE "-v" ' Print version
_DEST _CONSOLE
IF qb64versionprinted = 0 THEN qb64versionprinted = -1: PRINT "QB64-PE Compiler V" + Version$
SYSTEM
CASE "-u" 'Invoke "Update all pages" to populate internal/help files (hidden build option)
Help_Recaching = 2: Help_IgnoreCache = 1
IF ideupdatehelpbox THEN
@ -13090,6 +13219,34 @@ FUNCTION ParseCMDLineArgs$ ()
ConsoleMode = 1 'Implies -x
NoIDEMode = 1 'Implies -c
cmdlineswitch = -1
CASE "-f" 'temporary setting
token$ = MID$(token$, 3)
SELECT CASE LCASE$(LEFT$(token$, INSTR(token$, "=") - 1))
CASE ":useminiaudio"
IF NOT ParseBooleanSetting&(token$, UseMiniaudioBackend) THEN PrintTemporarySettingsHelpAndExit InvalidSettingError$(token$)
CASE ":optimizecppprogram"
IF NOT ParseBooleanSetting&(token$, OptimizeCppProgram) THEN PrintTemporarySettingsHelpAndExit InvalidSettingError$(token$)
CASE ":stripdebugsymbols"
IF NOT ParseBooleanSetting&(token$, StripDebugSymbols) THEN PrintTemporarySettingsHelpAndExit InvalidSettingError$(token$)
CASE ":extracppflags"
IF NOT ParseStringSetting&(token$, ExtraCppFlags) THEN PrintTemporarySettingsHelpAndExit InvalidSettingError$(token$)
CASE ":extralinkerflags"
IF NOT ParseStringSetting&(token$, ExtraLinkerFlags) THEN PrintTemporarySettingsHelpAndExit InvalidSettingError$(token$)
CASE ":maxcompilerprocesses"
IF NOT ParseLongSetting&(token$, MaxParallelProcesses) THEN PrintTemporarySettingsHelpAndExit InvalidSettingError$(token$)
IF MaxParallelProcesses = 0 THEN PrintTemporarySettingsHelpAndExit "MaxCompilerProcesses must be more than zero"
CASE ELSE
PrintTemporarySettingsHelpAndExit ""
END SELECT
CASE ELSE 'Something we don't recognise, assume it's a filename
IF PassedFileName$ = "" THEN PassedFileName$ = token$
END SELECT
@ -13102,6 +13259,80 @@ FUNCTION ParseCMDLineArgs$ ()
END IF
END FUNCTION
FUNCTION InvalidSettingError$(token$)
InvalidSettingError$ = "Invalid temporary setting switch: " + AddQuotes$(token$)
END FUNCTION
SUB PrintTemporarySettingsHelpAndExit(errstr$)
_DEST _CONSOLE
PRINT "QB64-PE Compiler V" + Version$
IF errstr$ <> "" THEN
PRINT "Error: "; errstr$
END IF
PRINT
PRINT "Note: Defaults can be changed by IDE settings"
PRINT
PRINT "Valid settings:"
PRINT " -f:UseMiniAudio=[true|false] (Use Miniaudio Audio backend, default true)"
PRINT " -f:OptimizeCppProgram=[true|false] (Use C++ Optimization flag, default false)"
PRINT " -f:StripDebugSymbols=[true|false] (Stirp C++ debug symbols, default true)"
PRINT " -f:ExtraCppFlags=[string] (Extra flags to pass to the C++ compiler)"
PRINT " -f:ExtraLinkerFlags=[string] (Extra flags to pass at link time)"
PRINT " -f:MaxCompilerProcesses=[integer] (Max C++ compiler processes to start in parallel)"
SYSTEM
END SUB
FUNCTION ParseBooleanSetting&(token$, setting AS _UNSIGNED LONG)
DIM equals AS LONG
DIM value AS STRING
equals = INSTR(token$, "=")
IF equals = -1 THEN ParseBooleanSetting& = 0: EXIT FUNCTION
value = LCASE$(MID$(token$, equals + 1))
SELECT CASE value
CASE "true", "on", "yes"
setting = -1
ParseBooleanSetting& = -1
CASE "false", "off", "no"
setting = 0
ParseBooleanSetting& = -1
CASE ELSE
ParseBooleanSetting& = 0
END SELECT
END FUNCTION
FUNCTION ParseLongSetting&(token$, setting AS _UNSIGNED LONG)
DIM equals AS LONG
DIM value AS STRING
equals = INSTR(token$, "=")
IF equals = -1 THEN ParseLongSetting& = 0: EXIT FUNCTION
setting = VAL(MID$(token$, equals + 1))
ParseLongSetting& = -1
END FUNCTION
FUNCTION ParseStringSetting&(token$, setting AS STRING)
DIM equals AS LONG
DIM value AS STRING
equals = INSTR(token$, "=")
IF equals = -1 THEN ParseStringSetting& = 0: EXIT FUNCTION
setting = MID$(token$, equals + 1)
ParseStringSetting& = -1
END FUNCTION
FUNCTION Type2MemTypeValue (t1)
t = 0
IF t1 AND ISARRAY THEN t = t + 65536

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

@ -1,5 +1,6 @@
#!/bin/bash
# Arg 1: qb54 location
# Arg 2: Optional category to test
PREFIX="Compilation"
@ -9,10 +10,14 @@ mkdir -p $RESULTS_DIR
QB64=$1
if [ "$#" -eq 2 ]; then
CATEGORY="/$2"
fi
show_failure()
{
cat "$RESULTS_DIR/$1-compile_result.txt"
cat "$RESULTS_DIR/$1-compilelog.txt"
cat "$RESULTS_DIR/$1-$2-compile_result.txt"
cat "$RESULTS_DIR/$2-compilelog.txt"
}
show_incorrect_result()
@ -21,41 +26,77 @@ show_incorrect_result()
printf "GOT: '%s'\n" "$2"
}
for test in ./tests/compile_tests/*
do
test=$(basename "$test")
TESTCASE="$test"
EXE="$RESULTS_DIR/$test - output"
# Each .bas file represents a separate test.
while IFS= read -r test
do
category=$(basename "$(dirname "$test")")
testName=$(basename "$test" .bas)
TESTCASE="$category/$testName"
EXE="$RESULTS_DIR/$category-$testName - output"
# If a .err file exists, then this test is actually testing a compilation error
testType="success"
if test -f "./tests/compile_tests/$category/$testName.err"; then
testType="error"
fi
# Clear out temp folder before next compile, avoids stale compilelog files
rm -fr ./internal/temp/*
"$QB64" -x "./tests/compile_tests/$test/test.bas" -o "$EXE" 1>"$RESULTS_DIR/$test-compile_result.txt"
ERR=$?
cp_if_exists ./internal/temp/compilelog.txt "$RESULTS_DIR/$test-compilelog.txt"
# Clean up existing EXE, so we don't use it by accident
rm -f "$EXE*"
(exit $ERR)
assert_success_named "Compile" "Compilation Error:" show_failure "$test"
compileResultOutput="$RESULTS_DIR/$category-$testName-compile_result.txt"
test -f "$EXE"
assert_success_named "exe exists" "$test-output executable does not exist!" show_failure "$test"
if [ ! -f "./tests/compile_tests/$test/test.output" ]; then
continue
# A .flags file contains any extra compiler flags to provide to QB64 for this test
compilerFlags=
if test -f "./tests/compile_tests/$category/$testName.flags"; then
compilerFlags=$(cat "./tests/compile_tests/$category/$testName.flags")
fi
expectedResult="$(cat "./tests/compile_tests/$test/test.output")"
pushd . > /dev/null
cd "./tests/compile_tests/$test"
testResult=$("../../../$EXE" 2>&1)
# -m and -q make sure that we get predictable results
"$QB64" $compilerFlags -m -q -x "./tests/compile_tests/$category/$testName.bas" -o "$EXE" 1>"$compileResultOutput"
ERR=$?
popd > /dev/null
cp_if_exists ./internal/temp/compilelog.txt "$RESULTS_DIR/$category-$testName-compilelog.txt"
(exit $ERR)
assert_success_named "run" "Execution Error:" echo "$testResult"
if [ "$testType" == "success" ]; then
(exit $ERR)
assert_success_named "Compile" "Compilation Error:" show_failure "$category" "$testName"
[ "$testResult" == "$expectedResult" ]
assert_success_named "result" "Result is wrong:" show_incorrect_result "$expectedResult" "$testResult"
done
test -f "$EXE"
assert_success_named "exe exists" "$test-output executable does not exist!" show_failure "$category" "$testName"
# Some tests do not have an output or err file because they should
# compile successfully but cannot be run on the build agents
if [ ! -f "./tests/compile_tests/$category/$testName.output" ]; then
continue
fi
expectedResult="$(cat "./tests/compile_tests/$category/$testName.output")"
pushd . > /dev/null
cd "./tests/compile_tests/$category"
testResult=$("../../../$EXE" 2>&1)
ERR=$?
popd > /dev/null
(exit $ERR)
assert_success_named "run" "Execution Error:" echo "$testResult"
[ "$testResult" == "$expectedResult" ]
assert_success_named "result" "Result is wrong:" show_incorrect_result "$expectedResult" "$testResult"
else
! (exit $ERR)
assert_success_named "Compile" "Compilation Success, was expecting error:" show_failure "$category" "$testName"
! test -f "$EXE"
assert_success_named "Exe exists" "'$category-$testName - output' exists, it should not!" show_failure "$category" "$testName"
expectedErr="$(cat "./tests/compile_tests/$category/$testName.err")"
diffResult=$(diff -y "./tests/compile_tests/$category/$testName.err" "$compileResultOutput")
assert_success_named "Error result" "Error reporting is wrong:" echo "$diffResult"
fi
done < <(find ./tests/compile_tests$CATEGORY -name "*.bas" -print)

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"

View file

@ -0,0 +1,4 @@
$UNSTABLE:MIDI
$MIDISOUNDFONT: DEFAULT

View file

@ -0,0 +1,4 @@
Midi is not supported with the old OpenAL audio backend.
Caused by (or after):
LINE 2:$ UNSTABLE : MIDI

View file

@ -0,0 +1 @@
-f:UseMiniaudio=false

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