From eb45a7913d83fe2a3dc03033230950e78fb9755d Mon Sep 17 00:00:00 2001 From: Wohlstand Date: Fri, 20 Oct 2017 04:28:53 +0300 Subject: Added CMake support --- .gitignore | 3 + CMakeLists.txt | 184 ++++ Makefile | 24 - Makefile.old | 24 + include/adlmidi.h | 143 +++ libADLMIDI-test.pro | 9 +- src/adlmidi.h | 143 --- src/dumpbank/dumpbank.cc | 167 --- src/dumpmiles/dumpmiles.cc | 40 - src/gen_adldata/file_formats/common.h | 28 - src/gen_adldata/file_formats/load_ail.h | 102 -- src/gen_adldata/file_formats/load_bisqwit.h | 53 - src/gen_adldata/file_formats/load_bnk.h | 152 --- src/gen_adldata/file_formats/load_bnk2.h | 102 -- src/gen_adldata/file_formats/load_ibk.h | 72 -- src/gen_adldata/file_formats/load_jv.h | 105 -- src/gen_adldata/file_formats/load_op2.h | 148 --- src/gen_adldata/file_formats/load_tmb.h | 68 -- src/gen_adldata/file_formats/load_wopl.h | 265 ----- src/gen_adldata/gen_adldata.cc | 506 --------- src/gen_adldata/gen_adldata.pro | 38 - src/gen_adldata/ini/IniProcessor.pri | 10 - src/gen_adldata/ini/ini_processing.cpp | 1385 ------------------------ src/gen_adldata/ini/ini_processing.h | 677 ------------ src/gen_adldata/ini/ini_processing_variant.h | 243 ----- src/gen_adldata/measurer.cpp | 543 ---------- src/gen_adldata/measurer.h | 105 -- src/gen_adldata/midi_inst_list.h | 185 ---- src/gen_adldata/progs_cache.cpp | 106 -- src/gen_adldata/progs_cache.h | 85 -- src/gen_adldata/scrapped.txt | 263 ----- src/midiplay/Makefile | 12 - src/midiplay/Makefile.win32 | 12 - src/midiplay/adlmidiplay.cpp | 338 ------ src/midiplay/wave_writer.c | 170 --- src/midiplay/wave_writer.h | 21 - src/test/adldatatest.cc | 2 - src/test/test.cc | 202 ---- test.wopl | Bin 0 -> 15959 bytes utils/dumpbank/dumpbank.cpp | 179 +++ utils/dumpmiles/dumpmiles.cpp | 52 + utils/gen_adldata/file_formats/common.h | 28 + utils/gen_adldata/file_formats/load_ail.h | 102 ++ utils/gen_adldata/file_formats/load_bisqwit.h | 53 + utils/gen_adldata/file_formats/load_bnk.h | 152 +++ utils/gen_adldata/file_formats/load_bnk2.h | 102 ++ utils/gen_adldata/file_formats/load_ibk.h | 72 ++ utils/gen_adldata/file_formats/load_jv.h | 105 ++ utils/gen_adldata/file_formats/load_op2.h | 148 +++ utils/gen_adldata/file_formats/load_tmb.h | 68 ++ utils/gen_adldata/file_formats/load_wopl.h | 265 +++++ utils/gen_adldata/gen_adldata.cc | 506 +++++++++ utils/gen_adldata/gen_adldata.pro | 38 + utils/gen_adldata/ini/IniProcessor.pri | 10 + utils/gen_adldata/ini/ini_processing.cpp | 1385 ++++++++++++++++++++++++ utils/gen_adldata/ini/ini_processing.h | 677 ++++++++++++ utils/gen_adldata/ini/ini_processing_variant.h | 243 +++++ utils/gen_adldata/measurer.cpp | 543 ++++++++++ utils/gen_adldata/measurer.h | 105 ++ utils/gen_adldata/midi_inst_list.h | 185 ++++ utils/gen_adldata/progs_cache.cpp | 106 ++ utils/gen_adldata/progs_cache.h | 85 ++ utils/gen_adldata/scrapped.txt | 263 +++++ utils/midiplay/Makefile | 12 + utils/midiplay/Makefile.win32 | 12 + utils/midiplay/adlmidiplay.cpp | 338 ++++++ utils/midiplay/wave_writer.c | 170 +++ utils/midiplay/wave_writer.h | 21 + utils/test/adldatatest.cc | 2 + utils/test/test.cc | 202 ++++ 70 files changed, 6588 insertions(+), 6376 deletions(-) create mode 100644 CMakeLists.txt delete mode 100644 Makefile create mode 100644 Makefile.old create mode 100644 include/adlmidi.h delete mode 100644 src/adlmidi.h delete mode 100644 src/dumpbank/dumpbank.cc delete mode 100644 src/dumpmiles/dumpmiles.cc delete mode 100644 src/gen_adldata/file_formats/common.h delete mode 100644 src/gen_adldata/file_formats/load_ail.h delete mode 100644 src/gen_adldata/file_formats/load_bisqwit.h delete mode 100644 src/gen_adldata/file_formats/load_bnk.h delete mode 100644 src/gen_adldata/file_formats/load_bnk2.h delete mode 100644 src/gen_adldata/file_formats/load_ibk.h delete mode 100644 src/gen_adldata/file_formats/load_jv.h delete mode 100644 src/gen_adldata/file_formats/load_op2.h delete mode 100644 src/gen_adldata/file_formats/load_tmb.h delete mode 100644 src/gen_adldata/file_formats/load_wopl.h delete mode 100644 src/gen_adldata/gen_adldata.cc delete mode 100644 src/gen_adldata/gen_adldata.pro delete mode 100644 src/gen_adldata/ini/IniProcessor.pri delete mode 100644 src/gen_adldata/ini/ini_processing.cpp delete mode 100644 src/gen_adldata/ini/ini_processing.h delete mode 100644 src/gen_adldata/ini/ini_processing_variant.h delete mode 100644 src/gen_adldata/measurer.cpp delete mode 100644 src/gen_adldata/measurer.h delete mode 100644 src/gen_adldata/midi_inst_list.h delete mode 100644 src/gen_adldata/progs_cache.cpp delete mode 100644 src/gen_adldata/progs_cache.h delete mode 100644 src/gen_adldata/scrapped.txt delete mode 100644 src/midiplay/Makefile delete mode 100644 src/midiplay/Makefile.win32 delete mode 100644 src/midiplay/adlmidiplay.cpp delete mode 100755 src/midiplay/wave_writer.c delete mode 100755 src/midiplay/wave_writer.h delete mode 100644 src/test/adldatatest.cc delete mode 100644 src/test/test.cc create mode 100644 test.wopl create mode 100644 utils/dumpbank/dumpbank.cpp create mode 100644 utils/dumpmiles/dumpmiles.cpp create mode 100644 utils/gen_adldata/file_formats/common.h create mode 100644 utils/gen_adldata/file_formats/load_ail.h create mode 100644 utils/gen_adldata/file_formats/load_bisqwit.h create mode 100644 utils/gen_adldata/file_formats/load_bnk.h create mode 100644 utils/gen_adldata/file_formats/load_bnk2.h create mode 100644 utils/gen_adldata/file_formats/load_ibk.h create mode 100644 utils/gen_adldata/file_formats/load_jv.h create mode 100644 utils/gen_adldata/file_formats/load_op2.h create mode 100644 utils/gen_adldata/file_formats/load_tmb.h create mode 100644 utils/gen_adldata/file_formats/load_wopl.h create mode 100644 utils/gen_adldata/gen_adldata.cc create mode 100644 utils/gen_adldata/gen_adldata.pro create mode 100644 utils/gen_adldata/ini/IniProcessor.pri create mode 100644 utils/gen_adldata/ini/ini_processing.cpp create mode 100644 utils/gen_adldata/ini/ini_processing.h create mode 100644 utils/gen_adldata/ini/ini_processing_variant.h create mode 100644 utils/gen_adldata/measurer.cpp create mode 100644 utils/gen_adldata/measurer.h create mode 100644 utils/gen_adldata/midi_inst_list.h create mode 100644 utils/gen_adldata/progs_cache.cpp create mode 100644 utils/gen_adldata/progs_cache.h create mode 100644 utils/gen_adldata/scrapped.txt create mode 100644 utils/midiplay/Makefile create mode 100644 utils/midiplay/Makefile.win32 create mode 100644 utils/midiplay/adlmidiplay.cpp create mode 100755 utils/midiplay/wave_writer.c create mode 100755 utils/midiplay/wave_writer.h create mode 100644 utils/test/adldatatest.cc create mode 100644 utils/test/test.cc diff --git a/.gitignore b/.gitignore index 0f3c9f9..dccade2 100644 --- a/.gitignore +++ b/.gitignore @@ -33,3 +33,6 @@ obj/* build-* *.user +# Cmake caches +build/* + diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..f2a7aca --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,184 @@ +cmake_minimum_required (VERSION 2.8.11) +project (libADLMIDI) + +#=========================================================================================== +# Strip garbage +if(APPLE) + set(LINK_FLAGS_RELEASE "${LINK_FLAGS_RELEASE} -dead_strip") +ELSEIF(NOT MSVC) + set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -Os -s -fdata-sections -ffunction-sections -Wl,--gc-sections -Wl,-s") + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -Os -s -fdata-sections -ffunction-sections -Wl,--gc-sections -Wl,-s") + set(LINK_FLAGS_RELEASE "${LINK_FLAGS_RELEASE} -Wl,--gc-sections -Wl,-s") +ENDIF() + +# Global optimization flags +IF(NOT MSVC) + set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -fno-omit-frame-pointer") + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fno-omit-frame-pointer") +ENDIF() + +if (CMAKE_BUILD_TYPE EQUAL "RELEASE") + add_definitions(-DNDEBUG) +ENDIF() + +# Disable bogus MSVC warnings +if(MSVC) + add_definitions(-D_CRT_SECURE_NO_WARNINGS) +ENDIF() + +# -fPIC thing +IF(NOT WIN32) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") +ENDIF() +#=========================================================================================== + +option(WITH_MIDIPLAY "Build also demo MIDI player" OFF) +option(WITH_OLD_UTILS "Build also old utilities" OFF) +option(WITH_EMBEDDED_BANKS "Use embedded banks" ON) +option(USE_DOSBOX_EMULATOR "Use DosBox emulator" OFF) + +option(libADLMIDI_STATIC "Build static library of libADLMIDI" ON) +option(libADLMIDI_SHARED "Build shared library of libADLMIDI" OFF) + + + +set(libADLMIDI_INSTALLS) + +include_directories(${libADLMIDI_SOURCE_DIR}/include) +include_directories(${libADLMIDI_SOURCE_DIR}/src/) +link_directories(${libADLMIDI_BINARY_DIR}/) + +if(WITH_OLD_UTILS) + # Old utility to dump AdLib bank files + add_executable(adldumpbank + ${libADLMIDI_SOURCE_DIR}/utils/dumpbank/dumpbank.cpp + ) + list(APPEND libADLMIDI_INSTALLS adldumpbank) + + # Old utility to dump AIL bank files + add_executable(adldumpmiles + ${libADLMIDI_SOURCE_DIR}/utils/dumpmiles/dumpmiles.cpp + ) + list(APPEND libADLMIDI_INSTALLS adldumpmiles) +endif() + +if(WITH_EMBEDDED_BANKS) + add_executable(gen_adldata + ${libADLMIDI_SOURCE_DIR}/utils/gen_adldata/gen_adldata.cc + ${libADLMIDI_SOURCE_DIR}/utils/gen_adldata/progs_cache.cpp + ${libADLMIDI_SOURCE_DIR}/utils/gen_adldata/measurer.cpp + ${libADLMIDI_SOURCE_DIR}/utils/gen_adldata/ini/ini_processing.cpp + ${libADLMIDI_SOURCE_DIR}/src/nukedopl3.c + ${libADLMIDI_SOURCE_DIR}/src/dbopl.cpp + ) + target_link_libraries(gen_adldata pthread) + + add_custom_target ( + gen-adldata-run + COMMAND ${libADLMIDI_BINARY_DIR}/gen_adldata ${libADLMIDI_SOURCE_DIR}/src/adldata.cpp + WORKING_DIRECTORY ${libADLMIDI_SOURCE_DIR} + ) + add_dependencies(gen-adldata-run gen_adldata) +endif() + + +set(libADLMIDI_SOURCES) + +list(APPEND libADLMIDI_SOURCES + ${libADLMIDI_SOURCE_DIR}/src/adlmidi.cpp + ${libADLMIDI_SOURCE_DIR}/src/adlmidi_load.cpp + ${libADLMIDI_SOURCE_DIR}/src/adlmidi_midiplay.cpp + ${libADLMIDI_SOURCE_DIR}/src/adlmidi_opl3.cpp + ${libADLMIDI_SOURCE_DIR}/src/adlmidi_private.cpp + ${libADLMIDI_SOURCE_DIR}/src/adlmidi_mus2mid.c + ${libADLMIDI_SOURCE_DIR}/src/adlmidi_xmi2mid.c +) + +if(USE_DOSBOX_EMULATOR) + add_definitions(-DADLMIDI_USE_DOSBOX_OPL) + list(APPEND libADLMIDI_SOURCES + ${libADLMIDI_SOURCE_DIR}/src/dbopl.cpp + ) +else() + list(APPEND libADLMIDI_SOURCES + ${libADLMIDI_SOURCE_DIR}/src/nukedopl3.c + ) +endif() + +if(WITH_EMBEDDED_BANKS) + list(APPEND libADLMIDI_SOURCES + ${libADLMIDI_SOURCE_DIR}/src/adldata.cpp + ) +else() + add_definitions(-DDISABLE_EMBEDDED_BANKS) +endif() + +if(libADLMIDI_STATIC) + add_library(ADLMIDI_static STATIC ${libADLMIDI_SOURCES}) + set_target_properties(ADLMIDI_static PROPERTIES OUTPUT_NAME ADLMIDI) + target_include_directories(ADLMIDI_static PUBLIC ${SDLMixerX_SOURCE_DIR}/include) + list(APPEND libADLMIDI_INSTALLS ADLMIDI_static) + if(WITH_EMBEDDED_BANKS) + add_dependencies(ADLMIDI_static gen-adldata-run) + endif() +endif() + +if(libADLMIDI_SHARED) + add_library(ADLMIDI_shared SHARED ${libADLMIDI_SOURCES}) + set_target_properties(ADLMIDI_shared PROPERTIES OUTPUT_NAME ADLMIDI) + target_include_directories(ADLMIDI_shared PUBLIC ${SDLMixerX_SOURCE_DIR}/include) + list(APPEND libADLMIDI_INSTALLS ADLMIDI_shared) + if(WITH_EMBEDDED_BANKS) + add_dependencies(ADLMIDI_shared gen-adldata-run) + endif() +endif() + +if(WITH_MIDIPLAY) + find_library(SDL2_LIBRARY SDL2 REQUIRED) + include_directories(${SDL2_INCLUDE_DIR}) + message("Found ${SDL2_LIBRARY}") + + add_executable(adlmidiplay + ${libADLMIDI_SOURCE_DIR}/utils/midiplay/adlmidiplay.cpp + ${libADLMIDI_SOURCE_DIR}/utils/midiplay/wave_writer.c + ) + + if(WIN32) + target_link_libraries(adlmidiplay ADLMIDI ${SDL2_LIBRARY} pthread) + else() + target_link_libraries(adlmidiplay ADLMIDI ${SDL2_LIBRARY} pthread dl) + endif() + + if(libADLMIDI_SHARED) + add_dependencies(adlmidiplay ADLMIDI_shared) + # ========= WIP ========= + # set_target_properties(adlmidiplay PROPERTIES COMPILE_FLAGS "-Wl,-rpath='$$ORIGIN/../lib'") + else() + if(NOT libADLMIDI_STATIC) + message(FATAL_ERROR "libADLMIDI is required to be built!") + endif() + add_dependencies(adlmidiplay ADLMIDI_static) + endif() + + list(APPEND libADLMIDI_INSTALLS adlmidiplay) +endif() + +install(TARGETS ${libADLMIDI_INSTALLS} + RUNTIME DESTINATION "bin" + LIBRARY DESTINATION "lib" + ARCHIVE DESTINATION "lib" + INCLUDES DESTINATION "include") + +install(FILES + include/adlmidi.h + DESTINATION include/) + +message("==== libADLMIDI options ====") +message("WITH_MIDIPLAY = ${WITH_MIDIPLAY}") +message("WITH_EMBEDDED_BANKS = ${WITH_EMBEDDED_BANKS}") +message("USE_DOSBOX_EMULATOR = ${USE_DOSBOX_EMULATOR}") +message("libADLMIDI_STATIC = ${libADLMIDI_STATIC}") +message("libADLMIDI_SHARED = ${libADLMIDI_SHARED}") + + diff --git a/Makefile b/Makefile deleted file mode 100644 index f1a2ead..0000000 --- a/Makefile +++ /dev/null @@ -1,24 +0,0 @@ -#CXX=i686-w64-mingw32-g++ -static -CC=gcc -CXX=g++ -CXXLINK=$(CXX) -MKDIR=mkdir -p -RM=rm -RM_F=rm -Rf - -#DEBUG=-O0 -fno-inline -D_GLIBCXX_DEBUG -g -fstack-protector-all -fdata-sections - -DEBUG=-Ofast -g - -#DEBUG += -fno-tree-vectorize - -# -march=pentium -mno-sse -mno-sse2 -mno-sse3 -mmmx - -CFLAGS += -DLIBADLMIDI_VISIBILITY - -CPPFLAGS += -DLIBADLMIDI_VISIBILITY - -CPPFLAGS += -std=c++11 -pedantic -Wall -Wextra - -include make.rules - diff --git a/Makefile.old b/Makefile.old new file mode 100644 index 0000000..f1a2ead --- /dev/null +++ b/Makefile.old @@ -0,0 +1,24 @@ +#CXX=i686-w64-mingw32-g++ -static +CC=gcc +CXX=g++ +CXXLINK=$(CXX) +MKDIR=mkdir -p +RM=rm +RM_F=rm -Rf + +#DEBUG=-O0 -fno-inline -D_GLIBCXX_DEBUG -g -fstack-protector-all -fdata-sections + +DEBUG=-Ofast -g + +#DEBUG += -fno-tree-vectorize + +# -march=pentium -mno-sse -mno-sse2 -mno-sse3 -mmmx + +CFLAGS += -DLIBADLMIDI_VISIBILITY + +CPPFLAGS += -DLIBADLMIDI_VISIBILITY + +CPPFLAGS += -std=c++11 -pedantic -Wall -Wextra + +include make.rules + diff --git a/include/adlmidi.h b/include/adlmidi.h new file mode 100644 index 0000000..c82ef63 --- /dev/null +++ b/include/adlmidi.h @@ -0,0 +1,143 @@ +/* + * libADLMIDI is a free MIDI to WAV conversion library with OPL3 emulation + * + * Original ADLMIDI code: Copyright (c) 2010-2014 Joel Yliluoma + * ADLMIDI Library API: Copyright (c) 2017 Vitaly Novichkov + * + * Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation: + * http://iki.fi/bisqwit/source/adlmidi.html + * + * 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 + * 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 . + */ + +#ifndef ADLMIDI_H +#define ADLMIDI_H + +#ifdef __cplusplus +extern "C" { +#endif + +enum ADLMIDI_VolumeModels +{ + ADLMIDI_VolumeModel_AUTO = 0, + ADLMIDI_VolumeModel_Generic, + ADLMIDI_VolumeModel_CMF, + ADLMIDI_VolumeModel_DMX, + ADLMIDI_VolumeModel_APOGEE, + ADLMIDI_VolumeModel_9X +}; + +struct ADL_MIDIPlayer +{ + unsigned int AdlBank; + unsigned int NumFourOps; + unsigned int NumCards; + unsigned int HighTremoloMode; + unsigned int HighVibratoMode; + unsigned int AdlPercussionMode; + unsigned int LogarithmicVolumes; + int VolumeModel; + unsigned int SkipForward; + unsigned int loopingIsEnabled; + unsigned int ScaleModulators; + double delay; + double carry; + + /* The lag between visual content and audio content equals */ + /* the sum of these two buffers. */ + double mindelay; + double maxdelay; + + /* For internal usage */ + int stored_samples; /* num of collected samples */ + short backup_samples[1024]; /* Backup sample storage. */ + int backup_samples_size; /* Backup sample storage. */ + /* For internal usage */ + + void *adl_midiPlayer; + unsigned long PCM_RATE; +}; + +/* Sets number of emulated sound cards (from 1 to 100). Emulation of multiple sound cards exchanges polyphony limits*/ +extern int adl_setNumCards(struct ADL_MIDIPlayer *device, int numCards); + +/* Sets a number of the patches bank from 0 to N banks */ +extern int adl_setBank(struct ADL_MIDIPlayer *device, int bank); + +/* Returns total number of available banks */ +extern int adl_getBanksCount(); + +/* Returns pointer to array of names of every bank */ +extern const char *const *adl_getBankNames(); + +/*Sets number of 4-chan operators*/ +extern int adl_setNumFourOpsChn(struct ADL_MIDIPlayer *device, int ops4); + +/*Enable or disable AdLib percussion mode*/ +extern void adl_setPercMode(struct ADL_MIDIPlayer *device, int percmod); + +/*Enable or disable deep vibrato*/ +extern void adl_setHVibrato(struct ADL_MIDIPlayer *device, int hvibro); + +/*Enable or disable deep tremolo*/ +extern void adl_setHTremolo(struct ADL_MIDIPlayer *device, int htremo); + +/*Enable or disable Enables scaling of modulator volumes*/ +extern void adl_setScaleModulators(struct ADL_MIDIPlayer *device, int smod); + +/*Enable or disable built-in loop (built-in loop supports 'loopStart' and 'loopEnd' tags to loop specific part)*/ +extern void adl_setLoopEnabled(struct ADL_MIDIPlayer *device, int loopEn); + +/*Enable or disable Logariphmic volume changer */ +extern void adl_setLogarithmicVolumes(struct ADL_MIDIPlayer *device, int logvol); + +/*Set different volume range model */ +extern void adl_setVolumeRangeModel(struct ADL_MIDIPlayer *device, int volumeModel); + +/*Load WOPL bank file from File System*/ +extern int adl_openBankFile(struct ADL_MIDIPlayer *device, char *filePath); + +/*Load WOPL bank file from memory data*/ +extern int adl_openBankData(struct ADL_MIDIPlayer *device, void *mem, long size); + + +/*Returns string which contains last error message*/ +extern const char *adl_errorString(); + +/*Initialize ADLMIDI Player device*/ +extern struct ADL_MIDIPlayer *adl_init(long sample_rate); + +/*Load MIDI file from File System*/ +extern int adl_openFile(struct ADL_MIDIPlayer *device, char *filePath); + +/*Load MIDI file from memory data*/ +extern int adl_openData(struct ADL_MIDIPlayer *device, void *mem, long size); + +/*Resets MIDI player*/ +extern void adl_reset(struct ADL_MIDIPlayer *device); + +/*Reset MIDI track position to begin */ +extern void adl_positionRewind(struct ADL_MIDIPlayer *device); + +/*Close and delete ADLMIDI device*/ +extern void adl_close(struct ADL_MIDIPlayer *device); + +/*Take a sample buffer*/ +extern int adl_play(struct ADL_MIDIPlayer *device, int sampleCount, short out[]); + +#ifdef __cplusplus +} +#endif + +#endif /* ADLMIDI_H */ diff --git a/libADLMIDI-test.pro b/libADLMIDI-test.pro index 7be6bd8..4ddc5b7 100644 --- a/libADLMIDI-test.pro +++ b/libADLMIDI-test.pro @@ -7,16 +7,16 @@ DESTDIR=$$PWD/bin/ #INCLUDEPATH += $$PWD/AudioCodecs/build/install/include #LIBS += -L$$PWD/AudioCodecs/build/install/lib -INCLUDEPATH += $$PWD/src +INCLUDEPATH += $$PWD/src $$PWD/include #LIBS += -Wl,-Bstatic -lSDL2 -Wl,-Bdynamic -lpthread -ldl LIBS += -lSDL2 -lpthread -ldl #DEFINES += DISABLE_EMBEDDED_BANKS HEADERS += \ + include/adlmidi.h \ src/adlbank.h \ src/adldata.hh \ - src/adlmidi.h \ src/adlmidi_mus2mid.h \ src/adlmidi_private.hpp \ src/adlmidi_xmi2mid.h \ @@ -35,5 +35,6 @@ SOURCES += \ src/adlmidi_private.cpp \ src/adlmidi_xmi2mid.c \ src/nukedopl3.c \ - src/midiplay/adlmidiplay.cpp \ - src/midiplay/wave_writer.c + utils/midiplay/adlmidiplay.cpp \ + utils/midiplay/wave_writer.c + diff --git a/src/adlmidi.h b/src/adlmidi.h deleted file mode 100644 index c82ef63..0000000 --- a/src/adlmidi.h +++ /dev/null @@ -1,143 +0,0 @@ -/* - * libADLMIDI is a free MIDI to WAV conversion library with OPL3 emulation - * - * Original ADLMIDI code: Copyright (c) 2010-2014 Joel Yliluoma - * ADLMIDI Library API: Copyright (c) 2017 Vitaly Novichkov - * - * Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation: - * http://iki.fi/bisqwit/source/adlmidi.html - * - * 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 - * 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 . - */ - -#ifndef ADLMIDI_H -#define ADLMIDI_H - -#ifdef __cplusplus -extern "C" { -#endif - -enum ADLMIDI_VolumeModels -{ - ADLMIDI_VolumeModel_AUTO = 0, - ADLMIDI_VolumeModel_Generic, - ADLMIDI_VolumeModel_CMF, - ADLMIDI_VolumeModel_DMX, - ADLMIDI_VolumeModel_APOGEE, - ADLMIDI_VolumeModel_9X -}; - -struct ADL_MIDIPlayer -{ - unsigned int AdlBank; - unsigned int NumFourOps; - unsigned int NumCards; - unsigned int HighTremoloMode; - unsigned int HighVibratoMode; - unsigned int AdlPercussionMode; - unsigned int LogarithmicVolumes; - int VolumeModel; - unsigned int SkipForward; - unsigned int loopingIsEnabled; - unsigned int ScaleModulators; - double delay; - double carry; - - /* The lag between visual content and audio content equals */ - /* the sum of these two buffers. */ - double mindelay; - double maxdelay; - - /* For internal usage */ - int stored_samples; /* num of collected samples */ - short backup_samples[1024]; /* Backup sample storage. */ - int backup_samples_size; /* Backup sample storage. */ - /* For internal usage */ - - void *adl_midiPlayer; - unsigned long PCM_RATE; -}; - -/* Sets number of emulated sound cards (from 1 to 100). Emulation of multiple sound cards exchanges polyphony limits*/ -extern int adl_setNumCards(struct ADL_MIDIPlayer *device, int numCards); - -/* Sets a number of the patches bank from 0 to N banks */ -extern int adl_setBank(struct ADL_MIDIPlayer *device, int bank); - -/* Returns total number of available banks */ -extern int adl_getBanksCount(); - -/* Returns pointer to array of names of every bank */ -extern const char *const *adl_getBankNames(); - -/*Sets number of 4-chan operators*/ -extern int adl_setNumFourOpsChn(struct ADL_MIDIPlayer *device, int ops4); - -/*Enable or disable AdLib percussion mode*/ -extern void adl_setPercMode(struct ADL_MIDIPlayer *device, int percmod); - -/*Enable or disable deep vibrato*/ -extern void adl_setHVibrato(struct ADL_MIDIPlayer *device, int hvibro); - -/*Enable or disable deep tremolo*/ -extern void adl_setHTremolo(struct ADL_MIDIPlayer *device, int htremo); - -/*Enable or disable Enables scaling of modulator volumes*/ -extern void adl_setScaleModulators(struct ADL_MIDIPlayer *device, int smod); - -/*Enable or disable built-in loop (built-in loop supports 'loopStart' and 'loopEnd' tags to loop specific part)*/ -extern void adl_setLoopEnabled(struct ADL_MIDIPlayer *device, int loopEn); - -/*Enable or disable Logariphmic volume changer */ -extern void adl_setLogarithmicVolumes(struct ADL_MIDIPlayer *device, int logvol); - -/*Set different volume range model */ -extern void adl_setVolumeRangeModel(struct ADL_MIDIPlayer *device, int volumeModel); - -/*Load WOPL bank file from File System*/ -extern int adl_openBankFile(struct ADL_MIDIPlayer *device, char *filePath); - -/*Load WOPL bank file from memory data*/ -extern int adl_openBankData(struct ADL_MIDIPlayer *device, void *mem, long size); - - -/*Returns string which contains last error message*/ -extern const char *adl_errorString(); - -/*Initialize ADLMIDI Player device*/ -extern struct ADL_MIDIPlayer *adl_init(long sample_rate); - -/*Load MIDI file from File System*/ -extern int adl_openFile(struct ADL_MIDIPlayer *device, char *filePath); - -/*Load MIDI file from memory data*/ -extern int adl_openData(struct ADL_MIDIPlayer *device, void *mem, long size); - -/*Resets MIDI player*/ -extern void adl_reset(struct ADL_MIDIPlayer *device); - -/*Reset MIDI track position to begin */ -extern void adl_positionRewind(struct ADL_MIDIPlayer *device); - -/*Close and delete ADLMIDI device*/ -extern void adl_close(struct ADL_MIDIPlayer *device); - -/*Take a sample buffer*/ -extern int adl_play(struct ADL_MIDIPlayer *device, int sampleCount, short out[]); - -#ifdef __cplusplus -} -#endif - -#endif /* ADLMIDI_H */ diff --git a/src/dumpbank/dumpbank.cc b/src/dumpbank/dumpbank.cc deleted file mode 100644 index bd78af7..0000000 --- a/src/dumpbank/dumpbank.cc +++ /dev/null @@ -1,167 +0,0 @@ -//#ifdef __MINGW32__ -//typedef struct vswprintf {} swprintf; -//#endif -#include -#include -#include - -struct BNK1_header -{ - char maj_vers, min_vers; - char signature[6]; // "ADLIB-" - unsigned short ins_used, ins_entries; - unsigned name_list, inst_data; -} __attribute__((packed)); -struct BNK1_record -{ - unsigned short index; - unsigned char used; - char name[9]; -} __attribute__((packed)); -struct OPL2_op -{ - unsigned char key_scale_lvl; - unsigned char freq_mult; - unsigned char feedback; - unsigned char attack; - unsigned char sustain_lvl; - unsigned char sustain_sound; - unsigned char decay; - unsigned char release; - unsigned char out_lvl; - unsigned char amp_vib; - unsigned char pitch_vib; - unsigned char env_scaling; - unsigned char connection; -} __attribute__((packed)); -struct BNK1_instrument -{ - unsigned char sound_mode; - unsigned char voice_num; - OPL2_op ops[2]; - unsigned char waveforms[2]; -} __attribute__((packed)); // conventional Ad Lib instrument maker bankfile patch - -struct BNK2_header -{ - char signature[28]; // "Accomp. Bank, (C) AdLib Inc" - unsigned short file_ver; - char filler[10]; - unsigned short ins_entries, ins_used; - int lostSpace; -} __attribute__((packed)); -struct BNK2_record -{ - char O3_sig[3]; - char key[12]; - char used; - int attrib, dataOffset; - unsigned short blockSize, allocBSize; -} __attribute__((packed)); -struct OPL3_op -{ - unsigned char AVEKMMMM, KKLLLLLL; - unsigned char AAAADDDD, SSSSRRRR; - unsigned char DxxxxWWW, xxxxxxxx; -} __attribute__((packed)); -struct BNK2_instrument -{ - OPL3_op ops[4]; - unsigned char C4xxxFFFC; - unsigned char xxP24NNN; - unsigned char TTTTTTTT; - unsigned char xxxxxxxx; -} __attribute__((packed)); // Ad Lib Gold instrument maker bankfile patch - -static void LoadBNK1(const std::vector& data) -{ - const BNK1_header& bnk1 = *(const BNK1_header*) &data[0]; - const BNK1_record* names = (const BNK1_record*) &data[ bnk1.name_list ]; - const BNK1_instrument* ins = (const BNK1_instrument*) &data[ bnk1.inst_data ]; - printf("BNK1 version: %d.%d\n", bnk1.maj_vers, bnk1.min_vers); - for(unsigned a=0; a& data) -{ - const BNK2_header& bnk2 = *(const BNK2_header*) &data[0]; - const BNK2_record* names = (const BNK2_record*) &data[ sizeof(bnk2) ]; - printf("BNK2 version: %d, lost space %d\n", bnk2.file_ver, bnk2.lostSpace); - for(unsigned a=0; a data(ftell(fp)); - rewind(fp); - fread(&data[0], 1, data.size(), fp), - fclose(fp); - - const BNK1_header& bnk1 = *(const BNK1_header*) &data[0]; - const BNK2_header& bnk2 = *(const BNK2_header*) &data[0]; - - if(std::memcmp(bnk1.signature, "ADLIB-", 6) == 0) - LoadBNK1(data); - else if(std::memcmp(bnk2.signature, "Accomp. Bank, (C) AdLib Inc", 28) == 0) - LoadBNK2(data); - else - fprintf(stderr, "%s: Unknown format\n", fn); -} - -int main(int argc, const char* const* argv) -{ - LoadBNK(argv[1]); -} diff --git a/src/dumpmiles/dumpmiles.cc b/src/dumpmiles/dumpmiles.cc deleted file mode 100644 index 2715d16..0000000 --- a/src/dumpmiles/dumpmiles.cc +++ /dev/null @@ -1,40 +0,0 @@ -//#ifdef __MINGW32__ -//typedef struct vswprintf {} swprintf; -//#endif -#include -#include - -static void LoadMiles(const char* fn) -{ - FILE* fp = fopen(fn, "rb"); - fseek(fp, 0, SEEK_END); - std::vector data(ftell(fp)); - rewind(fp); - fread(&data[0], 1, data.size(), fp), - fclose(fp); - - for(unsigned a=0; a<500; ++a) - { - unsigned gmnumber = data[a*6+0]; - unsigned gmnumber2 = data[a*6+1]; - unsigned offset = *(unsigned*)&data[a*6+2]; - - if(gmnumber == 0xFF) break; - int gmno = gmnumber2==0x7F ? gmnumber+0x80 : gmnumber; - unsigned length = data[offset] + data[offset+1]*256; - signed char notenum = data[offset+2]; - - printf("%02X %02X ", gmnumber,gmnumber2); //, offset); - for(unsigned b=0; b 3 && (b-3)%11 == 0) printf("\n "); - printf("%02X ", data[offset+b]); - } - printf("\n"); - } -} - -int main(int argc, const char* const* argv) -{ - LoadMiles(argv[1]); -} diff --git a/src/gen_adldata/file_formats/common.h b/src/gen_adldata/file_formats/common.h deleted file mode 100644 index d06059e..0000000 --- a/src/gen_adldata/file_formats/common.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef COMMON_H -#define COMMON_H - -#include - -inline uint16_t toUint16BE(const uint8_t *arr) -{ - uint16_t num = arr[1]; - num |= ((arr[0] << 8) & 0xFF00); - return num; -} - -inline int16_t toSint16BE(const uint8_t *arr) -{ - int16_t num = *reinterpret_cast(&arr[0]); - num *= 1 << 8; - num |= arr[1]; - return num; -} - -inline uint16_t toUint16LE(const uint8_t *arr) -{ - uint16_t num = arr[0]; - num |= ((arr[1] << 8) & 0xFF00); - return num; -} - -#endif // COMMON_H diff --git a/src/gen_adldata/file_formats/load_ail.h b/src/gen_adldata/file_formats/load_ail.h deleted file mode 100644 index 4c6c482..0000000 --- a/src/gen_adldata/file_formats/load_ail.h +++ /dev/null @@ -1,102 +0,0 @@ -#ifndef LOAD_AIL_H -#define LOAD_AIL_H - -#include "../progs_cache.h" -#include "../midi_inst_list.h" - -static bool LoadMiles(const char *fn, unsigned bank, const char *prefix) -{ - #ifdef HARD_BANKS - writeIni("AIL", fn, prefix, bank, INI_Both); - #endif - FILE *fp = std::fopen(fn, "rb"); - if(!fp) - return false; - std::fseek(fp, 0, SEEK_END); - std::vector data(size_t(std::ftell(fp))); - std::rewind(fp); - if(std::fread(&data[0], 1, data.size(), fp) != data.size()) - { - std::fclose(fp); - return false; - } - std::fclose(fp); - - for(unsigned a = 0; a < 2000; ++a) - { - unsigned gm_patch = data[a * 6 + 0]; - unsigned gm_bank = data[a * 6 + 1]; - unsigned offset = *(unsigned *)&data[a * 6 + 2]; - - if(gm_patch == 0xFF) - break; - - int gmno = gm_bank == 0x7F ? int(gm_patch + 0x80) : int(gm_patch); - int midi_index = gmno < 128 ? gmno - : gmno < 128 + 35 ? -1 - : gmno < 128 + 88 ? gmno - 35 - : -1; - unsigned length = data[offset] + data[offset + 1] * 256; - signed char notenum = ((signed char)data[offset + 2]); - - /*printf("%02X %02X %08X ", gmnumber,gmnumber2, offset); - for(unsigned b=0; b 3 && (b-3)%11 == 0) printf("\n "); - printf("%02X ", data[offset+b]); - } - printf("\n");*/ - - if(gm_bank != 0 && gm_bank != 0x7F) - continue; - - char name2[512]; - sprintf(name2, "%s%c%u", prefix, - (gmno < 128 ? 'M' : 'P'), gmno & 127); - - insdata tmp[200]; - - const unsigned inscount = (length - 3) / 11; - for(unsigned i = 0; i < inscount; ++i) - { - unsigned o = offset + 3 + i * 11; - tmp[i].finetune = (gmno < 128 && i == 0) ? notenum : 0; - tmp[i].diff = false; - tmp[i].data[0] = data[o + 0]; // 20 - tmp[i].data[8] = data[o + 1]; // 40 (vol) - tmp[i].data[2] = data[o + 2]; // 60 - tmp[i].data[4] = data[o + 3]; // 80 - tmp[i].data[6] = data[o + 4]; // E0 - tmp[i].data[1] = data[o + 6]; // 23 - tmp[i].data[9] = data[o + 7]; // 43 (vol) - tmp[i].data[3] = data[o + 8]; // 63 - tmp[i].data[5] = data[o + 9]; // 83 - tmp[i].data[7] = data[o + 10]; // E3 - - unsigned fb_c = data[offset + 3 + 5]; - tmp[i].data[10] = uint8_t(fb_c); - if(i == 1) - { - tmp[0].data[10] = fb_c & 0x0F; - tmp[1].data[10] = uint8_t((fb_c & 0x0E) | (fb_c >> 7)); - } - } - if(inscount == 1) - tmp[1] = tmp[0]; - - if(inscount <= 2) - { - struct ins tmp2; - tmp2.notenum = gmno < 128 ? 0 : (unsigned char)notenum; - tmp2.pseudo4op = false; - tmp2.voice2_fine_tune = 0.0; - std::string name; - if(midi_index >= 0) name = std::string(1, '\377') + MidiInsName[midi_index]; - size_t resno = InsertIns(tmp[0], tmp[1], tmp2, name, name2); - SetBank(bank, (unsigned int)gmno, resno); - } - } - return true; -} - -#endif // LOAD_AIL_H diff --git a/src/gen_adldata/file_formats/load_bisqwit.h b/src/gen_adldata/file_formats/load_bisqwit.h deleted file mode 100644 index 4928efa..0000000 --- a/src/gen_adldata/file_formats/load_bisqwit.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef LOAD_BISQWIT_H -#define LOAD_BISQWIT_H - -#include "../progs_cache.h" -#include "../midi_inst_list.h" - -static bool LoadBisqwit(const char *fn, unsigned bank, const char *prefix) -{ - #ifdef HARD_BANKS - writeIni("Bisqwit", fn, prefix, bank, INI_Both); - #endif - FILE *fp = std::fopen(fn, "rb"); - if(!fp) - return false; - - for(uint32_t a = 0; a < 256; ++a) - { - //unsigned offset = a * 25; - uint32_t gmno = a; - int32_t midi_index = gmno < 128 ? int32_t(gmno) - : gmno < 128 + 35 ? -1 - : gmno < 128 + 88 ? int32_t(gmno - 35) - : -1; - - struct ins tmp2; - tmp2.notenum = (uint8_t)std::fgetc(fp); - tmp2.pseudo4op = false; - tmp2.voice2_fine_tune = 0.0; - - insdata tmp[2]; - for(int side = 0; side < 2; ++side) - { - tmp[side].finetune = (int8_t)std::fgetc(fp); - tmp[side].diff = false; - if(std::fread(tmp[side].data, 1, 11, fp) != 11) - return false; - } - - std::string name; - if(midi_index >= 0) name = std::string(1, '\377') + MidiInsName[midi_index]; - - char name2[512]; - sprintf(name2, "%s%c%u", prefix, - (gmno < 128 ? 'M' : 'P'), gmno & 127); - - size_t resno = InsertIns(tmp[0], tmp[1], tmp2, name, name2); - SetBank(bank, gmno, resno); - } - std::fclose(fp); - return true; -} - -#endif // LOAD_BISQWIT_H diff --git a/src/gen_adldata/file_formats/load_bnk.h b/src/gen_adldata/file_formats/load_bnk.h deleted file mode 100644 index 79ce5f5..0000000 --- a/src/gen_adldata/file_formats/load_bnk.h +++ /dev/null @@ -1,152 +0,0 @@ -#ifndef LOAD_BNK_H -#define LOAD_BNK_H - -#include "../progs_cache.h" - -#include -#include -#include - -static bool LoadBNK(const char *fn, unsigned bank, const char *prefix, bool is_fat, bool percussive) -{ - #ifdef HARD_BANKS - writeIni("HMI", fn, prefix, bank, percussive ? INI_Drums : INI_Melodic); - #endif - FILE *fp = std::fopen(fn, "rb"); - if(!fp) - return false; - std::fseek(fp, 0, SEEK_END); - std::vector data(size_t(std::ftell(fp))); - std::rewind(fp); - if(std::fread(&data[0], 1, data.size(), fp) != data.size()) - { - std::fclose(fp); - return false; - } - std::fclose(fp); - - /*printf("%s:\n", fn);*/ - //unsigned short version = *(short*)&data[0]; // major,minor (2 bytes) - // "ADLIB-" (6 bytes) - uint16_t entries_used = *(uint16_t *)&data[8]; // entries used - //unsigned short total_entries = *(short*)&data[10]; // total entries - unsigned name_offset = *(unsigned *)&data[12]; // name_offset - unsigned data_offset = *(unsigned *)&data[16]; // data_offset - // 16..23: 8 byte sof filler - /*printf("version=%u %u %u %u %u\n", - version, entries_used,total_entries,name_offset,data_offset);*/ - - for(unsigned n = 0; n < entries_used; ++n) - { - const size_t offset1 = name_offset + n * 12; - - unsigned short data_index = data[offset1 + 0] + data[offset1 + 1] * 256; - unsigned char usage_flag = data[offset1 + 2]; - std::string name; - for(unsigned p = 0; p < 9; ++p) - { - if(data[offset1 + 3 + p] == '\0') break; - name += char(data[offset1 + 3 + p]); - } - - const size_t offset2 = data_offset + data_index * 30; - //const unsigned char mode = data[offset2+0]; - const unsigned char voice_num = data[offset2 + 1]; - const unsigned char *op1 = &data[offset2 + 2]; // 13 bytes - const unsigned char *op2 = &data[offset2 + 15]; - const unsigned char waveform_mod = data[offset2 + 28]; - const unsigned char waveform_car = data[offset2 + 29]; - - /*printf("%5d %3d %8s mode=%02X voice=%02X: ", data_index,usage_flag, name.c_str(), - mode,voice_num);*/ - - int gmno = int(is_fat - ? ((n & 127) + percussive * 128) - : (n + percussive * 128)); - - if(is_fat && percussive) - { - if(name[2] == 'O' - || name[2] == 'S') - { - gmno = 128 + std::stoi(name.substr(3)); - } - } - - char name2[512]; - if(is_fat) - sprintf(name2, "%s%c%u", prefix, percussive ? 'P' : 'M', gmno & 127); - else - sprintf(name2, "%s%u", prefix, n); - - insdata tmp; - tmp.data[0] = uint8_t( - (op1[ 9] << 7) // TREMOLO FLAG - + (op1[10] << 6) // VIBRATO FLAG - + (op1[ 5] << 5) // SUSTAIN FLAG - + (op1[11] << 4) // SCALING FLAG - + op1[ 1]); // FREQMUL - - tmp.data[1] = uint8_t((op2[ 9] << 7) - + (op2[10] << 6) - + (op2[ 5] << 5) - + (op2[11] << 4) - + op2[ 1]); - tmp.data[2] = op1[3] * 0x10 + op1[6]; // ATTACK, DECAY - tmp.data[3] = op2[3] * 0x10 + op2[6]; - tmp.data[4] = op1[4] * 0x10 + op1[7]; // SUSTAIN, RELEASE - tmp.data[5] = op2[4] * 0x10 + op2[7]; - tmp.data[6] = waveform_mod; - tmp.data[7] = waveform_car; - tmp.data[8] = op1[0] * 0x40 + op1[8]; // KSL , LEVEL - tmp.data[9] = op2[0] * 0x40 + op2[8]; // KSL , LEVEL - tmp.data[10] = op1[2] * 2 + op1[12]; // FEEDBACK, ADDITIVEFLAG - tmp.finetune = 0; - tmp.diff = false; - // Note: op2[2] and op2[12] are unused and contain garbage. - ins tmp2; - tmp2.notenum = is_fat ? voice_num : (percussive ? usage_flag : 0); - tmp2.pseudo4op = false; - tmp2.voice2_fine_tune = 0.0; - - if(is_fat) tmp.data[10] ^= 1; - - size_t resno = InsertIns(tmp, tmp, tmp2, std::string(1, '\377') + name, name2); - - if(!is_fat) - { - SetBank(bank, (unsigned int)gmno, resno); - } - else - { - if(name[2] == 'O' || name[1] == 'M') SetBank(bank + 0, (unsigned int)gmno, resno); - if(name[2] == 'S' || name[1] == 'M') SetBank(bank + 1, (unsigned int)gmno, resno); - } - - /* - for(unsigned p=0; p<30; ++p) - { - unsigned char value = data[offset2+p]; - if(value > maxvalues[p]) maxvalues[p] = value; - - #define dot(maxval) if(value<=maxval) printf("."); else printf("?[%u]%X",p,value); - - { - //if(p==6 || p==7 || p==19||p==20) value=15-value; - - if(p==4 || p==10 || p==17 || p==23)// || p==25) - printf(" %2X", value); - else - printf(" %X", value); - } - nl:; - //if(p == 12) printf("\n%*s", 22, ""); - //if(p == 25) printf("\n%*s", 22, ""); - } - printf("\n"); - */ - } - return true; -} - -#endif // LOAD_BNK_H diff --git a/src/gen_adldata/file_formats/load_bnk2.h b/src/gen_adldata/file_formats/load_bnk2.h deleted file mode 100644 index 202402c..0000000 --- a/src/gen_adldata/file_formats/load_bnk2.h +++ /dev/null @@ -1,102 +0,0 @@ -#ifndef LOAD_BNK2_H -#define LOAD_BNK2_H - -#include "../progs_cache.h" - -static bool LoadBNK2(const char *fn, unsigned bank, const char *prefix, - const std::string &melo_filter, - const std::string &perc_filter) -{ - #ifdef HARD_BANKS - writeIni("AdLibGold", fn, prefix, bank, INI_Both, melo_filter.c_str(), perc_filter.c_str()); - #endif - FILE *fp = std::fopen(fn, "rb"); - if(!fp) - return false; - std::fseek(fp, 0, SEEK_END); - std::vector data(size_t(std::ftell(fp))); - std::rewind(fp); - if(std::fread(&data[0], 1, data.size(), fp) != data.size()) - { - std::fclose(fp); - return false; - } - std::fclose(fp); - - unsigned short ins_entries = *(unsigned short *)&data[28 + 2 + 10]; - unsigned char *records = &data[48]; - - for(unsigned n = 0; n < ins_entries; ++n) - { - const size_t offset1 = n * 28; - int used = records[offset1 + 15]; - //int attrib = *(int*)&records[offset1 + 16]; - int offset2 = *(int *)&records[offset1 + 20]; - if(used == 0) continue; - - std::string name; - for(unsigned p = 0; p < 12; ++p) - { - if(records[offset1 + 3 + p] == '\0') break; - name += char(records[offset1 + 3 + p]); - } - - int gmno = 0; - if(name.substr(0, melo_filter.size()) == melo_filter) - gmno = std::stoi(name.substr(melo_filter.size())); - else if(name.substr(0, perc_filter.size()) == perc_filter) - gmno = std::stoi(name.substr(perc_filter.size())) + 128; - else - continue; - - const unsigned char *insdata = &data[size_t(offset2)]; - const unsigned char *ops[4] = { insdata + 0, insdata + 6, insdata + 12, insdata + 18 }; - unsigned char C4xxxFFFC = insdata[24]; - unsigned char xxP24NNN = insdata[25]; - unsigned char TTTTTTTT = insdata[26]; - //unsigned char xxxxxxxx = insdata[27]; - - char name2[512]; - sprintf(name2, "%s%c%u", prefix, (gmno & 128) ? 'P' : 'M', gmno & 127); - - struct insdata tmp[2]; - for(unsigned a = 0; a < 2; ++a) - { - tmp[a].data[0] = ops[a * 2 + 0][0]; - tmp[a].data[1] = ops[a * 2 + 1][0]; - tmp[a].data[2] = ops[a * 2 + 0][2]; - tmp[a].data[3] = ops[a * 2 + 1][2]; - tmp[a].data[4] = ops[a * 2 + 0][3]; - tmp[a].data[5] = ops[a * 2 + 1][3]; - tmp[a].data[6] = ops[a * 2 + 0][4] & 0x07; - tmp[a].data[7] = ops[a * 2 + 1][4] & 0x07; - tmp[a].data[8] = ops[a * 2 + 0][1]; - tmp[a].data[9] = ops[a * 2 + 1][1]; - tmp[a].finetune = (int8_t)TTTTTTTT; - tmp[a].diff = false; - } - tmp[0].data[10] = C4xxxFFFC & 0x0F; - tmp[1].data[10] = (tmp[0].data[10] & 0x0E) | (C4xxxFFFC >> 7); - - ins tmp2; - tmp2.notenum = (gmno & 128) ? 35 : 0; - tmp2.pseudo4op = false; - tmp2.voice2_fine_tune = 0.0; - - if(xxP24NNN & 8) - { - // dual-op - size_t resno = InsertIns(tmp[0], tmp[1], tmp2, std::string(1, '\377') + name, name2); - SetBank(bank, (unsigned int)gmno, resno); - } - else - { - // single-op - size_t resno = InsertIns(tmp[0], tmp[0], tmp2, std::string(1, '\377') + name, name2); - SetBank(bank, (unsigned int)gmno, resno); - } - } - return true; -} - -#endif // LOAD_BNK2_H diff --git a/src/gen_adldata/file_formats/load_ibk.h b/src/gen_adldata/file_formats/load_ibk.h deleted file mode 100644 index 6370ad0..0000000 --- a/src/gen_adldata/file_formats/load_ibk.h +++ /dev/null @@ -1,72 +0,0 @@ -#ifndef LOAD_IBK_H -#define LOAD_IBK_H - -#include "../progs_cache.h" - -static bool LoadIBK(const char *fn, unsigned bank, const char *prefix, bool percussive) -{ - #ifdef HARD_BANKS - writeIni("IBK", fn, prefix, bank, percussive ? INI_Drums : INI_Melodic); - #endif - FILE *fp = std::fopen(fn, "rb"); - if(!fp) - return false; - std::fseek(fp, 0, SEEK_END); - std::vector data(size_t(std::ftell(fp))); - std::rewind(fp); - if(std::fread(&data[0], 1, data.size(), fp) != data.size()) - { - std::fclose(fp); - return false; - } - std::fclose(fp); - - unsigned offs1_base = 0x804, offs1_len = 9; - unsigned offs2_base = 0x004, offs2_len = 16; - - for(unsigned a = 0; a < 128; ++a) - { - unsigned offset1 = offs1_base + a * offs1_len; - unsigned offset2 = offs2_base + a * offs2_len; - - std::string name; - for(unsigned p = 0; p < 9; ++p) - if(data[offset1] != '\0') - name += char(data[offset1 + p]); - - int gmno = int(a + 128 * percussive); - /*int midi_index = gmno < 128 ? gmno - : gmno < 128+35 ? -1 - : gmno < 128+88 ? gmno-35 - : -1;*/ - char name2[512]; - sprintf(name2, "%s%c%u", prefix, - (gmno < 128 ? 'M' : 'P'), gmno & 127); - - insdata tmp; - tmp.data[0] = data[offset2 + 0]; - tmp.data[1] = data[offset2 + 1]; - tmp.data[8] = data[offset2 + 2]; - tmp.data[9] = data[offset2 + 3]; - tmp.data[2] = data[offset2 + 4]; - tmp.data[3] = data[offset2 + 5]; - tmp.data[4] = data[offset2 + 6]; - tmp.data[5] = data[offset2 + 7]; - tmp.data[6] = data[offset2 + 8]; - tmp.data[7] = data[offset2 + 9]; - tmp.data[10] = data[offset2 + 10]; - // [+11] seems to be used also, what is it for? - tmp.finetune = 0; - tmp.diff = false; - struct ins tmp2; - tmp2.notenum = gmno < 128 ? 0 : 35; - tmp2.pseudo4op = false; - tmp2.voice2_fine_tune = 0.0; - - size_t resno = InsertIns(tmp, tmp, tmp2, std::string(1, '\377') + name, name2); - SetBank(bank, (unsigned int)gmno, resno); - } - return true; -} - -#endif // LOAD_IBK_H diff --git a/src/gen_adldata/file_formats/load_jv.h b/src/gen_adldata/file_formats/load_jv.h deleted file mode 100644 index f35de03..0000000 --- a/src/gen_adldata/file_formats/load_jv.h +++ /dev/null @@ -1,105 +0,0 @@ -#ifndef LOAD_JV_H -#define LOAD_JV_H - -#include "../progs_cache.h" -#include "../midi_inst_list.h" - -static bool LoadJunglevision(const char *fn, unsigned bank, const char *prefix) -{ - #ifdef HARD_BANKS - writeIni("Junglevision", fn, prefix, bank, INI_Both); - #endif - FILE *fp = std::fopen(fn, "rb"); - if(!fp) - return false; - std::fseek(fp, 0, SEEK_END); - std::vector data(size_t(std::ftell(fp))); - std::rewind(fp); - if(std::fread(&data[0], 1, data.size(), fp) != data.size()) - { - std::fclose(fp); - return false; - } - std::fclose(fp); - - uint16_t ins_count = uint16_t(data[0x20] + (data[0x21] << 8)); - uint16_t drum_count = uint16_t(data[0x22] + (data[0x23] << 8)); - uint16_t first_ins = uint16_t(data[0x24] + (data[0x25] << 8)); - uint16_t first_drum = uint16_t(data[0x26] + (data[0x27] << 8)); - - unsigned total_ins = ins_count + drum_count; - - for(unsigned a = 0; a < total_ins; ++a) - { - unsigned offset = 0x28 + a * 0x18; - unsigned gmno = (a < ins_count) ? (a + first_ins) : (a + first_drum); - int midi_index = gmno < 128 ? int(gmno) - : gmno < 128 + 35 ? -1 - : gmno < 128 + 88 ? int(gmno - 35) - : -1; - - insdata tmp[2]; - - tmp[0].data[0] = data[offset + 2]; - tmp[0].data[1] = data[offset + 8]; - tmp[0].data[2] = data[offset + 4]; - tmp[0].data[3] = data[offset + 10]; - tmp[0].data[4] = data[offset + 5]; - tmp[0].data[5] = data[offset + 11]; - tmp[0].data[6] = data[offset + 6]; - tmp[0].data[7] = data[offset + 12]; - tmp[0].data[8] = data[offset + 3]; - tmp[0].data[9] = data[offset + 9]; - tmp[0].data[10] = data[offset + 7] & 0x0F;//~0x30; - tmp[0].finetune = 0; - tmp[0].diff = false; - - tmp[1].data[0] = data[offset + 2 + 11]; - tmp[1].data[1] = data[offset + 8 + 11]; - tmp[1].data[2] = data[offset + 4 + 11]; - tmp[1].data[3] = data[offset + 10 + 11]; - tmp[1].data[4] = data[offset + 5 + 11]; - tmp[1].data[5] = data[offset + 11 + 11]; - tmp[1].data[6] = data[offset + 6 + 11]; - tmp[1].data[7] = data[offset + 12 + 11]; - tmp[1].data[8] = data[offset + 3 + 11]; - tmp[1].data[9] = data[offset + 9 + 11]; - tmp[1].data[10] = data[offset + 7 + 11] & 0x0F;//~0x30; - tmp[1].finetune = 0; - tmp[1].diff = false; - - struct ins tmp2; - tmp2.notenum = data[offset + 1]; - tmp2.pseudo4op = false; - tmp2.voice2_fine_tune = 0.0; - - while(tmp2.notenum && tmp2.notenum < 20) - { - tmp2.notenum += 12; - tmp[0].finetune -= 12; - tmp[1].finetune -= 12; - } - - std::string name; - if(midi_index >= 0) name = std::string(1, '\377') + MidiInsName[midi_index]; - - char name2[512]; - sprintf(name2, "%s%c%u", prefix, - (gmno < 128 ? 'M' : 'P'), gmno & 127); - - if(!data[offset]) - { - size_t resno = InsertIns(tmp[0], tmp[0], tmp2, name, name2); - SetBank(bank, gmno, resno); - } - else // Double instrument - { - size_t resno = InsertIns(tmp[0], tmp[1], tmp2, name, name2); - SetBank(bank, gmno, resno); - } - } - return true; -} - -#endif // LOAD_JV_H - diff --git a/src/gen_adldata/file_formats/load_op2.h b/src/gen_adldata/file_formats/load_op2.h deleted file mode 100644 index 30a118f..0000000 --- a/src/gen_adldata/file_formats/load_op2.h +++ /dev/null @@ -1,148 +0,0 @@ -#ifndef LOAD_OP2_H -#define LOAD_OP2_H - -#include "../progs_cache.h" - -#pragma pack(push, 1) -struct Doom_OPL2instrument -{ - unsigned char trem_vibr_1; /* OP 1: tremolo/vibrato/sustain/KSR/multi */ - unsigned char att_dec_1; /* OP 1: attack rate/decay rate */ - unsigned char sust_rel_1; /* OP 1: sustain level/release rate */ - unsigned char wave_1; /* OP 1: waveform select */ - unsigned char scale_1; /* OP 1: key scale level */ - unsigned char level_1; /* OP 1: output level */ - unsigned char feedback; /* feedback/AM-FM (both operators) */ - unsigned char trem_vibr_2; /* OP 2: tremolo/vibrato/sustain/KSR/multi */ - unsigned char att_dec_2; /* OP 2: attack rate/decay rate */ - unsigned char sust_rel_2; /* OP 2: sustain level/release rate */ - unsigned char wave_2; /* OP 2: waveform select */ - unsigned char scale_2; /* OP 2: key scale level */ - unsigned char level_2; /* OP 2: output level */ - unsigned char unused; - short basenote; /* base note offset */ -} __attribute__((packed)); -#pragma pack(pop) - -struct Doom_opl_instr -{ - unsigned short flags; -#define FL_FIXED_PITCH 0x0001 // note has fixed pitch (drum note) -#define FL_UNKNOWN 0x0002 // ??? (used in instrument #65 only) -#define FL_DOUBLE_VOICE 0x0004 // use two voices instead of one - - unsigned char finetune; - unsigned char note; - struct Doom_OPL2instrument patchdata[2]; -} __attribute__((packed)); - - -static bool LoadDoom(const char *fn, unsigned bank, const char *prefix) -{ - #ifdef HARD_BANKS - writeIni("OP2", fn, prefix, bank, INI_Both); - #endif - FILE *fp = std::fopen(fn, "rb"); - if(!fp) - return false; - std::fseek(fp, 0, SEEK_END); - std::vector data(size_t(std::ftell(fp))); - std::rewind(fp); - - if(std::fread(&data[0], 1, data.size(), fp) != data.size()) - { - std::fclose(fp); - return false; - } - std::fclose(fp); - - for(unsigned a = 0; a < 175; ++a) - { - const size_t offset1 = 0x18A4 + a * 32; - const size_t offset2 = 8 + a * 36; - - std::string name; - for(unsigned p = 0; p < 32; ++p) - if(data[offset1] != '\0') - name += char(data[offset1 + p]); - - //printf("%3d %3d %3d %8s: ", a,b,c, name.c_str()); - int gmno = int(a < 128 ? a : ((a | 128) + 35)); - - char name2[512]; - sprintf(name2, "%s%c%u", prefix, (gmno < 128 ? 'M' : 'P'), gmno & 127); - - Doom_opl_instr &ins = *(Doom_opl_instr *) &data[offset2]; - - insdata tmp[2]; - tmp[0].diff = false; - tmp[1].diff = true; - for(unsigned index = 0; index < 2; ++index) - { - const Doom_OPL2instrument &src = ins.patchdata[index]; - tmp[index].data[0] = src.trem_vibr_1; - tmp[index].data[1] = src.trem_vibr_2; - tmp[index].data[2] = src.att_dec_1; - tmp[index].data[3] = src.att_dec_2; - tmp[index].data[4] = src.sust_rel_1; - tmp[index].data[5] = src.sust_rel_2; - tmp[index].data[6] = src.wave_1; - tmp[index].data[7] = src.wave_2; - tmp[index].data[8] = src.scale_1 | src.level_1; - tmp[index].data[9] = src.scale_2 | src.level_2; - tmp[index].data[10] = src.feedback; - tmp[index].finetune = int8_t(src.basenote + 12); - } - struct ins tmp2; - tmp2.notenum = ins.note; - tmp2.pseudo4op = false; - tmp2.voice2_fine_tune = 0.0; - while(tmp2.notenum && tmp2.notenum < 20) - { - tmp2.notenum += 12; - tmp[0].finetune -= 12; - tmp[1].finetune -= 12; - } - - if(!(ins.flags & 4)) - { - size_t resno = InsertIns(tmp[0], tmp[0], tmp2, std::string(1, '\377') + name, name2); - SetBank(bank, (unsigned int)gmno, resno); - } - else // Double instrument - { - tmp2.pseudo4op = true; - tmp2.voice2_fine_tune = (((double)ins.finetune - 128.0) * 15.625) / 1000.0; - if(ins.finetune == 129) - tmp2.voice2_fine_tune = 0.000025; - else if(ins.finetune == 127) - tmp2.voice2_fine_tune = -0.000025; - //printf("/*DOOM FINE TUNE (flags %000X instrument is %d) IS %d -> %lf*/\n", ins.flags, a, ins.finetune, tmp2.fine_tune); - size_t resno = InsertIns(tmp[0], tmp[1], tmp2, std::string(1, '\377') + name, name2); - SetBank(bank, (unsigned int)gmno, resno); - } - - /*const Doom_OPL2instrument& A = ins.patchdata[0]; - const Doom_OPL2instrument& B = ins.patchdata[1]; - printf( - "flags:%04X fine:%02X note:%02X\n" - "{t:%02X a:%02X s:%02X w:%02X s:%02X l:%02X f:%02X\n" - " t:%02X a:%02X s:%02X w:%02X s:%02X l:%02X ?:%02X base:%d}\n" - "{t:%02X a:%02X s:%02X w:%02X s:%02X l:%02X f:%02X\n" - " t:%02X a:%02X s:%02X w:%02X s:%02X l:%02X ?:%02X base:%d} ", - ins.flags, ins.finetune, ins.note, - A.trem_vibr_1, A.att_dec_1, A.sust_rel_1, - A.wave_1, A.scale_1, A.level_1, A.feedback, - A.trem_vibr_2, A.att_dec_2, A.sust_rel_2, - A.wave_2, A.scale_2, A.level_2, A.unused, A.basenote, - B.trem_vibr_1, B.att_dec_1, B.sust_rel_1, - B.wave_1, B.scale_1, B.level_1, B.feedback, - B.trem_vibr_2, B.att_dec_2, B.sust_rel_2, - B.wave_2, B.scale_2, B.level_2, B.unused, B.basenote); - printf(" %s VS %s\n", name.c_str(), MidiInsName[a]); - printf("------------------------------------------------------------\n");*/ - } - return true; -} - -#endif // LOAD_OP2_H diff --git a/src/gen_adldata/file_formats/load_tmb.h b/src/gen_adldata/file_formats/load_tmb.h deleted file mode 100644 index c5a3f60..0000000 --- a/src/gen_adldata/file_formats/load_tmb.h +++ /dev/null @@ -1,68 +0,0 @@ -#ifndef LOAD_TMB_H -#define LOAD_TMB_H - -#include "../progs_cache.h" -#include "../midi_inst_list.h" - -static bool LoadTMB(const char *fn, unsigned bank, const char *prefix) -{ - #ifdef HARD_BANKS - writeIni("TMB", fn, prefix, bank, INI_Both); - #endif - FILE *fp = std::fopen(fn, "rb"); - if(!fp) - return false; - std::fseek(fp, 0, SEEK_END); - std::vector data(size_t(std::ftell(fp))); - std::rewind(fp); - if(std::fread(&data[0], 1, data.size(), fp) != data.size()) - { - std::fclose(fp); - return false; - } - std::fclose(fp); - - for(unsigned a = 0; a < 256; ++a) - { - unsigned offset = a * 0x0D; - unsigned gmno = a; - int midi_index = gmno < 128 ? int(gmno) - : gmno < 128 + 35 ? -1 - : gmno < 128 + 88 ? int(gmno - 35) - : -1; - - insdata tmp; - - tmp.data[0] = data[offset + 0]; - tmp.data[1] = data[offset + 1]; - tmp.data[2] = data[offset + 4]; - tmp.data[3] = data[offset + 5]; - tmp.data[4] = data[offset + 6]; - tmp.data[5] = data[offset + 7]; - tmp.data[6] = data[offset + 8]; - tmp.data[7] = data[offset + 9]; - tmp.data[8] = data[offset + 2]; - tmp.data[9] = data[offset + 3]; - tmp.data[10] = data[offset + 10]; - tmp.finetune = 0; //data[offset + 12]; - tmp.diff = false; - - struct ins tmp2; - tmp2.notenum = data[offset + 11]; - tmp2.pseudo4op = false; - tmp2.voice2_fine_tune = 0.0; - - std::string name; - if(midi_index >= 0) name = std::string(1, '\377') + MidiInsName[midi_index]; - - char name2[512]; - sprintf(name2, "%s%c%u", prefix, - (gmno < 128 ? 'M' : 'P'), gmno & 127); - - size_t resno = InsertIns(tmp, tmp, tmp2, name, name2); - SetBank(bank, gmno, resno); - } - return true; -} - -#endif // LOAD_TMB_H diff --git a/src/gen_adldata/file_formats/load_wopl.h b/src/gen_adldata/file_formats/load_wopl.h deleted file mode 100644 index 300a3a0..0000000 --- a/src/gen_adldata/file_formats/load_wopl.h +++ /dev/null @@ -1,265 +0,0 @@ -#ifndef LOAD_WOPL_H -#define LOAD_WOPL_H - -#include "../progs_cache.h" -#include "../midi_inst_list.h" -#include "common.h" - -static uint8_t wopl_latest_version = 2; - -static bool LoadWopl(const char *fn, unsigned bank, const char *prefix) -{ - FILE *fp = std::fopen(fn, "rb"); - if(!fp) - { - std::fprintf(stderr, "WOPL: CAN'T OPEN FILE %s\n", fn); - std::fflush(stderr); - return false; - } - std::fseek(fp, 0, SEEK_END); - std::vector data(size_t(std::ftell(fp))); - std::rewind(fp); - if(std::fread(&data[0], 1, data.size(), fp) != data.size()) - { - std::fclose(fp); - std::fprintf(stderr, "WOPL: CAN'T READ FILE %s\n", fn); - std::fflush(stderr); - return false; - } - std::fclose(fp); - - if(data.size() < 19) // Smaller than header size - { - std::fprintf(stderr, "WOPL: Too small header %s\n", fn); - std::fflush(stderr); - return false; - } - - uint16_t version = toUint16LE((const uint8_t *)data.data() + 11); - if(version > wopl_latest_version) - { - std::fprintf(stderr, "WOPL: Version %d is not supported (latest %d) %s\n", version, wopl_latest_version, fn); - std::fflush(stderr); - return false; - } - - uint16_t mbanks_count = toUint16BE((const uint8_t *)data.data() + 0x0d); - uint16_t pbanks_count = toUint16BE((const uint8_t *)data.data() + 0x0f); - - // Validate file format by size calculation - if(version == 1) - { - //Header size + melodic banks + percussion banks - if(data.size() < size_t(19 + (62 * 128 * mbanks_count) + (62 * 128 * pbanks_count))) - { - std::fprintf(stderr, "WOPL: Version 1 size calculation failed %s\n", fn); - std::fflush(stderr); - return false; - } - } - else if(version >= 2) - { - //Header size + melodic bank meta data + percussion bank meta data + melodic banks + percussion banks - if(data.size() < size_t(19 + (34 * mbanks_count) + (34 * pbanks_count) + (62 * 128 * mbanks_count) + (62 * 128 * pbanks_count))) - { - std::fprintf(stderr, "WOPL: Version %d size calculation failed %s\n", version, fn); - std::fflush(stderr); - return false; - } - } - - uint32_t melodic_offset = 0; - uint32_t percussion_offset = 0; - if(version < 2) - melodic_offset = 0x13; - else - melodic_offset = 0x13 + 34 * mbanks_count + 34 * pbanks_count; - - percussion_offset = melodic_offset + (62 * 128 * mbanks_count); - - for(uint32_t mbank = 0; mbank < 1; mbank++) // only first melodic bank (Until multi-banks support will be implemented) - { - uint32_t bank_offset = melodic_offset + (mbank * 62 * 128); - - for(unsigned i = 0; i < 128; i++) - { - uint32_t offset = bank_offset + uint32_t(i * 62); - std::string name; - insdata tmp[2]; - - name.resize(32); - std::memcpy(&name[0], data.data() + offset, 32); - name.resize(std::strlen(&name[0])); - - tmp[0].data[0] = data[offset + 42 + 5]; - tmp[0].data[1] = data[offset + 42 + 0]; - tmp[0].data[2] = data[offset + 42 + 7]; - tmp[0].data[3] = data[offset + 42 + 2]; - tmp[0].data[4] = data[offset + 42 + 8]; - tmp[0].data[5] = data[offset + 42 + 3]; - tmp[0].data[6] = data[offset + 42 + 9]; - tmp[0].data[7] = data[offset + 42 + 4]; - tmp[0].data[8] = data[offset + 42 + 6]; - tmp[0].data[9] = data[offset + 42 + 1]; - tmp[0].data[10] = data[offset + 40]; - - tmp[1].data[0] = data[offset + 52 + 5]; - tmp[1].data[1] = data[offset + 52 + 0]; - tmp[1].data[2] = data[offset + 52 + 7]; - tmp[1].data[3] = data[offset + 52 + 2]; - tmp[1].data[4] = data[offset + 52 + 8]; - tmp[1].data[5] = data[offset + 52 + 3]; - tmp[1].data[6] = data[offset + 52 + 9]; - tmp[1].data[7] = data[offset + 52 + 4]; - tmp[1].data[8] = data[offset + 52 + 6]; - tmp[1].data[9] = data[offset + 52 + 1]; - tmp[1].data[10] = data[offset + 41]; - - tmp[0].finetune = int8_t(toSint16BE((const uint8_t *)data.data() + offset + 32)); - tmp[1].finetune = int8_t(toSint16BE((const uint8_t *)data.data() + offset + 34)); - - uint8_t flags = data[offset + 39]; - - struct ins tmp2; - tmp2.notenum = 0; - tmp2.pseudo4op = (flags & 0x02) != 0; - tmp2.voice2_fine_tune = 0; - tmp[0].diff = false; - tmp[1].diff = tmp2.pseudo4op; - - int8_t fine_tune = (int8_t)data[offset + 37]; - if(fine_tune != 0) - { - if(fine_tune == 1) - tmp2.voice2_fine_tune = 0.000025; - else if(fine_tune == -1) - tmp2.voice2_fine_tune = -0.000025; - else - tmp2.voice2_fine_tune = ((fine_tune * 15.625) / 1000.0); - } - - if(name.empty()) - name = std::string(1, '\377') + MidiInsName[i]; - else - name.insert(0, 1, '\377'); - - char name2[512]; - sprintf(name2, "%sM%u", prefix, i); - - if((flags & 0x03) == 0) - { - size_t resno = InsertIns(tmp[0], tmp[0], tmp2, name, name2); - SetBank(bank, i, resno); - } - else - { - size_t resno = InsertIns(tmp[0], tmp[1], tmp2, name, name2); - SetBank(bank, i, resno); - } - } - } - - for(uint32_t pbank = 0; pbank < 1; pbank++) // only first percussion bank (Until multi-banks support will be implemented) - { - uint32_t bank_offset = percussion_offset + (pbank * 62 * 128); - - for(uint32_t i = 0; i < 128; i++) - { - uint32_t offset = bank_offset + (i * 62); - std::string name; - insdata tmp[2]; - - name.resize(32); - std::memcpy(&name[0], data.data() + offset, 32); - name.resize(std::strlen(&name[0])); -/* - WOPL's - - 0 AM/Vib/Env/Ksr/FMult characteristics - 1 Key Scale Level / Total level register data - 2 Attack / Decay - 3 Systain and Release register data - 4 Wave form - - 5 AM/Vib/Env/Ksr/FMult characteristics - 6 Key Scale Level / Total level register data - 7 Attack / Decay - 8 Systain and Release register data - 9 Wave form -*/ - tmp[0].data[0] = data[offset + 42 + 5];//AMVIB op1 - tmp[0].data[1] = data[offset + 42 + 0];//AMVIB op2 - tmp[0].data[2] = data[offset + 42 + 7];//AtDec op1 - tmp[0].data[3] = data[offset + 42 + 2];//AtDec op2 - tmp[0].data[4] = data[offset + 42 + 8];//SusRel op1 - tmp[0].data[5] = data[offset + 42 + 3];//SusRel op2 - tmp[0].data[6] = data[offset + 42 + 9];//Wave op1 - tmp[0].data[7] = data[offset + 42 + 4];//Wave op2 - tmp[0].data[8] = data[offset + 42 + 6];//KSL op1 - tmp[0].data[9] = data[offset + 42 + 1];//KSL op2 - tmp[0].data[10] = data[offset + 40]; - - tmp[1].data[0] = data[offset + 52 + 5]; - tmp[1].data[1] = data[offset + 52 + 0]; - tmp[1].data[2] = data[offset + 52 + 7]; - tmp[1].data[3] = data[offset + 52 + 2]; - tmp[1].data[4] = data[offset + 52 + 8]; - tmp[1].data[5] = data[offset + 52 + 3]; - tmp[1].data[6] = data[offset + 52 + 9]; - tmp[1].data[7] = data[offset + 52 + 4]; - tmp[1].data[8] = data[offset + 52 + 6]; - tmp[1].data[9] = data[offset + 52 + 1]; - tmp[1].data[10] = data[offset + 41]; - - tmp[0].finetune = int8_t(toSint16BE((const uint8_t *)data.data() + offset + 32)); - tmp[1].finetune = int8_t(toSint16BE((const uint8_t *)data.data() + offset + 34)); - uint8_t flags = data[offset + 39]; - - struct ins tmp2; - tmp2.notenum = data[offset + 38]; - tmp2.pseudo4op = (flags & 0x02) != 0; - tmp2.voice2_fine_tune = 0; - tmp[0].diff = false; - tmp[1].diff = tmp2.pseudo4op; - - int8_t fine_tune = (int8_t)data[offset + 37]; - if(fine_tune != 0) - { - if(fine_tune == 1) - tmp2.voice2_fine_tune = 0.000025; - else if(fine_tune == -1) - tmp2.voice2_fine_tune = -0.000025; - else - tmp2.voice2_fine_tune = ((fine_tune * 15.625) / 1000.0); - } - - uint32_t gmno = i + 128; - int midi_index = (gmno < (128 + 35)) ? -1 - : (gmno < (128 + 88)) ? int(gmno) - 35 - : -1; - - if(name.empty() && (midi_index >= 0)) - name = std::string(1, '\377') + MidiInsName[midi_index]; - if(!name.empty()) - name.insert(0, 1, '\377'); - - char name2[512]; - sprintf(name2, "%sP%u", prefix, gmno & 127); - - if((flags & 0x03) == 0) - { - size_t resno = InsertIns(tmp[0], tmp[0], tmp2, name, name2); - SetBank(bank, gmno, resno); - } - else - { - size_t resno = InsertIns(tmp[0], tmp[1], tmp2, name, name2); - SetBank(bank, gmno, resno); - } - } - } - return true; -} - - -#endif // LOAD_WOPL_H diff --git a/src/gen_adldata/gen_adldata.cc b/src/gen_adldata/gen_adldata.cc deleted file mode 100644 index 6c77a12..0000000 --- a/src/gen_adldata/gen_adldata.cc +++ /dev/null @@ -1,506 +0,0 @@ -//#ifdef __MINGW32__ -//typedef struct vswprintf {} swprintf; -//#endif -#include -#include -#include - -#include "ini/ini_processing.h" - -#include "progs_cache.h" -#include "measurer.h" - -#include "midi_inst_list.h" - -#include "file_formats/load_ail.h" -#include "file_formats/load_bisqwit.h" -#include "file_formats/load_bnk2.h" -#include "file_formats/load_bnk.h" -#include "file_formats/load_ibk.h" -#include "file_formats/load_jv.h" -#include "file_formats/load_op2.h" -#include "file_formats/load_tmb.h" -#include "file_formats/load_wopl.h" - -int main(int argc, char**argv) -{ - if(argc == 1) - { - printf("Usage:\n" - "\n" - "bin/gen_adldata src/adldata.cpp\n" - "\n"); - return 1; - } - - const char *outFile_s = argv[1]; - - FILE *outFile = fopen(outFile_s, "w"); - if(!outFile) - { - fprintf(stderr, "Can't open %s file for write!\n", outFile_s); - return 1; - } - - fprintf(outFile, "\ -#include \"adldata.hh\"\n\ -\n\ -/* THIS OPL-3 FM INSTRUMENT DATA IS AUTOMATICALLY GENERATED\n\ - * FROM A NUMBER OF SOURCES, MOSTLY PC GAMES.\n\ - * PREPROCESSED, CONVERTED, AND POSTPROCESSED OFF-SCREEN.\n\ - */\n\ -"); - { - IniProcessing ini; - if(!ini.open("banks.ini")) - { - fprintf(stderr, "Can't open banks.ini!\n"); - return 1; - } - - uint32_t banks_count; - ini.beginGroup("General"); - ini.read("banks", banks_count, 0); - ini.endGroup(); - - if(!banks_count) - { - fprintf(stderr, "Zero count of banks found in banks.ini!\n"); - return 1; - } - - for(uint32_t bank = 0; bank < banks_count; bank++) - { - if(!ini.beginGroup(std::string("bank-") + std::to_string(bank))) - { - fprintf(stderr, "Failed to find bank %u!\n", bank); - return 1; - } - std::string bank_name; - std::string filepath; - std::string filepath_d; - std::string prefix; - std::string prefix_d; - std::string filter_m; - std::string filter_p; - std::string format; - - ini.read("name", bank_name, "Untitled"); - ini.read("format", format, "Unknown"); - ini.read("file", filepath, ""); - ini.read("file-p", filepath_d, ""); - ini.read("prefix", prefix, ""); - ini.read("prefix-p", prefix_d, ""); - ini.read("filter-m", filter_m, ""); - ini.read("filter-p", filter_p, ""); - - if(filepath.empty()) - { - fprintf(stderr, "Failed to load bank %u, file is empty!\n", bank); - return 1; - } - - banknames.push_back(bank_name); - - //printf("Loading %s...\n", filepath.c_str()); - - if(format == "AIL") - { - if(!LoadMiles(filepath.c_str(), bank, prefix.c_str())) - { - fprintf(stderr, "Failed to load bank %u, file %s!\n", bank, filepath.c_str()); - return 1; - } - } - else - if(format == "Bisqwit") - { - if(!LoadBisqwit(filepath.c_str(), bank, prefix.c_str())) - { - fprintf(stderr, "Failed to load bank %u, file %s!\n", bank, filepath.c_str()); - return 1; - } - } - else - if(format == "WOPL") - { - if(!LoadWopl(filepath.c_str(), bank, prefix.c_str())) - { - fprintf(stderr, "Failed to load bank %u, file %s!\n", bank, filepath.c_str()); - return 1; - } - } - else - if(format == "OP2") - { - if(!LoadDoom(filepath.c_str(), bank, prefix.c_str())) - { - fprintf(stderr, "Failed to load bank %u, file %s!\n", bank, filepath.c_str()); - return 1; - } - } - else - if(format == "TMB") - { - if(!LoadTMB(filepath.c_str(), bank, prefix.c_str())) - { - fprintf(stderr, "Failed to load bank %u, file %s!\n", bank, filepath.c_str()); - return 1; - } - } - else - if(format == "Junglevision") - { - if(!LoadJunglevision(filepath.c_str(), bank, prefix.c_str())) - { - fprintf(stderr, "Failed to load bank %u, file %s!\n", bank, filepath.c_str()); - return 1; - } - } - else - if(format == "AdLibGold") - { - if(!LoadBNK2(filepath.c_str(), bank, prefix.c_str(), filter_m, filter_p)) - { - fprintf(stderr, "Failed to load bank %u, file %s!\n", bank, filepath.c_str()); - return 1; - } - } - else - if(format == "HMI") - { - if(!LoadBNK(filepath.c_str(), bank, prefix.c_str(), false, false)) - { - fprintf(stderr, "Failed to load bank %u, file %s!\n", bank, filepath.c_str()); - return 1; - } - if(!filepath_d.empty()) - { - if(!LoadBNK(filepath_d.c_str(),bank, prefix_d.c_str(), false, true)) - { - fprintf(stderr, "Failed to load bank %u, file %s!\n", bank, filepath.c_str()); - return 1; - } - } - } - else - if(format == "IBK") - { - if(!LoadIBK(filepath.c_str(), bank, prefix.c_str(), false)) - { - fprintf(stderr, "Failed to load bank %u, file %s!\n", bank, filepath.c_str()); - return 1; - } - if(!filepath_d.empty()) - { - //printf("Loading %s... \n", filepath_d.c_str()); - if(!LoadIBK(filepath_d.c_str(),bank, prefix_d.c_str(), true)) - { - fprintf(stderr, "Failed to load bank %u, file %s!\n", bank, filepath.c_str()); - return 1; - } - } - } - else - { - fprintf(stderr, "Failed to load bank %u, file %s!\nUnknown format type %s\n", - bank, - filepath.c_str(), - format.c_str()); - return 1; - } - - - ini.endGroup(); - } - - printf("Loaded %u banks!\n", banks_count); - fflush(stdout); - } - - #if 0 - for(unsigned a = 0; a < 36 * 8; ++a) - { - if((1 << (a % 8)) > maxvalues[a / 8]) continue; - - const std::map &data = Correlate[a]; - if(data.empty()) continue; - std::vector< std::pair > correlations; - for(std::map::const_iterator - i = data.begin(); - i != data.end(); - ++i) - { - correlations.push_back(std::make_pair(i->second, i->first)); - } - std::sort(correlations.begin(), correlations.end()); - fprintf(outFile, "Byte %2u bit %u=mask %02X:\n", a / 8, a % 8, 1 << (a % 8)); - for(size_t c = 0; c < correlations.size() && c < 10; ++c) - { - unsigned count = correlations[correlations.size() - 1 - c ].first; - unsigned index = correlations[correlations.size() - 1 - c ].second; - fprintf(outFile, "\tAdldata index %u, bit %u=mask %02X (%u matches)\n", - index / 8, index % 8, 1 << (index % 8), count); - } - } - #endif - - printf("Writing raw instrument data...\n"); - fflush(stdout); - { - fprintf(outFile, - /* - "static const struct\n" - "{\n" - " unsigned modulator_E862, carrier_E862; // See below\n" - " unsigned char modulator_40, carrier_40; // KSL/attenuation settings\n" - " unsigned char feedconn; // Feedback/connection bits for the channel\n" - " signed char finetune; // Finetune\n" - "} adl[] =\n"*/ - "const adldata adl[%u] =\n" - "{ // ,---------+-------- Wave select settings\n" - " // | ,-------ч-+------ Sustain/release rates\n" - " // | | ,-----ч-ч-+---- Attack/decay rates\n" - " // | | | ,---ч-ч-ч-+-- AM/VIB/EG/KSR/Multiple bits\n" - " // | | | | | | | |\n" - " // | | | | | | | | ,----+-- KSL/attenuation settings\n" - " // | | | | | | | | | | ,----- Feedback/connection bits\n" - " // | | | | | | | | | | | ,----- Fine tune\n\n" - " // | | | | | | | | | | | |\n" - " // | | | | | | | | | | | |\n", (unsigned)insdatatab.size()); - - for(size_t b = insdatatab.size(), c = 0; c < b; ++c) - { - for(std::map > > - ::const_iterator - i = insdatatab.begin(); - i != insdatatab.end(); - ++i) - { - if(i->second.first != c) continue; - fprintf(outFile, " { "); - - uint32_t carrier_E862 = - uint32_t(i->first.data[6] << 24) - + uint32_t(i->first.data[4] << 16) - + uint32_t(i->first.data[2] << 8) - + uint32_t(i->first.data[0] << 0); - uint32_t modulator_E862 = - uint32_t(i->first.data[7] << 24) - + uint32_t(i->first.data[5] << 16) - + uint32_t(i->first.data[3] << 8) - + uint32_t(i->first.data[1] << 0); - - fprintf(outFile, "0x%07X,0x%07X, 0x%02X,0x%02X, 0x%X, %+d", - carrier_E862, - modulator_E862, - i->first.data[8], - i->first.data[9], - i->first.data[10], - i->first.finetune); - - std::string names; - for(std::set::const_iterator - j = i->second.second.begin(); - j != i->second.second.end(); - ++j) - { - if(!names.empty()) names += "; "; - if((*j)[0] == '\377') - names += j->substr(1); - else - names += *j; - } - fprintf(outFile, " }, // %u: %s\n", (unsigned)c, names.c_str()); - } - } - fprintf(outFile, "};\n"); - } - - /*fprintf(outFile, "static const struct\n" - "{\n" - " unsigned short adlno1, adlno2;\n" - " unsigned char tone;\n" - " unsigned char flags;\n" - " long ms_sound_kon; // Number of milliseconds it produces sound;\n" - " long ms_sound_koff;\n" - "} adlins[] =\n");*/ - - fprintf(outFile, "const struct adlinsdata adlins[%u] =\n", (unsigned)instab.size()); - fprintf(outFile, "{\n"); - - MeasureThreaded measureCounter; - { - std::printf("Beginning to generate measures data... (Hardware concurrency: %d)\n", std::thread::hardware_concurrency()); - std::fflush(stdout); - measureCounter.LoadCache("fm_banks/adldata-cache.dat"); - measureCounter.m_total = instab.size(); - for(size_t b = instab.size(), c = 0; c < b; ++c) - { - for(std::map > >::const_iterator i = instab.begin(); i != instab.end(); ++i) - { - if(i->second.first != c) continue; - measureCounter.run(i); - } - } - std::fflush(stdout); - measureCounter.waitAll(); - measureCounter.SaveCache("fm_banks/adldata-cache.dat"); - } - - std::printf("Writing generated measure data...\n"); - std::fflush(stdout); - - std::vector adlins_flags; - - for(size_t b = instab.size(), c = 0; c < b; ++c) - for(std::map > > - ::const_iterator - i = instab.begin(); - i != instab.end(); - ++i) - { - if(i->second.first != c) continue; - //DurationInfo info = MeasureDurations(i->first); - MeasureThreaded::DurationInfoCache::iterator indo_i = measureCounter.m_durationInfo.find(i->first); - DurationInfo info = indo_i->second; - { - if(info.peak_amplitude_time == 0) - { - fprintf(outFile, - " // Amplitude begins at %6.1f,\n" - " // fades to 20%% at %.1fs, keyoff fades to 20%% in %.1fs.\n", - info.begin_amplitude, - info.quarter_amplitude_time / double(info.interval), - info.keyoff_out_time / double(info.interval)); - } - else - { - fprintf(outFile, - " // Amplitude begins at %6.1f, peaks %6.1f at %.1fs,\n" - " // fades to 20%% at %.1fs, keyoff fades to 20%% in %.1fs.\n", - info.begin_amplitude, - info.peak_amplitude_value, - info.peak_amplitude_time / double(info.interval), - info.quarter_amplitude_time / double(info.interval), - info.keyoff_out_time / double(info.interval)); - } - } - - unsigned flags = (i->first.pseudo4op ? 1 : 0) | (info.nosound ? 2 : 0); - - fprintf(outFile, " {"); - fprintf(outFile, "%4d,%4d,%3d, %d, %6ld,%6ld,%lf", - (unsigned) i->first.insno1, - (unsigned) i->first.insno2, - (int)(i->first.notenum), - flags, - info.ms_sound_kon, - info.ms_sound_koff, - i->first.voice2_fine_tune); - std::string names; - for(std::set::const_iterator - j = i->second.second.begin(); - j != i->second.second.end(); - ++j) - { - if(!names.empty()) names += "; "; - if((*j)[0] == '\377') - names += j->substr(1); - else - names += *j; - } - fprintf(outFile, " }, // %u: %s\n\n", (unsigned)c, names.c_str()); - fflush(outFile); - adlins_flags.push_back(flags); - } - fprintf(outFile, "};\n\n"); - - - printf("Writing banks data...\n"); - fflush(stdout); - - //fprintf(outFile, "static const unsigned short banks[][256] =\n"); - #ifdef HARD_BANKS - const unsigned bankcount = sizeof(banknames) / sizeof(*banknames); - #else - const size_t bankcount = banknames.size(); - #endif - - size_t nosound = InsertNoSoundIns(); - - std::map > bank_data; - for(size_t bank = 0; bank < bankcount; ++bank) - { - //bool redundant = true; - std::vector data(256); - for(size_t p = 0; p < 256; ++p) - { - size_t v = progs[bank][p]; - if(v == 0 || (adlins_flags[v - 1] & 2)) - v = nosound; // Blank.in - else - v -= 1; - data[p] = v; - } - bank_data[bank] = data; - } - std::set listed; - - fprintf(outFile, - "\n\n//Returns total number of generated banks\n" - "int maxAdlBanks()\n" - "{" - " return %u;\n" - "}\n\n" - "const char* const banknames[%u] =\n", (unsigned int)bankcount, (unsigned int)bankcount); - fprintf(outFile, "{\n"); - for(unsigned bank = 0; bank < bankcount; ++bank) - fprintf(outFile, " \"%s\",\n", banknames[bank].c_str()); - fprintf(outFile, "};\n"); - - fprintf(outFile, "const unsigned short banks[%u][256] =\n", (unsigned int)bankcount); - fprintf(outFile, "{\n"); - for(unsigned bank = 0; bank < bankcount; ++bank) - { - fprintf(outFile, " { // bank %u, %s\n", bank, banknames[bank].c_str()); - bool redundant = true; - for(unsigned p = 0; p < 256; ++p) - { - size_t v = bank_data[bank][p]; - if(listed.find(v) == listed.end()) - { - listed.insert(v); - redundant = false; - } - fprintf(outFile, "%4d,", (unsigned int)v); - if(p % 16 == 15) fprintf(outFile, "\n"); - } - fprintf(outFile, " },\n"); - if(redundant) - { - fprintf(outFile, " // Bank %u defines nothing new.\n", bank); - for(unsigned refbank = 0; refbank < bank; ++refbank) - { - bool match = true; - for(unsigned p = 0; p < 256; ++p) - if(bank_data[bank][p] != nosound - && bank_data[bank][p] != bank_data[refbank][p]) - { - match = false; - break; - } - if(match) - fprintf(outFile, " // Bank %u is just a subset of bank %u!\n", - bank, refbank); - } - } - } - - fprintf(outFile, "};\n"); - fflush(outFile); - fclose(outFile); - - printf("Generation of ADLMIDI data has been completed!\n"); - fflush(stdout); -} diff --git a/src/gen_adldata/gen_adldata.pro b/src/gen_adldata/gen_adldata.pro deleted file mode 100644 index 74c504e..0000000 --- a/src/gen_adldata/gen_adldata.pro +++ /dev/null @@ -1,38 +0,0 @@ -TEMPLATE=app -CONFIG-=qt -CONFIG+=console -TARGET=gen_adldata -DESTDIR=$$PWD/../../bin -CONFIG += c++11 - -include($$PWD/ini/IniProcessor.pri) - -#DEFINES += ADLMIDI_USE_DOSBOX_OPL - -QMAKE_CXXFLAGS_RELEASE += -O3 -finline-functions -LIBS += -lpthread - -HEADERS += \ - midi_inst_list.h \ - ../nukedopl3.h \ - ../dbopl.h \ - progs_cache.h \ - file_formats/load_bnk.h \ - file_formats/load_bnk2.h \ - file_formats/load_op2.h \ - file_formats/load_ail.h \ - file_formats/load_ibk.h \ - file_formats/load_jv.h \ - file_formats/load_tmb.h \ - file_formats/load_bisqwit.h \ - file_formats/load_wopl.h \ - measurer.h \ - file_formats/common.h - -SOURCES += \ - gen_adldata.cc \ - ../nukedopl3.c \ - ../dbopl.cpp \ - progs_cache.cpp \ - measurer.cpp - diff --git a/src/gen_adldata/ini/IniProcessor.pri b/src/gen_adldata/ini/IniProcessor.pri deleted file mode 100644 index cdadb59..0000000 --- a/src/gen_adldata/ini/IniProcessor.pri +++ /dev/null @@ -1,10 +0,0 @@ - -INCLUDEPATH += $$PWD - -HEADERS += \ - $$PWD/ini_processing.h \ - $$PWD/ini_processing_variant.h \ - -SOURCES += \ - $$PWD/ini_processing.cpp - diff --git a/src/gen_adldata/ini/ini_processing.cpp b/src/gen_adldata/ini/ini_processing.cpp deleted file mode 100644 index 2f15821..0000000 --- a/src/gen_adldata/ini/ini_processing.cpp +++ /dev/null @@ -1,1385 +0,0 @@ -/* -INI Processor - a small library which allows you parsing INI-files - -Copyright (c) 2017 Vitaliy Novichkov - -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. - -*/ - -//#define USE_FILE_MAPPER - -/* Stop parsing on first error (default is to keep parsing). */ -//#define INI_STOP_ON_FIRST_ERROR - -#include "ini_processing.h" -#include -#include -#include -#include -#include -#include -#include -#ifdef _WIN32 -#include -#endif - -#ifdef USE_FILE_MAPPER -/*****Replace this with right path to file mapper class*****/ -#include "../fileMapper/file_mapper.h" -#endif - -static const unsigned char utfbom[3] = {0xEF, 0xBB, 0xBF}; - -enum { Space = 0x01, Special = 0x02, INIParamEq = 0x04 }; - -static const unsigned char charTraits[256] = -{ - // Space: '\t', '\n', '\r', ' ' - // Special: '\n', '\r', '"', ';', '=', '\\' - // INIParamEq: ':', '=' - - 0, 0, 0, 0, 0, 0, 0, 0, 0, Space, Space | Special, 0, 0, Space | Special, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Space, 0, Special, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, INIParamEq, - Special, 0, Special | INIParamEq, 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, Special, 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, 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, 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 -}; - -#if 0//for speed comparison who faster - macro or inline function. Seems speeds are same -#define IS_SPACE(c) (charTraits[static_cast(c)] & Space) -#define IS_SPECIAL(c) (charTraits[static_cast(c)] & Special) -#define IS_INIEQUAL(c) (charTraits[static_cast(c)] & INIParamEq) -#else -inline unsigned char IS_SPACE(char &c) -{ - return (charTraits[static_cast(c)] & Space); -} -inline unsigned char IS_SPECIAL(char &c) -{ - return (charTraits[static_cast(c)] & Special); -} -inline unsigned char IS_INIEQUAL(char &c) -{ - return (charTraits[static_cast(c)] & INIParamEq); -} -#endif - -/* Strip whitespace chars off end of given string, in place. Return s. */ -inline char *rstrip(char *s) -{ - char *p = s + strlen(s); - - while(p > s && IS_SPACE(*--p)) - *p = '\0'; - - return s; -} - -/* Return pointer to first non-whitespace char in given string. */ -inline char *lskip(char *s) -{ - while(*s && IS_SPACE(*s)) - s++; - - return reinterpret_cast(s); -} - -inline char *lrtrim(char *s) -{ - while(*s && IS_SPACE(*s)) - s++; - - char *p = s + strlen(s); - - while(p > s && IS_SPACE(*--p)) - *p = '\0'; - - return s; -} - -/* Return pointer to first char c or ';' comment in given string, or pointer to - null at end of string if neither found. ';' must be prefixed by a whitespace - character to register as a comment. */ -inline char *find_char_or_comment(char *s, char c) -{ - unsigned char was_whitespace = 0; - - while(*s && *s != c && !(was_whitespace && *s == ';')) - { - was_whitespace = IS_SPACE(*s); - s++; - } - - return s; -} - -inline char *find_inieq_or_comment(char *s) -{ - unsigned char was_whitespace = 0; - - while(*s && (!IS_INIEQUAL(*s)) && !(was_whitespace && *s == ';')) - { - was_whitespace = IS_SPACE(*s); - s++; - } - - return s; -} - -inline char *removeQuotes(char *begin, char *end) -{ - if((*begin == '\0') || (begin == end)) - return begin; - - if((*begin == '"') && (begin + 1 != end)) - begin++; - else - return begin; - - if(*(end - 1) == '"') - *(end - 1) = '\0'; - - return begin; -} - -inline char *unescapeString(char* str) -{ - char *src, *dst; - src = str; - dst = str; - while(*src) - { - if(*src == '\\') - { - src++; - switch(*src) - { - case 'n': *dst = '\n'; break; - case 'r': *dst = '\r'; break; - case 't': *dst = '\t'; break; - default: *dst = *src; break; - } - } - else - if(src != dst) - { - *dst = *src; - } - src++; dst++; - } - *dst = '\0'; - return str; -} - -//Remove comment line from a tail of value -inline void skipcomment(char *value) -{ - unsigned char quoteDepth = 0; - - while(*value) - { - if(quoteDepth > 0) - { - if(*value == '\\') - { - value++; - continue; - } - - if(*value == '"') - --quoteDepth; - } - else if(*value == '"') - ++quoteDepth; - - if((quoteDepth == 0) && (*value == ';')) - { - *value = '\0'; - break; - } - - value++; - } -} - -inline bool memfgets(char *&line, char *data, char *&pos, char *end) -{ - line = pos; - - while(pos != end) - { - if(*pos == '\n') - { - if((pos > data) && (*(pos - 1) == '\r')) - *((pos++) - 1) = '\0';//Support CRLF too - else - *(pos++) = '\0'; - - break; - } - - ++pos; - } - - return (pos != line); - //EOF is a moment when position wasn't changed. - //If do check "pos != end", will be an inability to read last line. - //this logic allows detect true EOF when line is really eof -} - -/* See documentation in header file. */ -bool IniProcessing::parseHelper(char *data, size_t size) -{ - char *section = nullptr; - #if defined(INI_ALLOW_MULTILINE) - char *prev_name = nullptr; - #endif - char *start; - char *end; - char *name; - char *value; - int lineno = 0; - int error = 0; - char *line; - char *pos_end = data + size; - char *pos_cur = data; - params::IniKeys *recentKeys = nullptr; - - /* Scan through file line by line */ - //while (fgets(line, INI_MAX_LINE, file) != NULL) - while(memfgets(line, data, pos_cur, pos_end)) - { - lineno++; - start = line; - - if((lineno == 1) && (size >= 3) && (memcmp(start, utfbom, 3) == 0)) - start += 3; - - start = lrtrim(start); - - if(!*start)//if empty line - skip it away! - continue; - - switch(*start) - { - case ';': - case '#': - //if (*start == ';' || *start == '#') { - // /* Per Python ConfigParser, allow '#' comments at start of line */ - //} - continue; - - case '[': - { - /* A "[section]" line */ - end = find_char_or_comment(start + 1, ']'); - - if(*end == ']') - { - *end = '\0'; - section = start + 1; - //#if defined(INI_ALLOW_MULTILINE) - // prev_name = nullptr; - //#endif - recentKeys = &m_params.iniData[section]; - } - else if(!error) - { - /* No ']' found on section line */ - m_params.errorCode = ERR_SECTION_SYNTAX; - error = lineno; - } - } - break; - - default: - { - /* Not a comment, must be a name[=:]value pair */ - end = find_inieq_or_comment(start); - - if(IS_INIEQUAL(*end)) - { - *end = '\0'; - name = rstrip(start); - value = lskip(end + 1); - end = find_char_or_comment(value, '\0'); - - #ifndef CASE_SENSITIVE_KEYS - for(char *iter = name; *iter != '\0'; ++iter) - *iter = (char)tolower(*iter); - #endif - - if(*end == ';') - *end = '\0'; - - rstrip(value); - { - char *v = value; - skipcomment(v); - v = rstrip(v); - - if(!recentKeys) - recentKeys = &m_params.iniData["General"]; - - #ifdef INIDEBUG - printf("-> [%s]; %s = %s\n", section, name, v); - #endif - (*recentKeys)[name] = unescapeString( removeQuotes(v, v + strlen(v)) ); - } - } - else if(!error) - { - /* No '=' or ':' found on name[=:]value line */ - m_params.errorCode = ERR_KEY_SYNTAX; - error = lineno; - } - - break; - } - }//switch(*start) - - #if defined(INI_STOP_ON_FIRST_ERROR) - - if(error) - break; - - #endif - } - - m_params.lineWithError = error; - return (error == 0); -} - -/* See documentation in header file. */ -bool IniProcessing::parseFile(const char *filename) -{ - bool valid = true; - char *tmp = nullptr; - #ifdef USE_FILE_MAPPER - //By mystical reasons, reading whole file form fread() is faster than mapper :-P - PGE_FileMapper file(filename); - - if(!file.data) - { - m_params.errorCode = ERR_NOFILE; - return -1; - } - - tmp = reinterpret_cast(malloc(static_cast(file.size + 1))); - - if(!tmp) - { - m_params.errorCode = ERR_NO_MEMORY; - return false; - } - - memcpy(tmp, file.data, static_cast(file.size)); - *(tmp + file.size) = '\0';//null terminate last line - valid = ini_parse_file(tmp, static_cast(file.size)); - #else - #ifdef _WIN32 - //Convert UTF8 file path into UTF16 to support non-ASCII paths on Windows - std::wstring dest; - dest.resize(std::strlen(filename)); - int newSize = MultiByteToWideChar(CP_UTF8, - 0, - filename, - dest.size(), - (wchar_t *)dest.c_str(), - dest.size()); - dest.resize(newSize); - FILE *cFile = _wfopen(dest.c_str(), L"rb"); - #else - FILE *cFile = fopen(filename, "rb"); - #endif - - if(!cFile) - { - m_params.errorCode = ERR_NOFILE; - return false; - } - - fseek(cFile, 0, SEEK_END); - ssize_t size = static_cast(ftell(cFile)); - if(size < 0) - { - m_params.errorCode = ERR_KEY_SYNTAX; - fclose(cFile); - return false; - } - fseek(cFile, 0, SEEK_SET); - tmp = reinterpret_cast(malloc(static_cast(size + 1))); - if(!tmp) - { - fclose(cFile); - m_params.errorCode = ERR_NO_MEMORY; - return false; - } - - if(fread(tmp, 1, static_cast(size), cFile) != static_cast(size)) - valid = false; - - fclose(cFile); - if(valid) - { - *(tmp + size) = '\0';//null terminate last line - try - { - valid = parseHelper(tmp, static_cast(size)); - } - catch(...) - { - valid = false; - m_params.errorCode = ERR_SECTION_SYNTAX; - } - } - #endif - - free(tmp); - return valid; -} - -bool IniProcessing::parseMemory(char *mem, size_t size) -{ - bool valid = true; - char *tmp = nullptr; - tmp = reinterpret_cast(malloc(size + 1)); - - if(!tmp) - { - m_params.errorCode = ERR_NO_MEMORY; - return false; - } - - memcpy(tmp, mem, static_cast(size)); - *(tmp + size) = '\0';//null terminate last line - valid = parseHelper(tmp, size); - free(tmp); - return valid; -} - - -IniProcessing::IniProcessing() : - m_params{"", false, -1, ERR_OK, false, params::IniSections(), nullptr, ""} -{} - -IniProcessing::IniProcessing(const char *iniFileName, int) : - m_params{iniFileName, false, -1, ERR_OK, false, params::IniSections(), nullptr, ""} -{ - open(iniFileName); -} - -IniProcessing::IniProcessing(const std::string &iniFileName, int) : - m_params{iniFileName, false, -1, ERR_OK, false, params::IniSections(), nullptr, ""} -{ - open(iniFileName); -} - -#ifdef INI_PROCESSING_ALLOW_QT_TYPES -IniProcessing::IniProcessing(const QString &iniFileName, int) : - m_params{iniFileName.toStdString(), false, -1, ERR_OK, false, params::IniSections(), nullptr, ""} -{ - open(m_params.filePath); -} -#endif - -IniProcessing::IniProcessing(char *memory, size_t size): - m_params{"", false, -1, ERR_OK, false, params::IniSections(), nullptr, ""} -{ - openMem(memory, size); -} - -IniProcessing::IniProcessing(const IniProcessing &ip) : - m_params(ip.m_params) -{} - -bool IniProcessing::open(const std::string &iniFileName) -{ - std::setlocale(LC_NUMERIC, "C"); - - if(!iniFileName.empty()) - { - close(); - m_params.errorCode = ERR_OK; - m_params.filePath = iniFileName; - bool res = parseFile(m_params.filePath.c_str()); - #ifdef INIDEBUG - - if(res) - printf("\n==========WOOHOO!!!==============\n\n"); - else - printf("\n==========OOOUCH!!!==============\n\n"); - - #endif - m_params.opened = res; - return res; - } - - m_params.errorCode = ERR_NOFILE; - return false; -} - -bool IniProcessing::openMem(char *memory, size_t size) -{ - std::setlocale(LC_NUMERIC, "C"); - - if((memory != nullptr) && (size > 0)) - { - close(); - m_params.errorCode = ERR_OK; - m_params.filePath.clear(); - bool res = parseMemory(memory, size); - m_params.opened = res; - return res; - } - - m_params.errorCode = ERR_NOFILE; - return false; -} - -void IniProcessing::close() -{ - m_params.errorCode = ERR_OK; - m_params.iniData.clear(); - m_params.opened = false; - m_params.lineWithError = -1; -} - -IniProcessing::ErrCode IniProcessing::lastError() -{ - return m_params.errorCode; -} - -int IniProcessing::lineWithError() -{ - return m_params.lineWithError; -} - -bool IniProcessing::isOpened() -{ - return m_params.opened; -} - -bool IniProcessing::beginGroup(const std::string &groupName) -{ - //Keep the group name. If not exist, will be created on value write - m_params.currentGroupName = groupName; - - params::IniSections::iterator e = m_params.iniData.find(groupName); - - if(e == m_params.iniData.end()) - return false; - - params::IniKeys &k = e->second; - m_params.currentGroup = &k; - return true; -} - -bool IniProcessing::contains(const std::string &groupName) -{ - if(!m_params.opened) - return false; - - params::IniSections::iterator e = m_params.iniData.find(groupName); - return (e != m_params.iniData.end()); -} - -std::string IniProcessing::fileName() -{ - return m_params.filePath; -} - -std::string IniProcessing::group() -{ - return m_params.currentGroupName; -} - -std::vector IniProcessing::childGroups() -{ - std::vector groups; - groups.reserve(m_params.iniData.size()); - for(params::IniSections::iterator e = m_params.iniData.begin(); - e != m_params.iniData.end(); - e++) - { - groups.push_back(e->first); - } - return groups; -} - -bool IniProcessing::hasKey(const std::string &keyName) -{ - if(!m_params.opened) - return false; - - if(!m_params.currentGroup) - return false; - - params::IniKeys::iterator e = m_params.currentGroup->find(keyName); - return (e != m_params.currentGroup->end()); -} - -std::vector IniProcessing::allKeys() -{ - std::vector keys; - if(!m_params.opened) - return keys; - if(!m_params.currentGroup) - return keys; - - keys.reserve(m_params.currentGroup->size()); - - for(params::IniKeys::iterator it = m_params.currentGroup->begin(); - it != m_params.currentGroup->end(); - it++) - { - keys.push_back( it->first ); - } - - return keys; -} - -void IniProcessing::endGroup() -{ - m_params.currentGroup = nullptr; - m_params.currentGroupName.clear(); -} - -void IniProcessing::read(const char *key, bool &dest, bool defVal) -{ - bool ok = false; - params::IniKeys::iterator e = readHelper(key, ok); - - if(!ok) - { - dest = defVal; - return; - } - - std::string &k = e->second; - size_t i = 0; - size_t ss = std::min(static_cast(4ul), k.size()); - char buff[4] = {0, 0, 0, 0}; - const char *pbufi = k.c_str(); - char *pbuff = buff; - - for(; i < ss; i++) - (*pbuff++) = static_cast(std::tolower(*pbufi++)); - - if(ss < 4) - { - if(ss == 0) - { - dest = false; - return; - } - - if(ss == 1) - { - dest = (buff[0] == '1'); - return; - } - - bool isNum = true; - isNum &= std::isdigit(buff[i]) || (buff[i] == '-') || (buff[i] == '+'); - - for(size_t i = 1; i < ss; i++) - isNum &= std::isdigit(buff[i]); - - if(isNum) - { - long num = std::strtol(buff, 0, 0); - dest = num != 0l; - return; - } - else - { - dest = (std::memcmp(buff, "yes", 3) == 0) || - (std::memcmp(buff, "on", 2) == 0); - return; - } - } - - if(std::memcmp(buff, "true", 4) == 0) - { - dest = true; - return; - } - - try - { - long num = std::strtol(buff, 0, 0); - dest = num != 0l; - return; - } - catch(...) - { - dest = false; - return; - } -} - -void IniProcessing::read(const char *key, unsigned char &dest, unsigned char defVal) -{ - bool ok = false; - params::IniKeys::iterator e = readHelper(key, ok); - - if(!ok) - { - dest = defVal; - return; - } - - std::string &k = e->second; - - if(k.size() >= 1) - dest = static_cast(k[0]); - else - dest = defVal; -} - -void IniProcessing::read(const char *key, char &dest, char defVal) -{ - bool ok = false; - params::IniKeys::iterator e = readHelper(key, ok); - - if(!ok) - { - dest = defVal; - return; - } - - std::string &k = e->second; - - if(k.size() >= 1) - dest = k[0]; - else - dest = defVal; -} - -void IniProcessing::read(const char *key, unsigned short &dest, unsigned short defVal) -{ - bool ok = false; - params::IniKeys::iterator e = readHelper(key, ok); - - if(!ok) - { - dest = defVal; - return; - } - - dest = static_cast(std::strtoul(e->second.c_str(), nullptr, 0)); -} - -void IniProcessing::read(const char *key, short &dest, short defVal) -{ - bool ok = false; - params::IniKeys::iterator e = readHelper(key, ok); - - if(!ok) - { - dest = defVal; - return; - } - - dest = static_cast(std::strtol(e->second.c_str(), nullptr, 0)); -} - -void IniProcessing::read(const char *key, unsigned int &dest, unsigned int defVal) -{ - bool ok = false; - params::IniKeys::iterator e = readHelper(key, ok); - - if(!ok) - { - dest = defVal; - return; - } - - dest = static_cast(std::strtoul(e->second.c_str(), nullptr, 0)); -} - -void IniProcessing::read(const char *key, int &dest, int defVal) -{ - bool ok = false; - params::IniKeys::iterator e = readHelper(key, ok); - - if(!ok) - { - dest = defVal; - return; - } - - dest = static_cast(std::strtol(e->second.c_str(), nullptr, 0)); -} - -void IniProcessing::read(const char *key, unsigned long &dest, unsigned long defVal) -{ - bool ok = false; - params::IniKeys::iterator e = readHelper(key, ok); - - if(!ok) - { - dest = defVal; - return; - } - - dest = std::strtoul(e->second.c_str(), nullptr, 0); -} - -void IniProcessing::read(const char *key, long &dest, long defVal) -{ - bool ok = false; - params::IniKeys::iterator e = readHelper(key, ok); - - if(!ok) - { - dest = defVal; - return; - } - - dest = std::strtol(e->second.c_str(), nullptr, 0); -} - -void IniProcessing::read(const char *key, unsigned long long &dest, unsigned long long defVal) -{ - bool ok = false; - params::IniKeys::iterator e = readHelper(key, ok); - - if(!ok) - { - dest = defVal; - return; - } - - dest = std::strtoull(e->second.c_str(), nullptr, 0); -} - -void IniProcessing::read(const char *key, long long &dest, long long defVal) -{ - bool ok = false; - params::IniKeys::iterator e = readHelper(key, ok); - - if(!ok) - { - dest = defVal; - return; - } - - dest = std::strtoll(e->second.c_str(), nullptr, 0); -} - -void IniProcessing::read(const char *key, float &dest, float defVal) -{ - bool ok = false; - params::IniKeys::iterator e = readHelper(key, ok); - if(!ok) - { - dest = defVal; - return; - } - dest = std::strtof(e->second.c_str(), nullptr); -} - -void IniProcessing::read(const char *key, double &dest, double defVal) -{ - bool ok = false; - params::IniKeys::iterator e = readHelper(key, ok); - - if(!ok) - { - dest = defVal; - return; - } - dest = std::strtod(e->second.c_str(), nullptr); -} - -void IniProcessing::read(const char *key, long double &dest, long double defVal) -{ - bool ok = false; - params::IniKeys::iterator e = readHelper(key, ok); - if(!ok) - { - dest = defVal; - return; - } - dest = std::strtold(e->second.c_str(), nullptr); -} - -void IniProcessing::read(const char *key, std::string &dest, const std::string &defVal) -{ - bool ok = false; - params::IniKeys::iterator e = readHelper(key, ok); - - if(!ok) - { - dest = defVal; - return; - } - - dest = e->second; -} - -#ifdef INI_PROCESSING_ALLOW_QT_TYPES -void IniProcessing::read(const char *key, QString &dest, const QString &defVal) -{ - bool ok = false; - params::IniKeys::iterator e = readHelper(key, ok); - - if(!ok) - { - dest = defVal; - return; - } - - dest = QString::fromStdString(e->second); -} -#endif - -template -inline void StrToNumVectorHelper(const std::string &source, TList &dest, const typename TList::value_type &def) -{ - typedef typename TList::value_type T; - dest.clear(); - - if(!source.empty()) - { - std::stringstream ss(source); - std::string item; - while(std::getline(ss, item, ',')) - { - std::remove(item.begin(), item.end(), ' '); - try - { - if(std::is_same::value || - std::is_same::value || - std::is_same::value) - dest.push_back(static_cast(std::strtol(item.c_str(), NULL, 0))); - else if(std::is_same::value || - std::is_same::value || - std::is_same::value) - dest.push_back(static_cast(std::strtoul(item.c_str(), NULL, 0))); - else if(std::is_same::value) - dest.push_back(std::strtof(item.c_str(), NULL)); - else - dest.push_back(std::strtod(item.c_str(), NULL)); - } - catch(...) - { - dest.pop_back(); - } - } - - if(dest.empty()) - dest.push_back(def); - } - else - dest.push_back(def); -} - -template -void readNumArrHelper(IniProcessing *self, const char *key, TList &dest, const TList &defVal) -{ - bool ok = false; - IniProcessing::params::IniKeys::iterator e = self->readHelper(key, ok); - - if(!ok) - { - dest = defVal; - return; - } - - StrToNumVectorHelper(e->second, dest, static_cast(0)); -} - -void IniProcessing::read(const char *key, std::vector &dest, const std::vector &defVal) -{ - readNumArrHelper, unsigned short>(this, key, dest, defVal); -} -void IniProcessing::read(const char *key, std::vector &dest, const std::vector &defVal) -{ - readNumArrHelper, short>(this, key, dest, defVal); -} -void IniProcessing::read(const char *key, std::vector &dest, const std::vector &defVal) -{ - readNumArrHelper, unsigned int>(this, key, dest, defVal); -} -void IniProcessing::read(const char *key, std::vector &dest, const std::vector &defVal) -{ - readNumArrHelper, int>(this, key, dest, defVal); -} -void IniProcessing::read(const char *key, std::vector &dest, const std::vector &defVal) -{ - readNumArrHelper, unsigned long>(this, key, dest, defVal); -} -void IniProcessing::read(const char *key, std::vector &dest, const std::vector &defVal) -{ - readNumArrHelper, long>(this, key, dest, defVal); -} -void IniProcessing::read(const char *key, std::vector &dest, const std::vector &defVal) -{ - readNumArrHelper, unsigned long long>(this, key, dest, defVal); -} -void IniProcessing::read(const char *key, std::vector &dest, const std::vector &defVal) -{ - readNumArrHelper, long long>(this, key, dest, defVal); -} -void IniProcessing::read(const char *key, std::vector &dest, const std::vector &defVal) -{ - readNumArrHelper, float>(this, key, dest, defVal); -} -void IniProcessing::read(const char *key, std::vector &dest, const std::vector &defVal) -{ - readNumArrHelper, double>(this, key, dest, defVal); -} - -void IniProcessing::read(const char *key, std::vector &dest, const std::vector &defVal) -{ - readNumArrHelper, long double>(this, key, dest, defVal); -} - -#ifdef INI_PROCESSING_ALLOW_QT_TYPES -void IniProcessing::read(const char *key, QList &dest, const QList &defVal) -{ - readNumArrHelper, short>(this, key, dest, defVal); -} - -void IniProcessing::read(const char *key, QList &dest, const QList &defVal) -{ - readNumArrHelper, unsigned short>(this, key, dest, defVal); -} - -void IniProcessing::read(const char *key, QList &dest, const QList &defVal) -{ - readNumArrHelper, int>(this, key, dest, defVal); -} -void IniProcessing::read(const char *key, QList &dest, const QList &defVal) -{ - readNumArrHelper, unsigned int>(this, key, dest, defVal); -} -void IniProcessing::read(const char *key, QList &dest, const QList &defVal) -{ - readNumArrHelper, long>(this, key, dest, defVal); -} -void IniProcessing::read(const char *key, QList &dest, const QList &defVal) -{ - readNumArrHelper, unsigned long>(this, key, dest, defVal); -} -void IniProcessing::read(const char *key, QList &dest, const QList &defVal) -{ - readNumArrHelper, long long>(this, key, dest, defVal); -} -void IniProcessing::read(const char *key, QList &dest, const QList &defVal) -{ - readNumArrHelper, unsigned long long>(this, key, dest, defVal); -} -void IniProcessing::read(const char *key, QList &dest, const QList &defVal) -{ - readNumArrHelper, float>(this, key, dest, defVal); -} -void IniProcessing::read(const char *key, QList &dest, const QList &defVal) -{ - readNumArrHelper, double>(this, key, dest, defVal); -} - -void IniProcessing::read(const char *key, QList &dest, const QList &defVal) -{ - readNumArrHelper, long double>(this, key, dest, defVal); -} - -void IniProcessing::read(const char *key, QVector &dest, const QVector &defVal) -{ - readNumArrHelper, short>(this, key, dest, defVal); -} -void IniProcessing::read(const char *key, QVector &dest, const QVector &defVal) -{ - readNumArrHelper, unsigned short>(this, key, dest, defVal); -} -void IniProcessing::read(const char *key, QVector &dest, const QVector &defVal) -{ - readNumArrHelper, int>(this, key, dest, defVal); -} -void IniProcessing::read(const char *key, QVector &dest, const QVector &defVal) -{ - readNumArrHelper, unsigned int>(this, key, dest, defVal); -} -void IniProcessing::read(const char *key, QVector &dest, const QVector &defVal) -{ - readNumArrHelper, long>(this, key, dest, defVal); -} -void IniProcessing::read(const char *key, QVector &dest, const QVector &defVal) -{ - readNumArrHelper, unsigned long>(this, key, dest, defVal); -} -void IniProcessing::read(const char *key, QVector &dest, const QVector &defVal) -{ - readNumArrHelper, long long>(this, key, dest, defVal); -} -void IniProcessing::read(const char *key, QVector &dest, const QVector &defVal) -{ - readNumArrHelper, unsigned long long>(this, key, dest, defVal); -} -void IniProcessing::read(const char *key, QVector &dest, const QVector &defVal) -{ - readNumArrHelper, float>(this, key, dest, defVal); -} -void IniProcessing::read(const char *key, QVector &dest, const QVector &defVal) -{ - readNumArrHelper, double>(this, key, dest, defVal); -} - -void IniProcessing::read(const char *key, QVector &dest, const QVector &defVal) -{ - readNumArrHelper, long double>(this, key, dest, defVal); -} -#endif - -IniProcessingVariant IniProcessing::value(const char *key, const IniProcessingVariant &defVal) -{ - bool ok = false; - params::IniKeys::iterator e = readHelper(key, ok); - - if(!ok) - return defVal; - - std::string &k = e->second; - return IniProcessingVariant(&k); -} - -void IniProcessing::writeIniParam(const char *key, const std::string &value) -{ - if(m_params.currentGroupName.empty()) - return; - - bool ok = false; - params::IniKeys::iterator e = readHelper(key, ok); - if(ok) - { - e->second = value; - } - else - { - if(!m_params.currentGroup) - { - m_params.iniData.insert({m_params.currentGroupName, params::IniKeys()}); - m_params.currentGroup = &m_params.iniData[m_params.currentGroupName]; - } - m_params.currentGroup->insert({std::string(key), value}); - //Mark as opened - m_params.opened = true; - } -} - -void IniProcessing::setValue(const char *key, unsigned short value) -{ - writeIniParam(key, std::to_string(value)); -} - -void IniProcessing::setValue(const char *key, short value) -{ - writeIniParam(key, std::to_string(value)); -} - -void IniProcessing::setValue(const char *key, unsigned int value) -{ - writeIniParam(key, std::to_string(value)); -} - -void IniProcessing::setValue(const char *key, int value) -{ - writeIniParam(key, std::to_string(value)); -} - -void IniProcessing::setValue(const char *key, unsigned long value) -{ - writeIniParam(key, std::to_string(value)); -} - -void IniProcessing::setValue(const char *key, long value) -{ - writeIniParam(key, std::to_string(value)); -} - -void IniProcessing::setValue(const char *key, unsigned long long value) -{ - writeIniParam(key, std::to_string(value)); -} - -void IniProcessing::setValue(const char *key, long long value) -{ - writeIniParam(key, std::to_string(value)); -} - -void IniProcessing::setValue(const char *key, float value) -{ - writeIniParam(key, IniProcessing::to_string_with_precision(value)); -} - -void IniProcessing::setValue(const char *key, double value) -{ - writeIniParam(key, IniProcessing::to_string_with_precision(value)); -} - -void IniProcessing::setValue(const char *key, long double value) -{ - writeIniParam(key, IniProcessing::to_string_with_precision(value)); -} - -void IniProcessing::setValue(const char *key, const char *value) -{ - writeIniParam(key, value); -} - -void IniProcessing::setValue(const char *key, const std::string &value) -{ - writeIniParam(key, value); -} - -#ifdef INI_PROCESSING_ALLOW_QT_TYPES -void IniProcessing::setValue(const char *key, const QString &value) -{ - writeIniParam(key, value.toStdString()); -} -#endif - -static inline bool isFloatValue(const std::string &str) -{ - enum State - { - ST_SIGN = 0, - ST_DOT, - ST_EXPONENT, - ST_EXPONENT_SIGN, - ST_TAIL - } st = ST_SIGN; - - for(const char &c : str) - { - if(!isdigit(c)) - { - switch(st) - { - case ST_SIGN: - if(c != '-') - return false; - st = ST_DOT; - continue; - case ST_DOT: - if(c != '.') - return false; - else - if((c == 'E') || (c == 'e')) - st = ST_EXPONENT_SIGN; - else - st = ST_EXPONENT; - continue; - case ST_EXPONENT: - if((c != 'E') && (c != 'e')) - return false; - st = ST_EXPONENT_SIGN; - continue; - case ST_EXPONENT_SIGN: - if(c != '-') - return false; - st = ST_TAIL; - continue; - case ST_TAIL: - return false; - } - return false; - } - else - { - if(st == ST_SIGN) - st = ST_DOT; - } - } - return true; -} - -bool IniProcessing::writeIniFile() -{ - #ifdef _WIN32 - //Convert UTF8 file path into UTF16 to support non-ASCII paths on Windows - std::wstring dest; - dest.resize(m_params.filePath.size()); - int newSize = MultiByteToWideChar(CP_UTF8, - 0, - m_params.filePath.c_str(), - dest.size(), - (wchar_t *)dest.c_str(), - dest.size()); - dest.resize(newSize); - FILE *cFile = _wfopen(dest.c_str(), L"wb"); - #else - FILE *cFile = fopen(m_params.filePath.c_str(), "wb"); - #endif - if(!cFile) - return false; - - for(params::IniSections::iterator group = m_params.iniData.begin(); - group != m_params.iniData.end(); - group++) - { - fprintf(cFile, "[%s]\n", group->first.c_str()); - for(params::IniKeys::iterator key = group->second.begin(); - key != group->second.end(); - key++) - { - if(isFloatValue(key->second)) - { - //Store as-is without quoting - fprintf(cFile, "%s = %s\n", key->first.c_str(), key->second.c_str()); - } - else - { - //Set escape quotes and put the string with a quotes - std::string &s = key->second; - std::string escaped; - escaped.reserve(s.length() * 2); - for(char &c : s) - { - switch(c) - { - case '\n': escaped += "\\n"; break; - case '\r': escaped += "\\r"; break; - case '\t': escaped += "\\t"; break; - default: - if((c == '\\') || (c == '"')) - escaped.push_back('\\'); - escaped.push_back(c); - } - } - fprintf(cFile, "%s = \"%s\"\n", key->first.c_str(), escaped.c_str()); - } - } - fprintf(cFile, "\n"); - fflush(cFile); - } - fclose(cFile); - return true; -} - diff --git a/src/gen_adldata/ini/ini_processing.h b/src/gen_adldata/ini/ini_processing.h deleted file mode 100644 index 52ab2e2..0000000 --- a/src/gen_adldata/ini/ini_processing.h +++ /dev/null @@ -1,677 +0,0 @@ -/* -INI Processor - a small library which allows you parsing INI-files - -Copyright (c) 2017 Vitaliy Novichkov - -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 INIPROCESSING_H -#define INIPROCESSING_H - -#include -#include -#include -#include -#include -#ifdef INI_PROCESSING_ALLOW_QT_TYPES -#include -#include -#include -#endif - -#include "ini_processing_variant.h" - -/** - * @brief INI Processor - an utility which providing fast and flexible INI file parsing API - */ -class IniProcessing -{ -public: - /** - * @brief Available error codes - */ - enum ErrCode - { - //! Everything is fine - ERR_OK = 0, - //! File not found or memory pointer is null - ERR_NOFILE, - //! Invalid section declaration syntax - ERR_SECTION_SYNTAX, - //! Invalid key declaration syntax - ERR_KEY_SYNTAX, - //! No available memory - ERR_NO_MEMORY - }; - -private: - struct params - { - std::string filePath; - bool opened; - int lineWithError; - ErrCode errorCode; - bool modified; - typedef std::unordered_map IniKeys; - typedef std::unordered_map IniSections; - IniSections iniData; - IniKeys *currentGroup; - std::string currentGroupName; - } m_params; - - template - friend void readNumArrHelper(IniProcessing* self, const char *key, TList &dest, const TList &defVal); - - bool parseHelper(char *data, size_t size); - - bool parseFile(const char *filename); - bool parseMemory(char *mem, size_t size); - - inline params::IniKeys::iterator readHelper(const char *key, bool &ok) - { - if(!m_params.opened) - return params::IniKeys::iterator(); - - if(!m_params.currentGroup) - return params::IniKeys::iterator(); - - #ifndef CASE_SENSITIVE_KEYS - std::string key1(key); - for(char *iter = &key1[0]; *iter != '\0'; ++iter) - *iter = (char)tolower(*iter); - #endif - - params::IniKeys::iterator e = m_params.currentGroup->find(key1); - - if(e != m_params.currentGroup->end()) - ok = true; - - return e; - } - - void writeIniParam(const char *key, const std::string &value); - -public: - IniProcessing(); - IniProcessing(const char *iniFileName, int dummy = 0); - IniProcessing(const std::string &iniFileName, int dummy = 0); -#ifdef INI_PROCESSING_ALLOW_QT_TYPES - IniProcessing(const QString &iniFileName, int dummy = 0); -#endif - IniProcessing(char *memory, size_t size); - IniProcessing(const IniProcessing &ip); - - /** - * @brief Open INI-file from disk and parse it - * @param iniFileName full path to INI-file to parse - * @return true if INI file has been passed, false if any error happen - */ - bool open(const std::string &iniFileName); - - /** - * @brief Open raw INI-data from memory and parse it - * @param memory pointer to memory block - * @param size size of memory block to process - * @return - */ - bool openMem(char *memory, size_t size); - - /** - * @brief Clear all internal buffers and close the file - */ - void close(); - - /** - * @brief Returns last happen error code - * @return Error code - */ - ErrCode lastError(); - /** - * @brief Line number which contains error - * @return line number wit herror - */ - int lineWithError(); - - /** - * @brief State of INI Processor - * @return true if any file is opened - */ - bool isOpened(); - - /** - * @brief Select a section to process - * @param groupName name of section to process - * @return true if group exists and opened - */ - bool beginGroup(const std::string &groupName); - - /** - * @brief Is this INI file contains section of specific name - * @param groupName name of section - * @return true if section is exists - */ - bool contains(const std::string &groupName); - - /** - * @brief Currently opened file name - * @return path to currently opened file - */ - std::string fileName(); - - /** - * @brief Currently processing section - * @return name of current section - */ - std::string group(); - - /** - * @brief Get list of available groups - * @return Array of strings - */ - std::vector childGroups(); - - /** - * @brief Is current section contains specific key name - * @param keyName name of key - * @return true if key is presented in this section - */ - bool hasKey(const std::string &keyName); - - /** - * @brief Get list of available keys in current groul - * @return Array of strings - */ - std::vector allKeys(); - - /** - * @brief Release current section to choice another for process - */ - void endGroup(); - - /** - * @brief Retreive value by specific key and pass it via reference - * @param [_IN] key name of key with value to retrieved - * @param [_OUT] dest Reference to destination variable to store retrieved value - * @param [_IN] defVal Default value for case of non-existing key - */ - void read(const char *key, bool &dest, bool defVal); - /** - * @brief Retreive value by specific key and pass it via reference - * @param [_IN] key name of key with value to retrieved - * @param [_OUT] dest Reference to destination variable to store retrieved value - * @param [_IN] defVal Default value for case of non-existing key - */ - void read(const char *key, unsigned char &dest, unsigned char defVal); - /** - * @brief Retreive value by specific key and pass it via reference - * @param [_IN] key name of key with value to retrieved - * @param [_OUT] dest Reference to destination variable to store retrieved value - * @param [_IN] defVal Default value for case of non-existing key - */ - void read(const char *key, char &dest, char defVal); - /** - * @brief Retreive value by specific key and pass it via reference - * @param [_IN] key name of key with value to retrieved - * @param [_OUT] dest Reference to destination variable to store retrieved value - * @param [_IN] defVal Default value for case of non-existing key - */ - void read(const char *key, unsigned short &dest, unsigned short defVal); - /** - * @brief Retreive value by specific key and pass it via reference - * @param [_IN] key name of key with value to retrieved - * @param [_OUT] dest Reference to destination variable to store retrieved value - * @param [_IN] defVal Default value for case of non-existing key - */ - void read(const char *key, short &dest, short defVal); - /** - * @brief Retreive value by specific key and pass it via reference - * @param [_IN] key name of key with value to retrieved - * @param [_OUT] dest Reference to destination variable to store retrieved value - * @param [_IN] defVal Default value for case of non-existing key - */ - void read(const char *key, unsigned int &dest, unsigned int defVal); - /** - * @brief Retreive value by specific key and pass it via reference - * @param [_IN] key name of key with value to retrieved - * @param [_OUT] dest Reference to destination variable to store retrieved value - * @param [_IN] defVal Default value for case of non-existing key - */ - void read(const char *key, int &dest, int defVal); - /** - * @brief Retreive value by specific key and pass it via reference - * @param [_IN] key name of key with value to retrieved - * @param [_OUT] dest Reference to destination variable to store retrieved value - * @param [_IN] defVal Default value for case of non-existing key - */ - void read(const char *key, unsigned long &dest, unsigned long defVal); - /** - * @brief Retreive value by specific key and pass it via reference - * @param [_IN] key name of key with value to retrieved - * @param [_OUT] dest Reference to destination variable to store retrieved value - * @param [_IN] defVal Default value for case of non-existing key - */ - void read(const char *key, long &dest, long defVal); - /** - * @brief Retreive value by specific key and pass it via reference - * @param [_IN] key name of key with value to retrieved - * @param [_OUT] dest Reference to destination variable to store retrieved value - * @param [_IN] defVal Default value for case of non-existing key - */ - void read(const char *key, unsigned long long &dest, unsigned long long defVal); - /** - * @brief Retreive value by specific key and pass it via reference - * @param [_IN] key name of key with value to retrieved - * @param [_OUT] dest Reference to destination variable to store retrieved value - * @param [_IN] defVal Default value for case of non-existing key - */ - void read(const char *key, long long &dest, long long defVal); - /** - * @brief Retreive value by specific key and pass it via reference - * @param [_IN] key name of key with value to retrieved - * @param [_OUT] dest Reference to destination variable to store retrieved value - * @param [_IN] defVal Default value for case of non-existing key - */ - void read(const char *key, float &dest, float defVal); - /** - * @brief Retreive value by specific key and pass it via reference - * @param [_IN] key name of key with value to retrieved - * @param [_OUT] dest Reference to destination variable to store retrieved value - * @param [_IN] defVal Default value for case of non-existing key - */ - void read(const char *key, double &dest, double defVal); - /** - * @brief Retreive value by specific key and pass it via reference - * @param [_IN] key name of key with value to retrieved - * @param [_OUT] dest Reference to destination variable to store retrieved value - * @param [_IN] defVal Default value for case of non-existing key - */ - void read(const char *key, long double &dest, long double defVal); - /** - * @brief Retreive value by specific key and pass it via reference - * @param [_IN] key name of key with value to retrieved - * @param [_OUT] dest Reference to destination variable to store retrieved value - * @param [_IN] defVal Default value for case of non-existing key - */ - void read(const char *key, std::string &dest, const std::string &defVal); - - #ifdef INI_PROCESSING_ALLOW_QT_TYPES - /** - * @brief Retreive value by specific key and pass it via reference - * @param [_IN] key name of key with value to retrieved - * @param [_OUT] dest Reference to destination variable to store retrieved value - * @param [_IN] defVal Default value for case of non-existing key - */ - void read(const char *key, QString &dest, const QString &defVal); - #endif - - /** - * @brief Retreive value by specific key and pass it via reference - * @param [_IN] key name of key with value to retrieved - * @param [_OUT] dest Reference to destination variable to store retrieved value - * @param [_IN] defVal Default value for case of non-existing key - */ - void read(const char *key, std::vector &dest, const std::vector &defVal = std::vector()); - /** - * @brief Retreive value by specific key and pass it via reference - * @param [_IN] key name of key with value to retrieved - * @param [_OUT] dest Reference to destination variable to store retrieved value - * @param [_IN] defVal Default value for case of non-existing key - */ - void read(const char *key, std::vector &dest, const std::vector &defVal = std::vector()); - /** - * @brief Retreive value by specific key and pass it via reference - * @param [_IN] key name of key with value to retrieved - * @param [_OUT] dest Reference to destination variable to store retrieved value - * @param [_IN] defVal Default value for case of non-existing key - */ - void read(const char *key, std::vector &dest, const std::vector &defVal = std::vector()); - /** - * @brief Retreive value by specific key and pass it via reference - * @param [_IN] key name of key with value to retrieved - * @param [_OUT] dest Reference to destination variable to store retrieved value - * @param [_IN] defVal Default value for case of non-existing key - */ - void read(const char *key, std::vector &dest, const std::vector &defVal = std::vector()); - /** - * @brief Retreive value by specific key and pass it via reference - * @param [_IN] key name of key with value to retrieved - * @param [_OUT] dest Reference to destination variable to store retrieved value - * @param [_IN] defVal Default value for case of non-existing key - */ - void read(const char *key, std::vector &dest, const std::vector &defVal = std::vector()); - /** - * @brief Retreive value by specific key and pass it via reference - * @param [_IN] key name of key with value to retrieved - * @param [_OUT] dest Reference to destination variable to store retrieved value - * @param [_IN] defVal Default value for case of non-existing key - */ - void read(const char *key, std::vector &dest, const std::vector &defVal = std::vector()); - /** - * @brief Retreive value by specific key and pass it via reference - * @param [_IN] key name of key with value to retrieved - * @param [_OUT] dest Reference to destination variable to store retrieved value - * @param [_IN] defVal Default value for case of non-existing key - */ - void read(const char *key, std::vector &dest, const std::vector &defVal = std::vector()); - /** - * @brief Retreive value by specific key and pass it via reference - * @param [_IN] key name of key with value to retrieved - * @param [_OUT] dest Reference to destination variable to store retrieved value - * @param [_IN] defVal Default value for case of non-existing key - */ - void read(const char *key, std::vector &dest, const std::vector &defVal = std::vector()); - /** - * @brief Retreive value by specific key and pass it via reference - * @param [_IN] key name of key with value to retrieved - * @param [_OUT] dest Reference to destination variable to store retrieved value - * @param [_IN] defVal Default value for case of non-existing key - */ - void read(const char *key, std::vector &dest, const std::vector &defVal = std::vector()); - /** - * @brief Retreive value by specific key and pass it via reference - * @param [_IN] key name of key with value to retrieved - * @param [_OUT] dest Reference to destination variable to store retrieved value - * @param [_IN] defVal Default value for case of non-existing key - */ - void read(const char *key, std::vector &dest, const std::vector &defVal = std::vector()); - /** - * @brief Retreive value by specific key and pass it via reference - * @param [_IN] key name of key with value to retrieved - * @param [_OUT] dest Reference to destination variable to store retrieved value - * @param [_IN] defVal Default value for case of non-existing key - */ - void read(const char *key, std::vector &dest, const std::vector &defVal = std::vector()); - - #ifdef INI_PROCESSING_ALLOW_QT_TYPES - /** - * @brief Retreive value by specific key and pass it via reference - * @param [_IN] key name of key with value to retrieved - * @param [_OUT] dest Reference to destination variable to store retrieved value - * @param [_IN] defVal Default value for case of non-existing key - */ - void read(const char *key, QList &dest, const QList &defVal = QList()); - /** - * @brief Retreive value by specific key and pass it via reference - * @param [_IN] key name of key with value to retrieved - * @param [_OUT] dest Reference to destination variable to store retrieved value - * @param [_IN] defVal Default value for case of non-existing key - */ - void read(const char *key, QList &dest, const QList &defVal = QList()); - /** - * @brief Retreive value by specific key and pass it via reference - * @param [_IN] key name of key with value to retrieved - * @param [_OUT] dest Reference to destination variable to store retrieved value - * @param [_IN] defVal Default value for case of non-existing key - */ - void read(const char *key, QList &dest, const QList &defVal = QList()); - /** - * @brief Retreive value by specific key and pass it via reference - * @param [_IN] key name of key with value to retrieved - * @param [_OUT] dest Reference to destination variable to store retrieved value - * @param [_IN] defVal Default value for case of non-existing key - */ - void read(const char *key, QList &dest, const QList &defVal = QList()); - /** - * @brief Retreive value by specific key and pass it via reference - * @param [_IN] key name of key with value to retrieved - * @param [_OUT] dest Reference to destination variable to store retrieved value - * @param [_IN] defVal Default value for case of non-existing key - */ - void read(const char *key, QList &dest, const QList &defVal = QList()); - /** - * @brief Retreive value by specific key and pass it via reference - * @param [_IN] key name of key with value to retrieved - * @param [_OUT] dest Reference to destination variable to store retrieved value - * @param [_IN] defVal Default value for case of non-existing key - */ - void read(const char *key, QList &dest, const QList &defVal = QList()); - /** - * @brief Retreive value by specific key and pass it via reference - * @param [_IN] key name of key with value to retrieved - * @param [_OUT] dest Reference to destination variable to store retrieved value - * @param [_IN] defVal Default value for case of non-existing key - */ - void read(const char *key, QList &dest, const QList &defVal = QList()); - /** - * @brief Retreive value by specific key and pass it via reference - * @param [_IN] key name of key with value to retrieved - * @param [_OUT] dest Reference to destination variable to store retrieved value - * @param [_IN] defVal Default value for case of non-existing key - */ - void read(const char *key, QList &dest, const QList &defVal = QList()); - /** - * @brief Retreive value by specific key and pass it via reference - * @param [_IN] key name of key with value to retrieved - * @param [_OUT] dest Reference to destination variable to store retrieved value - * @param [_IN] defVal Default value for case of non-existing key - */ - void read(const char *key, QList &dest, const QList &defVal = QList()); - /** - * @brief Retreive value by specific key and pass it via reference - * @param [_IN] key name of key with value to retrieved - * @param [_OUT] dest Reference to destination variable to store retrieved value - * @param [_IN] defVal Default value for case of non-existing key - */ - void read(const char *key, QList &dest, const QList &defVal = QList()); - /** - * @brief Retreive value by specific key and pass it via reference - * @param [_IN] key name of key with value to retrieved - * @param [_OUT] dest Reference to destination variable to store retrieved value - * @param [_IN] defVal Default value for case of non-existing key - */ - void read(const char *key, QList &dest, const QList &defVal = QList()); - - /** - * @brief Retreive value by specific key and pass it via reference - * @param [_IN] key name of key with value to retrieved - * @param [_OUT] dest Reference to destination variable to store retrieved value - * @param [_IN] defVal Default value for case of non-existing key - */ - void read(const char *key, QVector &dest, const QVector &defVal = QVector()); - /** - * @brief Retreive value by specific key and pass it via reference - * @param [_IN] key name of key with value to retrieved - * @param [_OUT] dest Reference to destination variable to store retrieved value - * @param [_IN] defVal Default value for case of non-existing key - */ - void read(const char *key, QVector &dest, const QVector &defVal = QVector()); - /** - * @brief Retreive value by specific key and pass it via reference - * @param [_IN] key name of key with value to retrieved - * @param [_OUT] dest Reference to destination variable to store retrieved value - * @param [_IN] defVal Default value for case of non-existing key - */ - void read(const char *key, QVector &dest, const QVector &defVal = QVector()); - /** - * @brief Retreive value by specific key and pass it via reference - * @param [_IN] key name of key with value to retrieved - * @param [_OUT] dest Reference to destination variable to store retrieved value - * @param [_IN] defVal Default value for case of non-existing key - */ - void read(const char *key, QVector &dest, const QVector &defVal = QVector()); - /** - * @brief Retreive value by specific key and pass it via reference - * @param [_IN] key name of key with value to retrieved - * @param [_OUT] dest Reference to destination variable to store retrieved value - * @param [_IN] defVal Default value for case of non-existing key - */ - void read(const char *key, QVector &dest, const QVector &defVal = QVector()); - /** - * @brief Retreive value by specific key and pass it via reference - * @param [_IN] key name of key with value to retrieved - * @param [_OUT] dest Reference to destination variable to store retrieved value - * @param [_IN] defVal Default value for case of non-existing key - */ - void read(const char *key, QVector &dest, const QVector &defVal = QVector()); - /** - * @brief Retreive value by specific key and pass it via reference - * @param [_IN] key name of key with value to retrieved - * @param [_OUT] dest Reference to destination variable to store retrieved value - * @param [_IN] defVal Default value for case of non-existing key - */ - void read(const char *key, QVector &dest, const QVector &defVal = QVector()); - /** - * @brief Retreive value by specific key and pass it via reference - * @param [_IN] key name of key with value to retrieved - * @param [_OUT] dest Reference to destination variable to store retrieved value - * @param [_IN] defVal Default value for case of non-existing key - */ - void read(const char *key, QVector &dest, const QVector &defVal = QVector()); - /** - * @brief Retreive value by specific key and pass it via reference - * @param [_IN] key name of key with value to retrieved - * @param [_OUT] dest Reference to destination variable to store retrieved value - * @param [_IN] defVal Default value for case of non-existing key - */ - void read(const char *key, QVector &dest, const QVector &defVal = QVector()); - /** - * @brief Retreive value by specific key and pass it via reference - * @param [_IN] key name of key with value to retrieved - * @param [_OUT] dest Reference to destination variable to store retrieved value - * @param [_IN] defVal Default value for case of non-existing key - */ - void read(const char *key, QVector &dest, const QVector &defVal = QVector()); - /** - * @brief Retreive value by specific key and pass it via reference - * @param [_IN] key name of key with value to retrieved - * @param [_OUT] dest Reference to destination variable to store retrieved value - * @param [_IN] defVal Default value for case of non-existing key - */ - void read(const char *key, QVector &dest, const QVector &defVal = QVector()); - #endif - - //! Hash-table for the fast string to enum conversion - typedef std::unordered_map StrEnumMap; - - - template - /** - * @brief Retreive value by string-based enum key - * @param [_IN] key name of key with value to retrieved - * @param [_OUT] dest Reference to destination variable to store retrieved value - * @param [_IN] defVal Default value for case of non-existing key - * @param [_IN] enumMap - */ - void readEnum(const char *key, T &dest, T defVal, IniProcessing::StrEnumMap enumMap) - { - bool ok = false; - params::IniKeys::iterator e = readHelper(key, ok); - - if(!ok) - { - dest = defVal; - return; - } - - StrEnumMap::iterator em = enumMap.find(e->second); - - if(em == enumMap.end()) - { - dest = defVal; - return; - } - - dest = static_cast(em->second); - } - - /** - * @brief QSettings-compatible way to retreive value - * @param key key with value to retreive - * @param defVal default value key - * @return variant which contains a value - */ - IniProcessingVariant value(const char *key, const IniProcessingVariant &defVal = IniProcessingVariant()); - - void setValue(const char *key, unsigned short value); - void setValue(const char *key, short value); - void setValue(const char *key, unsigned int value); - void setValue(const char *key, int value); - void setValue(const char *key, unsigned long value); - void setValue(const char *key, long value); - void setValue(const char *key, unsigned long long value); - void setValue(const char *key, long long value); - void setValue(const char *key, float value); - void setValue(const char *key, double value); - void setValue(const char *key, long double value); - - template - static inline std::string to_string_with_precision(const T a_value) - { - char buf[35]; - memset(buf, 0, 35); - snprintf(buf, 34, "%.15g", static_cast(a_value)); - return buf; - } - - template - static inline std::string fromVector(const TList &value) - { - typedef typename TList::value_type T; - std::string out; - for(const T &f: value) - { - if(!out.empty()) - out.push_back(','); - if(std::is_same::value || - std::is_same::value || - std::is_same::value) - out.append(to_string_with_precision(f)); - else - out.append(std::to_string(f)); - } - return out; - } - - template - void setValue(const char *key, const std::vector &value) - { - static_assert(std::is_arithmetic::value, "Not arithmetic (integral or floating point required!)"); - writeIniParam(key, fromVector(value)); - } - - void setValue(const char *key, const char *value); - void setValue(const char *key, const std::string &value); - - #ifdef INI_PROCESSING_ALLOW_QT_TYPES - void setValue(const char *key, const QString &value); - - template - void setValue(const char *key, const QList &value) - { - static_assert(std::is_arithmetic::value, "Not arithmetic (integral or floating point required!)"); - writeIniParam(key, fromVector(value)); - } - - template - void setValue(const char *key, const QVector &value) - { - static_assert(std::is_arithmetic::value, "Not arithmetic (integral or floating point required!)"); - writeIniParam(key, fromVector(value)); - } - #endif - - /** - * @brief Write INI file by the recently given file path - * @return true if INI file was successfully written - */ - bool writeIniFile(); -}; - -#endif // INIPROCESSING_H diff --git a/src/gen_adldata/ini/ini_processing_variant.h b/src/gen_adldata/ini/ini_processing_variant.h deleted file mode 100644 index 34f999a..0000000 --- a/src/gen_adldata/ini/ini_processing_variant.h +++ /dev/null @@ -1,243 +0,0 @@ -/* -INI Processor - a small library which allows you parsing INI-files - -Copyright (c) 2017 Vitaliy Novichkov - -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. -*/ - -/* -A QVariant-like thing created just like a proxy between -INI Processor and target value (to be compatible with QSettings) -*/ - -#ifndef INI_PROCESSING_VARIANT_H -#define INI_PROCESSING_VARIANT_H - -#include -#include -#include -#ifdef INI_PROCESSING_ALLOW_QT_TYPES -#include -#endif - -class IniProcessingVariant -{ - std::string m_data; - std::string *m_dataP; - inline std::string &data() - { - if(m_dataP) - return *m_dataP; - else - return m_data; - } -public: - IniProcessingVariant(): - m_data(""), - m_dataP(nullptr) {} - - IniProcessingVariant(const std::string &data): - m_data(data), - m_dataP(nullptr) {} - IniProcessingVariant(const char *data): - m_data(data), - m_dataP(nullptr) {} - #ifdef INI_PROCESSING_ALLOW_QT_TYPES - IniProcessingVariant(const QString &data): - m_data(data.toStdString()), - m_dataP(nullptr) {} - #endif - IniProcessingVariant(std::string *dataPointer): - m_data(""), - m_dataP(dataPointer) {} - - IniProcessingVariant(const IniProcessingVariant &v): - m_data(v.m_data), - m_dataP(v.m_dataP) {} - - IniProcessingVariant(char data): - m_data(std::to_string(data)), - m_dataP(nullptr) {} - - IniProcessingVariant(unsigned char data): - m_data(std::to_string(data)), - m_dataP(nullptr) {} - - IniProcessingVariant(bool data): - m_data(std::to_string(data)), - m_dataP(nullptr) {} - - IniProcessingVariant(short data): - m_data(std::to_string(data)), - m_dataP(nullptr) {} - - IniProcessingVariant(unsigned short data): - m_data(std::to_string(data)), - m_dataP(nullptr) {} - - IniProcessingVariant(int data): - m_data(std::to_string(data)), - m_dataP(nullptr) {} - IniProcessingVariant(unsigned int data): - m_data(std::to_string(data)), - m_dataP(nullptr) {} - - IniProcessingVariant(long data): - m_data(std::to_string(data)), - m_dataP(nullptr) {} - IniProcessingVariant(unsigned long data): - m_data(std::to_string(data)), - m_dataP(nullptr) {} - - IniProcessingVariant(long long data): - m_data(std::to_string(data)), - m_dataP(nullptr) {} - IniProcessingVariant(unsigned long long data): - m_data(std::to_string(data)), - m_dataP(nullptr) {} - - IniProcessingVariant(float data): - m_data(std::to_string(data)), - m_dataP(nullptr) {} - - IniProcessingVariant(double data): - m_data(std::to_string(data)), - m_dataP(nullptr) {} - - IniProcessingVariant(long double data): - m_data(std::to_string(data)), - m_dataP(nullptr) {} - - bool isNull() - { - return (m_data.empty() && !m_dataP); - } - - bool isValid() - { - return ((!m_data.empty()) || (static_cast(m_dataP))); - } - - std::string toString() - { - std::string out = data(); - - if((out.size() > 2) && (out[0] == '"')) - out.erase(0, 1); - - if((out.size() > 1) && (out[out.size() - 1] == '"')) - out.erase((out.size() - 1), 1); - - return out; - } - - #ifdef INI_PROCESSING_ALLOW_QT_TYPES - QString toQString() - { - return QString::fromStdString(toString()); - } - #endif - - bool toBool() - { - size_t i = 0; - size_t ss = std::min(static_cast(4ul), data().size()); - char buff[4] = {0, 0, 0, 0}; - const char *pbufi = data().c_str(); - char *pbuff = buff; - - for(; i < ss; i++) - (*pbuff++) = static_cast(std::tolower(*pbufi++)); - - if(ss < 4) - { - if(ss == 0) - return false; - - if(ss == 1) - return (buff[0] == '1'); - - try - { - long num = std::strtol(buff, 0, 0); - return num != 0l; - } - catch(...) - { - bool res = (std::memcmp(buff, "yes", 3) == 0) || - (std::memcmp(buff, "on", 2) == 0); - return res; - } - } - - if(std::memcmp(buff, "true", 4) == 0) - return true; - - try - { - long num = std::strtol(buff, 0, 0); - return num != 0l; - } - catch(...) - { - return false; - } - } - - int toInt() - { - return std::atoi(data().c_str()); - } - unsigned int toUInt() - { - return static_cast(std::strtoul(data().c_str(), nullptr, 0)); - } - - long toLong() - { - return std::atol(data().c_str()); - } - unsigned long toULong() - { - return std::strtoul(data().c_str(), nullptr, 0); - } - - long long toLongLong() - { - return std::atoll(data().c_str()); - } - unsigned long long toULongLong() - { - return std::strtoull(data().c_str(), nullptr, 0); - } - - float toFloat() - { - return float(std::atof(data().c_str())); - } - - double toDouble() - { - return std::atof(data().c_str()); - } -}; - - -#endif // INI_PROCESSING_VARIANT_H diff --git a/src/gen_adldata/measurer.cpp b/src/gen_adldata/measurer.cpp deleted file mode 100644 index 6020ea0..0000000 --- a/src/gen_adldata/measurer.cpp +++ /dev/null @@ -1,543 +0,0 @@ -#include "measurer.h" -#include - -#ifndef ADLMIDI_USE_DOSBOX_OPL -#include "../nukedopl3.h" -#else -#include "../dbopl.h" -#endif - -DurationInfo MeasureDurations(const ins &in) -{ - std::vector stereoSampleBuf; -#ifdef ADLMIDI_USE_DOSBOX_OPL - std::vector stereoSampleBuf_32; -#endif - insdata id[2]; - bool found[2] = {false, false}; - for(InstrumentDataTab::const_iterator j = insdatatab.begin(); - j != insdatatab.end(); - ++j) - { - if(j->second.first == in.insno1) - { - id[0] = j->first; - found[0] = true; - if(found[1]) break; - } - if(j->second.first == in.insno2) - { - id[1] = j->first; - found[1] = true; - if(found[0]) break; - } - } - const unsigned rate = 22010; - const unsigned interval = 150; - const unsigned samples_per_interval = rate / interval; - const int notenum = - in.notenum < 20 ? (44 + in.notenum) - : in.notenum >= 128 ? (44 + 128 - in.notenum) - : in.notenum; - -#ifndef ADLMIDI_USE_DOSBOX_OPL -#define WRITE_REG(key, value) OPL3_WriteReg(&opl, (Bit8u)(key), (Bit8u)(value)) - _opl3_chip opl; -#else -#define WRITE_REG(key, value) opl.WriteReg((Bit8u)(key), (Bit8u)(value)); - DBOPL::Handler opl; -#endif - - static const short initdata[(2 + 3 + 2 + 2) * 2] = - { - 0x004, 96, 0x004, 128, // Pulse timer - 0x105, 0, 0x105, 1, 0x105, 0, // Pulse OPL3 enable, leave disabled - 0x001, 32, 0x0BD, 0 // Enable wave & melodic -}; -#ifndef ADLMIDI_USE_DOSBOX_OPL - OPL3_Reset(&opl, rate); -#else - opl.Init(rate); -#endif - for(unsigned a = 0; a < 18; a += 2) WRITE_REG(initdata[a], initdata[a + 1]); - - const unsigned n_notes = in.insno1 == in.insno2 ? 1 : 2; - unsigned x[2]; - - if(n_notes == 2 && !in.pseudo4op) - { - WRITE_REG(0x105, 1); - WRITE_REG(0x104, 1); - } - - for(unsigned n = 0; n < n_notes; ++n) - { - static const unsigned char patchdata[11] = - {0x20, 0x23, 0x60, 0x63, 0x80, 0x83, 0xE0, 0xE3, 0x40, 0x43, 0xC0}; - for(unsigned a = 0; a < 10; ++a) WRITE_REG(patchdata[a] + n * 8, id[n].data[a]); - WRITE_REG(patchdata[10] + n * 8, id[n].data[10] | 0x30); - } - - for(unsigned n = 0; n < n_notes; ++n) - { - double hertz = 172.00093 * std::exp(0.057762265 * (notenum + id[n].finetune)); - if(hertz > 131071) - { - fprintf(stderr, "Why does note %d + finetune %d produce hertz %g?\n", - notenum, id[n].finetune, hertz); - hertz = 131071; - } - x[n] = 0x2000; - while(hertz >= 1023.5) - { - hertz /= 2.0; // Calculate octave - x[n] += 0x400; - } - x[n] += (unsigned int)(hertz + 0.5); - - // Keyon the note - WRITE_REG(0xA0 + n * 3, x[n] & 0xFF); - WRITE_REG(0xB0 + n * 3, x[n] >> 8); - } - - const unsigned max_on = 40; - const unsigned max_off = 60; - - // For up to 40 seconds, measure mean amplitude. - std::vector amplitudecurve_on; - double highest_sofar = 0; - for(unsigned period = 0; period < max_on * interval; ++period) - { - stereoSampleBuf.clear(); - stereoSampleBuf.resize(samples_per_interval * 2); -#ifndef ADLMIDI_USE_DOSBOX_OPL - OPL3_GenerateStream(&opl, stereoSampleBuf.data(), samples_per_interval); -#else - { - stereoSampleBuf_32.resize(samples_per_interval * 2); - Bitu samples = samples_per_interval; - opl.GenerateArr(stereoSampleBuf_32.data(), &samples); - size_t ssat = 0; - for(const int32_t &i : stereoSampleBuf_32) - stereoSampleBuf[ssat++] = (int16_t)i; - } -#endif - - double mean = 0.0; - for(unsigned long c = 0; c < samples_per_interval; ++c) - mean += stereoSampleBuf[c * 2]; - mean /= samples_per_interval; - double std_deviation = 0; - for(unsigned long c = 0; c < samples_per_interval; ++c) - { - double diff = (stereoSampleBuf[c * 2] - mean); - std_deviation += diff * diff; - } - std_deviation = std::sqrt(std_deviation / samples_per_interval); - amplitudecurve_on.push_back(std_deviation); - if(std_deviation > highest_sofar) - highest_sofar = std_deviation; - - if(period > 6 * interval && std_deviation < highest_sofar * 0.2) - break; - } - - // Keyoff the note - for(unsigned n = 0; n < n_notes; ++n) - WRITE_REG(0xB0 + n, (x[n] >> 8) & 0xDF); - - // Now, for up to 60 seconds, measure mean amplitude. - std::vector amplitudecurve_off; - for(unsigned period = 0; period < max_off * interval; ++period) - { - stereoSampleBuf.clear(); - stereoSampleBuf.resize(samples_per_interval * 2); -#ifndef ADLMIDI_USE_DOSBOX_OPL - OPL3_GenerateStream(&opl, stereoSampleBuf.data(), samples_per_interval); -#else - { - stereoSampleBuf_32.resize(samples_per_interval * 2); - Bitu samples = samples_per_interval; - opl.GenerateArr(stereoSampleBuf_32.data(), &samples); - size_t ssat = 0; - for(const int32_t &i : stereoSampleBuf_32) - stereoSampleBuf[ssat++] = (int16_t)i; - } -#endif - - double mean = 0.0; - for(unsigned long c = 0; c < samples_per_interval; ++c) - mean += stereoSampleBuf[c * 2]; - mean /= samples_per_interval; - double std_deviation = 0; - for(unsigned long c = 0; c < samples_per_interval; ++c) - { - double diff = (stereoSampleBuf[c * 2] - mean); - std_deviation += diff * diff; - } - std_deviation = std::sqrt(std_deviation / samples_per_interval); - amplitudecurve_off.push_back(std_deviation); - - if(std_deviation < highest_sofar * 0.2) break; - } - - /* Analyze the results */ - double begin_amplitude = amplitudecurve_on[0]; - double peak_amplitude_value = begin_amplitude; - size_t peak_amplitude_time = 0; - size_t quarter_amplitude_time = amplitudecurve_on.size(); - size_t keyoff_out_time = 0; - - for(size_t a = 1; a < amplitudecurve_on.size(); ++a) - { - if(amplitudecurve_on[a] > peak_amplitude_value) - { - peak_amplitude_value = amplitudecurve_on[a]; - peak_amplitude_time = a; - } - } - for(size_t a = peak_amplitude_time; a < amplitudecurve_on.size(); ++a) - { - if(amplitudecurve_on[a] <= peak_amplitude_value * 0.2) - { - quarter_amplitude_time = a; - break; - } - } - for(size_t a = 0; a < amplitudecurve_off.size(); ++a) - { - if(amplitudecurve_off[a] <= peak_amplitude_value * 0.2) - { - keyoff_out_time = a; - break; - } - } - - if(keyoff_out_time == 0 && amplitudecurve_on.back() < peak_amplitude_value * 0.2) - keyoff_out_time = quarter_amplitude_time; - - DurationInfo result; - result.peak_amplitude_time = peak_amplitude_time; - result.peak_amplitude_value = peak_amplitude_value; - result.begin_amplitude = begin_amplitude; - result.quarter_amplitude_time = quarter_amplitude_time; - result.keyoff_out_time = keyoff_out_time; - - result.ms_sound_kon = (long)(quarter_amplitude_time * 1000.0 / interval); - result.ms_sound_koff = (long)(keyoff_out_time * 1000.0 / interval); - result.nosound = (peak_amplitude_value < 0.5); - return result; -} - -static const char* spinner = "-\\|/"; - -void MeasureThreaded::LoadCache(const char *fileName) -{ - FILE *in = std::fopen(fileName, "rb"); - if(!in) - { - std::printf("Failed to load cache: file is not exists.\n" - "Complete data will be generated from scratch.\n"); - std::fflush(stdout); - return; - } - - char magic[32]; - if(std::fread(magic, 1, 32, in) != 32) - { - std::fclose(in); - std::printf("Failed to load cache: can't read magic.\n" - "Complete data will be generated from scratch.\n"); - std::fflush(stdout); - return; - } - - if(memcmp(magic, "ADLMIDI-DURATION-CACHE-FILE-V1.0", 32) != 0) - { - std::fclose(in); - std::printf("Failed to load cache: magic missmatch.\n" - "Complete data will be generated from scratch.\n"); - std::fflush(stdout); - return; - } - - while(!std::feof(in)) - { - DurationInfo info; - ins inst; - //got by instrument - insdata id[2]; - size_t insNo[2] = {0, 0}; - bool found[2] = {false, false}; - //got from file - insdata id_f[2]; - bool found_f[2] = {false, false}; - bool isMatches = false; - - memset(id, 0, sizeof(insdata) * 2); - memset(id_f, 0, sizeof(insdata) * 2); - memset(&info, 0, sizeof(DurationInfo)); - memset(&inst, 0, sizeof(ins)); - - //Instrument - uint64_t inval; - if(std::fread(&inval, 1, sizeof(uint64_t), in) != sizeof(uint64_t)) - break; - inst.insno1 = inval; - if(std::fread(&inval, 1, sizeof(uint64_t), in) != sizeof(uint64_t)) - break; - inst.insno2 = inval; - if(std::fread(&inst.notenum, 1, 1, in) != 1) - break; - if(std::fread(&inst.pseudo4op, 1, 1, in) != 1) - break; - if(std::fread(&inst.voice2_fine_tune, sizeof(double), 1, in) != 1) - break; - - //Instrument data - if(fread(found_f, 1, 2 * sizeof(bool), in) != sizeof(bool) * 2) - break; - for(size_t i = 0; i < 2; i++) - { - if(fread(id_f[i].data, 1, 11, in) != 11) - break; - if(fread(&id_f[i].finetune, 1, 1, in) != 1) - break; - if(fread(&id_f[i].diff, 1, sizeof(bool), in) != sizeof(bool)) - break; - } - - if(found_f[0] || found_f[1]) - { - for(InstrumentDataTab::const_iterator j = insdatatab.begin(); j != insdatatab.end(); ++j) - { - if(j->second.first == inst.insno1) - { - id[0] = j->first; - found[0] = (id[0] == id_f[0]); - insNo[0] = inst.insno1; - if(found[1]) break; - } - if(j->second.first == inst.insno2) - { - id[1] = j->first; - found[1] = (id[1] == id_f[1]); - insNo[1] = inst.insno2; - if(found[0]) break; - } - } - - //Find instrument entries are matching - if((found[0] != found_f[0]) || (found[1] != found_f[1])) - { - for(InstrumentDataTab::const_iterator j = insdatatab.begin(); j != insdatatab.end(); ++j) - { - if(found_f[0] && (j->first == id_f[0])) - { - found[0] = true; - insNo[0] = j->second.first; - } - if(found_f[1] && (j->first == id_f[1])) - { - found[1] = true; - insNo[1] = j->second.first; - } - if(found[0] && !found_f[1]) - { - isMatches = true; - break; - } - if(found[0] && found[1]) - { - isMatches = true; - break; - } - } - } - else - { - isMatches = true; - } - - //Then find instrument entry that uses found instruments - if(isMatches) - { - inst.insno1 = insNo[0]; - inst.insno2 = insNo[1]; - InstrumentsData::iterator d = instab.find(inst); - if(d == instab.end()) - isMatches = false; - } - } - - //Duration data - if(std::fread(&info.peak_amplitude_time, 1, sizeof(uint64_t), in) != sizeof(uint64_t)) - break; - if(std::fread(&info.peak_amplitude_value, 1, sizeof(double), in) != sizeof(double)) - break; - if(std::fread(&info.quarter_amplitude_time, 1, sizeof(double), in) != sizeof(double)) - break; - if(std::fread(&info.begin_amplitude, 1, sizeof(double), in) != sizeof(double)) - break; - if(std::fread(&info.interval, 1, sizeof(double), in) != sizeof(double)) - break; - if(std::fread(&info.keyoff_out_time, 1, sizeof(double), in) != sizeof(double)) - break; - if(std::fread(&info.ms_sound_kon, 1, sizeof(int64_t), in) != sizeof(int64_t)) - break; - if(std::fread(&info.ms_sound_koff, 1, sizeof(int64_t), in) != sizeof(int64_t)) - break; - if(std::fread(&info.nosound, 1, sizeof(bool), in) != sizeof(bool)) - break; - - if(isMatches)//Store only if cached entry matches actual raw instrument data - m_durationInfo.insert({inst, info}); - } - - std::printf("Cache loaded!\n"); - std::fflush(stdout); - - std::fclose(in); -} - -void MeasureThreaded::SaveCache(const char *fileName) -{ - FILE *out = std::fopen(fileName, "wb"); - fprintf(out, "ADLMIDI-DURATION-CACHE-FILE-V1.0"); - for(DurationInfoCache::iterator it = m_durationInfo.begin(); it != m_durationInfo.end(); it++) - { - const ins &in = it->first; - insdata id[2]; - bool found[2] = {false, false}; - memset(id, 0, sizeof(insdata) * 2); - - uint64_t outval; - outval = in.insno1; - fwrite(&outval, 1, sizeof(uint64_t), out); - outval = in.insno2; - fwrite(&outval, 1, sizeof(uint64_t), out); - fwrite(&in.notenum, 1, 1, out); - fwrite(&in.pseudo4op, 1, 1, out); - fwrite(&in.voice2_fine_tune, sizeof(double), 1, out); - - for(InstrumentDataTab::const_iterator j = insdatatab.begin(); j != insdatatab.end(); ++j) - { - if(j->second.first == in.insno1) - { - id[0] = j->first; - found[0] = true; - if(found[1]) break; - } - if(j->second.first == in.insno2) - { - id[1] = j->first; - found[1] = true; - if(found[0]) break; - } - } - - fwrite(found, 1, 2 * sizeof(bool), out); - for(size_t i = 0; i < 2; i++) - { - fwrite(id[i].data, 1, 11, out); - fwrite(&id[i].finetune, 1, 1, out); - fwrite(&id[i].diff, 1, sizeof(bool), out); - } - - fwrite(&it->second.peak_amplitude_time, 1, sizeof(uint64_t), out); - fwrite(&it->second.peak_amplitude_value, 1, sizeof(double), out); - fwrite(&it->second.quarter_amplitude_time, 1, sizeof(double), out); - fwrite(&it->second.begin_amplitude, 1, sizeof(double), out); - fwrite(&it->second.interval, 1, sizeof(double), out); - fwrite(&it->second.keyoff_out_time, 1, sizeof(double), out); - fwrite(&it->second.ms_sound_kon, 1, sizeof(int64_t), out); - fwrite(&it->second.ms_sound_koff, 1, sizeof(int64_t), out); - fwrite(&it->second.nosound, 1, sizeof(bool), out); - } - std::fclose(out); -} - -void MeasureThreaded::printProgress() -{ - std::printf("Calculating measures... [%c %3u%% (%4u/%4u) Threads %3u, Matches %u] \r", - spinner[m_done.load() % 4], - (unsigned int)(((double)m_done.load() / (double)(m_total)) * 100), - (unsigned int)m_done.load(), - (unsigned int)m_total, - (unsigned int)m_threads.size(), - (unsigned int)m_cache_matches - ); - std::fflush(stdout); -} - -void MeasureThreaded::printFinal() -{ - std::printf("Calculating measures completed! [Total entries %4u with %u cache matches]\n", - (unsigned int)m_total, - (unsigned int)m_cache_matches); - std::fflush(stdout); -} - -void MeasureThreaded::run(InstrumentsData::const_iterator i) -{ - m_semaphore.wait(); - if(m_threads.size() > 0) - { - for(std::vector::iterator it = m_threads.begin(); it != m_threads.end();) - { - if(!(*it)->m_works) - { - delete(*it); - it = m_threads.erase(it); - } - else - it++; - } - } - - destData *dd = new destData; - dd->i = i; - dd->myself = this; - dd->start(); - m_threads.push_back(dd); - printProgress(); -} - -void MeasureThreaded::waitAll() -{ - for(auto &th : m_threads) - { - printProgress(); - delete th; - } - m_threads.clear(); - printFinal(); -} - -void MeasureThreaded::destData::start() -{ - m_work = std::thread(&destData::callback, this); -} - -void MeasureThreaded::destData::callback(void *myself) -{ - destData *s = reinterpret_cast(myself); - DurationInfo info; - DurationInfoCache::iterator cachedEntry = s->myself->m_durationInfo.find(s->i->first); - - if(cachedEntry != s->myself->m_durationInfo.end()) - { - s->myself->m_cache_matches++; - goto endWork; - } - - info = MeasureDurations(s->i->first); - s->myself->m_durationInfo_mx.lock(); - s->myself->m_durationInfo.insert({s->i->first, info}); - s->myself->m_durationInfo_mx.unlock(); - -endWork: - s->myself->m_semaphore.notify(); - s->myself->m_done++; - s->m_works = false; -} diff --git a/src/gen_adldata/measurer.h b/src/gen_adldata/measurer.h deleted file mode 100644 index b9ae3c6..0000000 --- a/src/gen_adldata/measurer.h +++ /dev/null @@ -1,105 +0,0 @@ -#ifndef MEASURER_H -#define MEASURER_H - -#include -#include -#include -#include -#include - -#include "progs_cache.h" - -struct DurationInfo -{ - uint64_t peak_amplitude_time; - double peak_amplitude_value; - double quarter_amplitude_time; - double begin_amplitude; - double interval; - double keyoff_out_time; - int64_t ms_sound_kon; - int64_t ms_sound_koff; - bool nosound; - uint8_t padding[7]; -}; - -class Semaphore -{ -public: - Semaphore(int count_ = 0) - : m_count(count_) {} - - inline void notify() - { - std::unique_lock lock(mtx); - m_count++; - cv.notify_one(); - } - - inline void wait() - { - std::unique_lock lock(mtx); - while(m_count == 0) - { - cv.wait(lock); - } - m_count--; - } - -private: - std::mutex mtx; - std::condition_variable cv; - std::atomic_int m_count; -}; - -struct MeasureThreaded -{ - typedef std::map DurationInfoCache; - - MeasureThreaded() : - m_semaphore(int(std::thread::hardware_concurrency()) * 2), - m_done(0), - m_cache_matches(0) - {} - - Semaphore m_semaphore; - std::mutex m_durationInfo_mx; - DurationInfoCache m_durationInfo; - std::atomic_bool m_delete_tail; - size_t m_total = 0; - std::atomic m_done; - std::atomic m_cache_matches; - - void LoadCache(const char *fileName); - void SaveCache(const char *fileName); - - struct destData - { - destData() - { - m_works = true; - } - ~destData() - { - m_work.join(); - } - MeasureThreaded *myself; - std::map > >::const_iterator i; - std::thread m_work; - std::atomic_bool m_works; - - void start(); - static void callback(void *myself); - }; - - std::vector m_threads; - - void printProgress(); - void printFinal(); - void run(InstrumentsData::const_iterator i); - void waitAll(); -}; - -extern DurationInfo MeasureDurations(const ins &in); - -#endif // MEASURER_H diff --git a/src/gen_adldata/midi_inst_list.h b/src/gen_adldata/midi_inst_list.h deleted file mode 100644 index 61c9119..0000000 --- a/src/gen_adldata/midi_inst_list.h +++ /dev/null @@ -1,185 +0,0 @@ -#pragma once -#ifndef MIDI_INS_LIST -#define MIDI_INS_LIST - -static const char *const MidiInsName[] = { -"AcouGrandPiano", -"BrightAcouGrand", -"ElecGrandPiano", -"Honky-tonkPiano", -"Rhodes Piano", -"Chorused Piano", -"Harpsichord", -"Clavinet", -"Celesta", -"Glockenspiel", -"Music box", -"Vibraphone", -"Marimba", -"Xylophone", -"Tubular Bells", -"Dulcimer", -"Hammond Organ", -"Percussive Organ", -"Rock Organ", -"Church Organ", -"Reed Organ", -"Accordion", -"Harmonica", -"Tango Accordion", -"Acoustic Guitar1", -"Acoustic Guitar2", -"Electric Guitar1", -"Electric Guitar2", -"Electric Guitar3", -"Overdrive Guitar", -"Distorton Guitar", -"Guitar Harmonics", -"Acoustic Bass", -"Electric Bass 1", -"Electric Bass 2", -"Fretless Bass", -"Slap Bass 1", -"Slap Bass 2", -"Synth Bass 1", -"Synth Bass 2", -"Violin", -"Viola", -"Cello", -"Contrabass", -"Tremulo Strings", -"Pizzicato String", -"Orchestral Harp", -"Timpany", -"String Ensemble1", -"String Ensemble2", -"Synth Strings 1", -"SynthStrings 2", -"Choir Aahs", -"Voice Oohs", -"Synth Voice", -"Orchestra Hit", -"Trumpet", -"Trombone", -"Tuba", -"Muted Trumpet", -"French Horn", -"Brass Section", -"Synth Brass 1", -"Synth Brass 2", -"Soprano Sax", -"Alto Sax", -"Tenor Sax", -"Baritone Sax", -"Oboe", -"English Horn", -"Bassoon", -"Clarinet", -"Piccolo", -"Flute", -"Recorder", -"Pan Flute", -"Bottle Blow", -"Shakuhachi", -"Whistle", -"Ocarina", -"Lead 1 squareea", -"Lead 2 sawtooth", -"Lead 3 calliope", -"Lead 4 chiff", -"Lead 5 charang", -"Lead 6 voice", -"Lead 7 fifths", -"Lead 8 brass", -"Pad 1 new age", -"Pad 2 warm", -"Pad 3 polysynth", -"Pad 4 choir", -"Pad 5 bowedpad", -"Pad 6 metallic", -"Pad 7 halo", -"Pad 8 sweep", -"FX 1 rain", -"FX 2 soundtrack", -"FX 3 crystal", -"FX 4 atmosphere", -"FX 5 brightness", -"FX 6 goblins", -"FX 7 echoes", -"FX 8 sci-fi", -"Sitar", -"Banjo", -"Shamisen", -"Koto", -"Kalimba", -"Bagpipe", -"Fiddle", -"Shanai", -"Tinkle Bell", -"Agogo Bells", -"Steel Drums", -"Woodblock", -"Taiko Drum", -"Melodic Tom", -"Synth Drum", -"Reverse Cymbal", -"Guitar FretNoise", -"Breath Noise", -"Seashore", -"Bird Tweet", -"Telephone", -"Helicopter", -"Applause/Noise", -"Gunshot", -// 27..34: High Q; Slap; Scratch Push; Scratch Pull; Sticks; -// Square Click; Metronome Click; Metronome Bell -"Ac Bass Drum", -"Bass Drum 1", -"Side Stick", -"Acoustic Snare", -"Hand Clap", -"Electric Snare", -"Low Floor Tom", -"Closed High Hat", -"High Floor Tom", -"Pedal High Hat", -"Low Tom", -"Open High Hat", -"Low-Mid Tom", -"High-Mid Tom", -"Crash Cymbal 1", -"High Tom", -"Ride Cymbal 1", -"Chinese Cymbal", -"Ride Bell", -"Tambourine", -"Splash Cymbal", -"Cow Bell", -"Crash Cymbal 2", -"Vibraslap", -"Ride Cymbal 2", -"High Bongo", -"Low Bongo", -"Mute High Conga", -"Open High Conga", -"Low Conga", -"High Timbale", -"Low Timbale", -"High Agogo", -"Low Agogo", -"Cabasa", -"Maracas", -"Short Whistle", -"Long Whistle", -"Short Guiro", -"Long Guiro", -"Claves", -"High Wood Block", -"Low Wood Block", -"Mute Cuica", -"Open Cuica", -"Mute Triangle", -"Open Triangle", -"Shaker","Jingle Bell","Bell Tree","Castanets","Mute Surdu","Open Surdu",""}; - -#endif //MIDI_INS_LIST diff --git a/src/gen_adldata/progs_cache.cpp b/src/gen_adldata/progs_cache.cpp deleted file mode 100644 index 4aec9be..0000000 --- a/src/gen_adldata/progs_cache.cpp +++ /dev/null @@ -1,106 +0,0 @@ -#include "progs_cache.h" - -InstrumentDataTab insdatatab; - -InstrumentsData instab; -InstProgsData progs; - -std::vector banknames; - -//unsigned maxvalues[30] = { 0 }; - -void SetBank(unsigned bank, unsigned patch, size_t insno) -{ - progs[bank][patch] = insno + 1; -} - -size_t InsertIns( - const insdata &id, - const insdata &id2, - ins &in, - const std::string &name, - const std::string &name2) -{ - if(true) - { - InstrumentDataTab::iterator i = insdatatab.lower_bound(id); - - size_t insno = size_t(~0); - if(i == insdatatab.end() || i->first != id) - { - std::pair > > res; - res.first = id; - res.second.first = insdatatab.size(); - if(!name.empty()) res.second.second.insert(name); - if(!name2.empty()) res.second.second.insert(name2); - insdatatab.insert(i, res); - insno = res.second.first; - } - else - { - if(!name.empty()) i->second.second.insert(name); - if(!name2.empty()) i->second.second.insert(name2); - insno = i->second.first; - } - - in.insno1 = insno; - } - if(id != id2) - { - InstrumentDataTab::iterator i = insdatatab.lower_bound(id2); - - size_t insno2 = size_t(~0); - if(i == insdatatab.end() || i->first != id2) - { - std::pair > > res; - res.first = id2; - res.second.first = insdatatab.size(); - if(!name.empty()) res.second.second.insert(name); - if(!name2.empty()) res.second.second.insert(name2); - insdatatab.insert(i, res); - insno2 = res.second.first; - } - else - { - if(!name.empty()) i->second.second.insert(name); - if(!name2.empty()) i->second.second.insert(name2); - insno2 = i->second.first; - } - in.insno2 = insno2; - } - else - in.insno2 = in.insno1; - - - { - InstrumentsData::iterator i = instab.lower_bound(in); - - size_t resno = size_t(~0); - if(i == instab.end() || i->first != in) - { - std::pair > > res; - res.first = in; - res.second.first = instab.size(); - if(!name.empty()) res.second.second.insert(name); - if(!name2.empty()) res.second.second.insert(name2); - instab.insert(i, res); - resno = res.second.first; - } - else - { - if(!name.empty()) i->second.second.insert(name); - if(!name2.empty()) i->second.second.insert(name2); - resno = i->second.first; - } - return resno; - } -} - -// Create silent 'nosound' instrument -size_t InsertNoSoundIns() -{ - // { 0x0F70700,0x0F70710, 0xFF,0xFF, 0x0,+0 }, - insdata tmp1 = { {0x00, 0x10, 0x07, 0x07, 0xF7, 0xF7, 0x00, 0x00, 0xFF, 0xFF, 0x00}, 0, 0 }; - struct ins tmp2 = { 0, 0, 0, false, 0.0 }; - return InsertIns(tmp1, tmp1, tmp2, "nosound"); -} diff --git a/src/gen_adldata/progs_cache.h b/src/gen_adldata/progs_cache.h deleted file mode 100644 index 007c3b4..0000000 --- a/src/gen_adldata/progs_cache.h +++ /dev/null @@ -1,85 +0,0 @@ -#ifndef PROGS_H -#define PROGS_H - -#include -#include -#include -#include -#include -#include -#include - -struct insdata -{ - uint8_t data[11]; - int8_t finetune; - bool diff; - bool operator==(const insdata &b) const - { - return std::memcmp(data, b.data, 11) == 0 && finetune == b.finetune && diff == b.diff; - } - bool operator< (const insdata &b) const - { - int c = std::memcmp(data, b.data, 11); - if(c != 0) return c < 0; - if(finetune != b.finetune) return finetune < b.finetune; - if(diff != b.diff) return (!diff) == (b.diff); - return 0; - } - bool operator!=(const insdata &b) const - { - return !operator==(b); - } -}; - -struct ins -{ - size_t insno1, insno2; - unsigned char notenum; - bool pseudo4op; - double voice2_fine_tune; - - bool operator==(const ins &b) const - { - return notenum == b.notenum - && insno1 == b.insno1 - && insno2 == b.insno2 - && pseudo4op == b.pseudo4op - && voice2_fine_tune == b.voice2_fine_tune; - } - bool operator< (const ins &b) const - { - if(insno1 != b.insno1) return insno1 < b.insno1; - if(insno2 != b.insno2) return insno2 < b.insno2; - if(notenum != b.notenum) return notenum < b.notenum; - if(pseudo4op != b.pseudo4op) return pseudo4op < b.pseudo4op; - if(voice2_fine_tune != b.voice2_fine_tune) return voice2_fine_tune < b.voice2_fine_tune; - return 0; - } - bool operator!=(const ins &b) const - { - return !operator==(b); - } -}; - -typedef std::map > > InstrumentDataTab; -extern InstrumentDataTab insdatatab; - -typedef std::map > > InstrumentsData; -extern InstrumentsData instab; - -typedef std::map > InstProgsData; -extern InstProgsData progs; - -extern std::vector banknames; - -//static std::map > Correlate; -//extern unsigned maxvalues[30]; - -void SetBank(unsigned bank, unsigned patch, size_t insno); - -size_t InsertIns(const insdata &id, const insdata &id2, ins &in, - const std::string &name, const std::string &name2 = ""); -size_t InsertNoSoundIns(); - -#endif // PROGS_H diff --git a/src/gen_adldata/scrapped.txt b/src/gen_adldata/scrapped.txt deleted file mode 100644 index 10c15cd..0000000 --- a/src/gen_adldata/scrapped.txt +++ /dev/null @@ -1,263 +0,0 @@ - -#ifdef HARD_BANKS -static const char *const banknames[] = -{ - // 0 - "AIL (Star Control 3, Albion, Empire 2, Sensible Soccer, Settlers 2, many others)", - "Bisqwit (selection of 4op and 2op)", - "HMI (Descent, Asterix)", //melodic,drum - "HMI (Descent:: Int)", //intmelo,intdrum - "HMI (Descent:: Ham)", //hammelo,hamdrum - "HMI (Descent:: Rick)", //rickmelo,rickdrum - "HMI (Descent 2)", //d2melo,d2drum - "HMI (Normality)", //normmelo,normdrum - "HMI (Shattered Steel)", //ssmelo,ssdrum - "HMI (Theme Park)", // file131, file132 - // 10 - "HMI (3d Table Sports, Battle Arena Toshinden)", //file133, file134 - "HMI (Aces of the Deep)", //file142, file143 - "HMI (Earthsiege)", //file144, file145 - "HMI (Anvil of Dawn)", //file167,file168 - "DMX (Doom :: partially pseudo 4op)", - "DMX (Hexen, Heretic :: partially pseudo 4op)", - "DMX (MUS Play :: partially pseudo 4op)", - "AIL (Discworld, Grandest Fleet, Pocahontas, Slob Zone 3d, Ultima 4, Zorro)", // file17 - "AIL (Warcraft 2)", - "AIL (Syndicate)", // file19 - // 20 - "AIL (Guilty, Orion Conspiracy, Terra Nova Strike Force Centauri :: 4op)", // file20 - "AIL (Magic Carpet 2)", // file21 - "AIL (Nemesis)", - "AIL (Jagged Alliance)", //file23 - "AIL (When Two Worlds War :: 4op, MISSING INSTRUMENTS)", //file24 - "AIL (Bards Tale Construction :: MISSING INSTRUMENTS)", //file25 - "AIL (Return to Zork)", //file26 - "AIL (Theme Hospital)", //file27 - "AIL (National Hockey League PA)", - "AIL (Inherit The Earth)", //file29 - // 30 - "AIL (Inherit The Earth, file two)", //file30 - "AIL (Little Big Adventure :: 4op)", //file31 - "AIL (Wreckin Crew)", //file32 - "AIL (Death Gate)", // file13 - "AIL (FIFA International Soccer)", //file34 - "AIL (Starship Invasion)", //file35 - "AIL (Super Street Fighter 2 :: 4op)", //file36 - "AIL (Lords of the Realm :: MISSING INSTRUMENTS)", //file37 - "AIL (SimFarm, SimHealth :: 4op)", - "AIL (SimFarm, Settlers, Serf City)", - // 40 - "AIL (Caesar 2 :: partially 4op, MISSING INSTRUMENTS)", // file12 - "AIL (Syndicate Wars)", //file41 - "AIL (Bubble Bobble Feat. Rainbow Islands, Z)", //file42 - "AIL (Warcraft)", //file47 - "AIL (Terra Nova Strike Force Centuri :: partially 4op)", //file48 - "AIL (System Shock :: partially 4op)", //file49 - "AIL (Advanced Civilization)", //file50 - "AIL (Battle Chess 4000 :: partially 4op, melodic only)", //file53 - "AIL (Ultimate Soccer Manager :: partially 4op)", //file54 - "AIL (Air Bucks, Blue And The Gray, America Invades, Terminator 2029)", // sample.ad - // 50 - "AIL (Ultima Underworld 2)", // sample.opl - "AIL (Kasparov's Gambit)", // file15 - "AIL (High Seas Trader :: MISSING INSTRUMENTS)", // file16 - "AIL (Master of Magic, Master of Orion 2 :: 4op, std percussion)", //file159 - "AIL (Master of Magic, Master of Orion 2 :: 4op, orchestral percussion)", //file159 - "SB (Action Soccer)", - "SB (3d Cyberpuck :: melodic only)", - "SB (Simon the Sorcerer :: melodic only)", - "OP3 (The Fat Man 2op set)", - "OP3 (The Fat Man 4op set)", - // 60 - "OP3 (JungleVision 2op set :: melodic only)", - "OP3 (Wallace 2op set, Nitemare 3D :: melodic only)", - "TMB (Duke Nukem 3D)", - "TMB (Shadow Warrior)", - "DMX (Raptor)", - "OP3 (Modded GMOPL by Wohlstand)", - "SB (Jammey O'Connel's bank)", - "TMB (Default bank of Build Engine)", - "OP3 (4op bank by James Alan Nguyen)", - "TMB (Blood)", - // 70 - "TMB (Lee)", - "TMB (Nam)", - "DMX (Bank by Sneakernets)" -}; - -const char *prev = ""; -const char *prev_prefix = ""; -size_t prev_index = 0; - -enum IniType -{ - INI_Both, - INI_Melodic, - INI_Drums -}; - -void writeIni(const char * format, const char * filepath, const char * prefix, size_t index, int type, const char*filter_mel = 0, const char *filter_perc = 0) -{ - if(type == INI_Both) - { - FILE *ini = fopen("banks.ini", "a"); - fprintf(ini, "[bank-%lu]\n", index); - fprintf(ini, "name = \"%s\"\n", banknames[index]); - fprintf(ini, "format = %s\n", format); - fprintf(ini, "file = \"%s\"\n", filepath); - fprintf(ini, "prefix = \"%s\"\n", prefix); - if(filter_mel) fprintf(ini, "filter-m = \"%s\"\n", filter_mel); - if(filter_perc) fprintf(ini, "filter-p = \"%s\"\n", filter_perc); - fprintf(ini, "\n"); - fclose(ini); - } - - if(type == INI_Drums) - { - FILE *ini = fopen("banks.ini", "a"); - fprintf(ini, "[bank-%lu]\n", index); - fprintf(ini, "name = \"%s\"\n", banknames[index]); - fprintf(ini, "format = %s\n", format); - fprintf(ini, "file = \"%s\"\n", prev); - fprintf(ini, "file-p = \"%s\"\n", filepath); - fprintf(ini, "prefix = \"%s\"\n", prev_prefix); - fprintf(ini, "prefix-p = \"%s\"\n", prefix); - fprintf(ini, "\n"); - fclose(ini); - } - - prev = filepath; - prev_prefix = prefix; - prev_index = index; -} -#endif - - - -#ifdef HARD_BANKS -LoadMiles("fm_banks/opl_files/sc3.opl", 0, "G"); // Our "standard" bank! Same as file22.opl - -LoadBisqwit("fm_banks/op3_files/bisqwit.adlraw", 1, "Bisq"); - -LoadBNK("fm_banks/bnk_files/melodic.bnk", 2, "HMIGM", false, false); // same as file156.bnk -LoadBNK("fm_banks/bnk_files/drum.bnk", 2, "HMIGP", false, true); - -LoadBNK("fm_banks/bnk_files/intmelo.bnk", 3, "intM", false, false); -LoadBNK("fm_banks/bnk_files/intdrum.bnk", 3, "intP", false, true); - -LoadBNK("fm_banks/bnk_files/hammelo.bnk", 4, "hamM", false, false); -LoadBNK("fm_banks/bnk_files/hamdrum.bnk", 4, "hamP", false, true); - -LoadBNK("fm_banks/bnk_files/rickmelo.bnk", 5, "rickM", false, false); -LoadBNK("fm_banks/bnk_files/rickdrum.bnk", 5, "rickP", false, true); - -LoadBNK("fm_banks/bnk_files/d2melo.bnk", 6, "b6M", false, false); -LoadBNK("fm_banks/bnk_files/d2drum.bnk", 6, "b6P", false, true); - -LoadBNK("fm_banks/bnk_files/normmelo.bnk", 7, "b7M", false, false); -LoadBNK("fm_banks/bnk_files/normdrum.bnk", 7, "b7P", false, true); // same as file122.bnk - -LoadBNK("fm_banks/bnk_files/ssmelo.bnk", 8, "b8M", false, false); -LoadBNK("fm_banks/bnk_files/ssdrum.bnk", 8, "b8P", false, true); - -LoadTMB("fm_banks/bnk_files/themepark.tmb", 9, "b9MP"); -//LoadBNK("fm_banks/bnk_files/file131.bnk", 9, "b9M", false, false); -//LoadBNK("fm_banks/bnk_files/file132.bnk", 9, "b9P", false, true); - -LoadBNK("fm_banks/bnk_files/file133.bnk", 10, "b10P", false, true); -LoadBNK("fm_banks/bnk_files/file134.bnk", 10, "b10M", false, false); - -LoadBNK("fm_banks/bnk_files/file142.bnk", 11, "b11P", false, true); -LoadBNK("fm_banks/bnk_files/file143.bnk", 11, "b11M", false, false); - -LoadBNK("fm_banks/bnk_files/file145.bnk", 12, "b12M", false, false);//file145 is MELODIC -LoadBNK("fm_banks/bnk_files/file144.bnk", 12, "b12P", false, true);//file144 is DRUMS - -LoadBNK("fm_banks/bnk_files/file167.bnk", 13, "b13P", false, true); -LoadBNK("fm_banks/bnk_files/file168.bnk", 13, "b13M", false, false); - -LoadDoom("fm_banks/doom2/genmidi.op2", 14, "dM"); -LoadDoom("fm_banks/doom2/genmidi.htc", 15, "hxM"); // same as genmidi.hxn -LoadDoom("fm_banks/doom2/default.op2", 16, "mus"); - -LoadMiles("fm_banks/opl_files/file17.opl", 17, "f17G"); -LoadMiles("fm_banks/opl_files/warcraft.ad", 18, "sG"); // same as file44, warcraft.opl -LoadMiles("fm_banks/opl_files/file19.opl", 19, "f19G"); -LoadMiles("fm_banks/opl_files/file20.opl", 20, "f20G"); -LoadMiles("fm_banks/opl_files/file21.opl", 21, "f21G"); -LoadMiles("fm_banks/opl_files/nemesis.opl", 22, "nem"); -LoadMiles("fm_banks/opl_files/file23.opl", 23, "f23G"); -LoadMiles("fm_banks/opl_files/file24.opl", 24, "f24G"); -LoadMiles("fm_banks/opl_files/file25.opl", 25, "f25G"); -LoadMiles("fm_banks/opl_files/file26.opl", 26, "f26G"); -LoadMiles("fm_banks/opl_files/file27.opl", 27, "f27G"); -LoadMiles("fm_banks/opl_files/nhlpa.opl", 28, "nhl"); -LoadMiles("fm_banks/opl_files/file29.opl", 29, "f29G"); -LoadMiles("fm_banks/opl_files/file30.opl", 30, "f30G"); -LoadMiles("fm_banks/opl_files/file31.opl", 31, "f31G"); -LoadMiles("fm_banks/opl_files/file32.opl", 32, "f32G"); -LoadMiles("fm_banks/opl_files/file13.opl", 33, "f13G"); -LoadMiles("fm_banks/opl_files/file34.opl", 34, "f34G"); -LoadMiles("fm_banks/opl_files/file35.opl", 35, "f35G"); -LoadMiles("fm_banks/opl_files/file36.opl", 36, "f36G"); -LoadMiles("fm_banks/opl_files/file37.opl", 37, "f37G"); -LoadMiles("fm_banks/opl_files/simfarm.opl", 38, "qG"); -LoadMiles("fm_banks/opl_files/simfarm.ad", 39, "mG"); // same as file18.opl -LoadMiles("fm_banks/opl_files/file12.opl", 40, "f12G"); -LoadMiles("fm_banks/opl_files/file41.opl", 41, "f41G"); -LoadMiles("fm_banks/opl_files/file42.opl", 42, "f42G"); -LoadMiles("fm_banks/opl_files/file47.opl", 43, "f47G"); -LoadMiles("fm_banks/opl_files/file48.opl", 44, "f48G"); -LoadMiles("fm_banks/opl_files/file49.opl", 45, "f49G"); -LoadMiles("fm_banks/opl_files/file50.opl", 46, "f50G"); -LoadMiles("fm_banks/opl_files/file53.opl", 47, "f53G"); -LoadBNK("fm_banks/bnk_files/file144.bnk", 47, "f53GD", false, true);//Attempt to append missing drums -LoadMiles("fm_banks/opl_files/file54.opl", 48, "f54G"); - -LoadMiles("fm_banks/opl_files/sample.ad", 49, "MG"); // same as file51.opl -LoadMiles("fm_banks/opl_files/sample.opl", 50, "oG"); // same as file40.opl -LoadMiles("fm_banks/opl_files/file15.opl", 51, "f15G"); -LoadMiles("fm_banks/opl_files/file16.opl", 52, "f16G"); - -LoadBNK2("fm_banks/bnk_files/file159.bnk", 53, "b50", "gm", "gps"); // fat-opl3 -LoadBNK2("fm_banks/bnk_files/file159.bnk", 54, "b51", "gm", "gpo"); - -LoadIBK("fm_banks/ibk_files/soccer-genmidi.ibk", 55, "b55M", false); -LoadIBK("fm_banks/ibk_files/soccer-percs.ibk", 55, "b55P", true); -LoadIBK("fm_banks/ibk_files/game.ibk", 56, "b56", false); -LoadIBK("fm_banks/ibk_files/mt_fm.ibk", 57, "b57", false); - -LoadJunglevision("fm_banks/op3_files/fat2.op3", 58, "fat2"); -LoadJunglevision("fm_banks/op3_files/fat4.op3", 59, "fat4"); -LoadJunglevision("fm_banks/op3_files/jv_2op.op3", 60, "b60"); -LoadJunglevision("fm_banks/op3_files/wallace.op3", 61, "b61"); - -LoadTMB("fm_banks/tmb_files/d3dtimbr.tmb", 62, "duke"); -LoadTMB("fm_banks/tmb_files/swtimbr.tmb", 63, "sw"); - -LoadDoom("fm_banks/raptor/genmidi.op2", 64, "rapt"); - -//LoadJunglevision("fm_banks/op3_files/fat2_modded.op3", 65, "b65M"); -LoadTMB("fm_banks/op3_files/gmopl_wohl_mod.tmb", 65, "b65"); - -//LoadIBK("fm_banks/ibk_files/JOconnel.IBK", 66, "b66M", false); -//LoadIBK("fm_banks/ibk_files/my-gmopldrums.IBK", 66, "b66P", true); -LoadTMB("fm_banks/op3_files/gmoconel.tmb", 66, "b66"); - -LoadTMB("fm_banks/tmb_files/default.tmb", 67, "3drm67"); -//LoadDoom("fm_banks/doom2/wolfinstein.op2", 67, "wolf"); //Small experiment! - -//LoadJunglevision("fm_banks/op3_files/2x2.op3", 68, "2x2byJAN"); -LoadMiles("fm_banks/op3_files/2x2.opl", 68, "2x2byJAN"); - -LoadTMB("fm_banks/tmb_files/bloodtmb.tmb", 69, "apgblood"); -LoadTMB("fm_banks/tmb_files/lee.tmb", 70, "apglee"); -LoadTMB("fm_banks/tmb_files/nam.tmb", 71, "apgnam"); - -LoadDoom("fm_banks/doom2/DMXOPL-by-sneakernets.op2", 72, "skeakernets"); - -//LoadBNK("bnk_files/grassman1.bnk", 63, "b63", false); -//LoadBNK("bnk_files/grassman2.bnk", 64, "b64", false); - -//LoadIBK("ibk_files/nitemare_3d.ibk", 65, "b65G", false); // Seems to be identical to wallace.op3 despite different format! -#endif diff --git a/src/midiplay/Makefile b/src/midiplay/Makefile deleted file mode 100644 index f2512b4..0000000 --- a/src/midiplay/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -all: midiplay - -midiplay: adlmidiplay.o wave_writer.o - g++ $^ -Wl,-rpath='$$ORIGIN' -L../../bin -ladlmidi -lSDL2 -o ../../bin/adlmidiplay - rm *.o - -adlmidiplay.o: adlmidiplay.cpp - g++ -c $^ -I.. -o adlmidiplay.o - -wave_writer.o: wave_writer.c - gcc -c $^ -I.. -o wave_writer.o - diff --git a/src/midiplay/Makefile.win32 b/src/midiplay/Makefile.win32 deleted file mode 100644 index 05e192f..0000000 --- a/src/midiplay/Makefile.win32 +++ /dev/null @@ -1,12 +0,0 @@ -all: midiplay - -midiplay: adlmidiplay.o wave_writer.o - g++ $^ -L../../bin -ladlmidi -lSDL2 -o ../../bin/adlmidiplay - rm *.o - -adlmidiplay.o: adlmidiplay.cpp - g++ -c $^ -I.. -o adlmidiplay.o - -wave_writer.o: wave_writer.c - gcc -c $^ -I.. -o wave_writer.o - diff --git a/src/midiplay/adlmidiplay.cpp b/src/midiplay/adlmidiplay.cpp deleted file mode 100644 index 7c8766d..0000000 --- a/src/midiplay/adlmidiplay.cpp +++ /dev/null @@ -1,338 +0,0 @@ - -#include -#include -#include -#include -#include -#include -#include -#define SDL_MAIN_HANDLED -#include - -#include - -#include "wave_writer.h" - -class MutexType -{ - SDL_mutex *mut; -public: - MutexType() : mut(SDL_CreateMutex()) { } - ~MutexType() - { - SDL_DestroyMutex(mut); - } - void Lock() - { - SDL_mutexP(mut); - } - void Unlock() - { - SDL_mutexV(mut); - } -}; - - -static std::deque AudioBuffer; -static MutexType AudioBuffer_lock; - -static void SDL_AudioCallbackX(void *, Uint8 *stream, int len) -{ - SDL_LockAudio(); - short *target = (short *) stream; - AudioBuffer_lock.Lock(); - /*if(len != AudioBuffer.size()) - fprintf(stderr, "len=%d stereo samples, AudioBuffer has %u stereo samples", - len/4, (unsigned) AudioBuffer.size()/2);*/ - unsigned ate = (unsigned)len / 2; // number of shorts - if(ate > AudioBuffer.size()) - ate = (unsigned)AudioBuffer.size(); - for(unsigned a = 0; a < ate; ++a) - { - target[a] = AudioBuffer[a]; - } - AudioBuffer.erase(AudioBuffer.begin(), AudioBuffer.begin() + ate); - AudioBuffer_lock.Unlock(); - SDL_UnlockAudio(); -} - -static bool is_number(const std::string &s) -{ - std::string::const_iterator it = s.begin(); - while(it != s.end() && std::isdigit(*it)) ++it; - return !s.empty() && it == s.end(); -} - -static void printError(const char *err) -{ - std::fprintf(stderr, "\nERROR: %s\n\n", err); - std::fflush(stderr); -} - -static int stop = 0; -static void sighandler(int dum) -{ - if((dum == SIGINT) - || (dum == SIGTERM) - #ifndef _WIN32 - || (dum == SIGHUP) - #endif - ) - stop = 1; -} - -int main(int argc, char **argv) -{ - if(argc < 2 || std::string(argv[1]) == "--help" || std::string(argv[1]) == "-h") - { - std::printf( - "Usage: adlmidi [ ] [ [ [ ] ] ]\n" - " -p Enables adlib percussion instrument mode\n" - " -t Enables tremolo amplification mode\n" - " -v Enables vibrato amplification mode\n" - " -s Enables scaling of modulator volumes\n" - " -nl Quit without looping\n" - " -w Write WAV file rather than playing\n" - "\n" - "Where - number of embeeded bank or filepath to custom WOPL bank file\n" - "\n" - "Note: To create WOPL bank files use OPL Bank Editor you can get here: \n" - "https://github.com/Wohlstand/OPL3BankEditor\n" - "\n" - ); - - int banksCount = adl_getBanksCount(); - const char *const *banknames = adl_getBankNames(); - - if(banksCount > 0) - { - std::printf(" Available embedded banks by number:\n\n"); - - for(int a = 0; a < banksCount; ++a) - std::printf("%10s%2u = %s\n", a ? "" : "Banks:", a, banknames[a]); - - std::printf( - "\n" - " Use banks 2-5 to play Descent \"q\" soundtracks.\n" - " Look up the relevant bank number from descent.sng.\n" - "\n" - " The fourth parameter can be used to specify the number\n" - " of four-op channels to use. Each four-op channel eats\n" - " the room of two regular channels. Use as many as required.\n" - " The Doom & Hexen sets require one or two, while\n" - " Miles four-op set requires the maximum of numcards*6.\n" - "\n" - ); - } - else - { - std::printf(" This build of libADLMIDI has no embedded banks!\n\n"); - } - - return 0; - } - - //const unsigned MaxSamplesAtTime = 512; // 512=dbopl limitation - // How long is SDL buffer, in seconds? - // The smaller the value, the more often SDL_AudioCallBack() - // is called. - const double AudioBufferLength = 0.08; - // How much do WE buffer, in seconds? The smaller the value, - // the more prone to sound chopping we are. - const double OurHeadRoomLength = 0.1; - // The lag between visual content and audio content equals - // the sum of these two buffers. - SDL_AudioSpec spec; - SDL_AudioSpec obtained; - - spec.freq = 44100; - spec.format = AUDIO_S16SYS; - spec.channels = 2; - spec.samples = Uint16((double)spec.freq * AudioBufferLength); - spec.callback = SDL_AudioCallbackX; - - ADL_MIDIPlayer *myDevice; - myDevice = adl_init(44100); - if(myDevice == NULL) - { - printError("Failed to init MIDI device!\n"); - return 1; - } - - bool recordWave = false; - - adl_setLoopEnabled(myDevice, 1); - - while(argc > 2) - { - bool had_option = false; - - if(!std::strcmp("-p", argv[2])) - adl_setPercMode(myDevice, 1); - else if(!std::strcmp("-v", argv[2])) - adl_setHVibrato(myDevice, 1); - else if(!std::strcmp("-w", argv[2])) - { - recordWave = true; - adl_setLoopEnabled(myDevice, 0);//Disable loop while record WAV - } - else if(!std::strcmp("-t", argv[2])) - adl_setHTremolo(myDevice, 1); - else if(!std::strcmp("-nl", argv[2])) - adl_setLoopEnabled(myDevice, 0); - else if(!std::strcmp("-s", argv[2])) - adl_setScaleModulators(myDevice, 1); - else break; - - std::copy(argv + (had_option ? 4 : 3), argv + argc, - argv + 2); - argc -= (had_option ? 2 : 1); - } - - if(!recordWave) - { - // Set up SDL - if(SDL_OpenAudio(&spec, &obtained) < 0) - { - std::fprintf(stderr, "\nERROR: Couldn't open audio: %s\n\n", SDL_GetError()); - std::fflush(stderr); - //return 1; - } - if(spec.samples != obtained.samples) - { - std::fprintf(stderr, "Wanted (samples=%u,rate=%u,channels=%u); obtained (samples=%u,rate=%u,channels=%u)\n", - spec.samples, spec.freq, spec.channels, - obtained.samples, obtained.freq, obtained.channels); - std::fflush(stderr); - } - } - - if(argc >= 3) - { - if(is_number(argv[2])) - { - int bankno = std::atoi(argv[2]); - if(adl_setBank(myDevice, bankno) != 0) - { - printError(adl_errorString()); - return 1; - } - } - else - { - std::fprintf(stdout, "Loading custom bank file %s...", argv[2]); - std::fflush(stdout); - if(adl_openBankFile(myDevice, argv[2]) != 0) - { - std::fprintf(stdout, "FAILED!\n"); - std::fflush(stdout); - printError(adl_errorString()); - return 1; - } - std::fprintf(stdout, "OK!\n"); - std::fflush(stdout); - } - } - - if(argc >= 4) - { - if(adl_setNumCards(myDevice, std::atoi(argv[3])) != 0) - { - printError(adl_errorString()); - return 1; - } - std::fprintf(stdout, "Number of cards %s\n", argv[3]); - } - else - { - // 4 chips by default - if(adl_setNumCards(myDevice, 4) != 0) - { - printError(adl_errorString()); - return 1; - } - } - - if(argc >= 5) - { - if(adl_setNumFourOpsChn(myDevice, std::atoi(argv[4])) != 0) - { - printError(adl_errorString()); - return 1; - } - std::fprintf(stdout, "Number of four-ops %s\n", argv[4]); - } - - if(adl_openFile(myDevice, argv[1]) != 0) - { - printError(adl_errorString()); - return 2; - } - - signal(SIGINT, sighandler); - signal(SIGTERM, sighandler); - #ifndef _WIN32 - signal(SIGHUP, sighandler); - #endif - - if(!recordWave) - { - SDL_PauseAudio(0); - - while(!stop) - { - short buff[4096]; - size_t got = (size_t)adl_play(myDevice, 4096, buff); - if(got <= 0) - break; - - AudioBuffer_lock.Lock(); - size_t pos = AudioBuffer.size(); - AudioBuffer.resize(pos + got); - for(size_t p = 0; p < got; ++p) - AudioBuffer[pos + p] = buff[p]; - AudioBuffer_lock.Unlock(); - - const SDL_AudioSpec &spec = obtained; - while(AudioBuffer.size() > spec.samples + (spec.freq * 2) * OurHeadRoomLength) - { - SDL_Delay(1); - } - } - - SDL_CloseAudio(); - } - else - { - std::string wave_out = std::string(argv[1]) + ".wav"; - std::fprintf(stdout, "Recording WAV file %s...\n", wave_out.c_str()); - std::fflush(stdout); - - if(wave_open(spec.freq, wave_out.c_str()) == 0) - { - wave_enable_stereo(); - while(!stop) - { - short buff[4096]; - size_t got = (size_t)adl_play(myDevice, 4096, buff); - if(got <= 0) - break; - wave_write(buff, (long)got); - } - wave_close(); - - std::fprintf(stdout, "Completed!\n"); - std::fflush(stdout); - } - else - { - adl_close(myDevice); - return 1; - } - } - - adl_close(myDevice); - - return 0; -} - diff --git a/src/midiplay/wave_writer.c b/src/midiplay/wave_writer.c deleted file mode 100755 index 0bfaf68..0000000 --- a/src/midiplay/wave_writer.c +++ /dev/null @@ -1,170 +0,0 @@ -/* snes_spc 0.9.0. http://www.slack.net/~ant/ */ - -#include "wave_writer.h" - -#include -#include -#include - -#ifdef _WIN32 -#include -#endif - -/* Copyright (C) 2003-2007 Shay Green. This module 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 -module 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 module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -enum { buf_size = 32768 * 2 }; -enum { header_size = 0x2C }; - -typedef short sample_t; - -static unsigned char* buf; -static FILE* file; -static long sample_count_; -static long sample_rate_; -static long buf_pos; -static int chan_count; - -static void exit_with_error( const char* str ) -{ - fprintf(stderr, "WAVE Writer Error: %s\n", str ); - fflush(stderr); -} - -int wave_open( long sample_rate, const char* filename ) -{ - sample_count_ = 0; - sample_rate_ = sample_rate; - buf_pos = header_size; - chan_count = 1; - - buf = (unsigned char*) malloc( buf_size * sizeof *buf ); - if ( !buf ) - { - exit_with_error( "Out of memory" ); - return -1; - } - -#ifndef _WIN32 - file = fopen( filename, "wb" ); -#else - wchar_t widePath[MAX_PATH]; - int size = MultiByteToWideChar(CP_UTF8, 0, filename, strlen(filename), widePath, MAX_PATH); - widePath[size] = '\0'; - file = _wfopen( widePath, L"wb" ); -#endif - if (!file) - { - exit_with_error( "Couldn't open WAVE file for writing" ); - return -1; - } - - setvbuf( file, 0, _IOFBF, 32 * 1024L ); - return 0; -} - -void wave_enable_stereo( void ) -{ - chan_count = 2; -} - -static void flush_() -{ - if ( buf_pos && !fwrite( buf, (size_t)buf_pos, 1, file ) ) - exit_with_error( "Couldn't write WAVE data" ); - buf_pos = 0; -} - -void wave_write( short const* in, long remain ) -{ - sample_count_ += remain; - while ( remain ) - { - if ( buf_pos >= buf_size ) - flush_(); - - { - unsigned char* p = &buf [buf_pos]; - long n = (buf_size - (unsigned long)buf_pos) / sizeof (sample_t); - if ( n > remain ) - n = remain; - remain -= n; - - /* convert to LSB first format */ - while ( n-- ) - { - int s = *in++; - *p++ = (unsigned char) s & (0x00FF); - *p++ = (unsigned char) (s >> 8) & (0x00FF); - } - - buf_pos = p - buf; - assert( buf_pos <= buf_size ); - } - } -} - -long wave_sample_count( void ) -{ - return sample_count_; -} - -static void set_le32( void* p, unsigned long n ) -{ - ((unsigned char*) p) [0] = (unsigned char) n & (0xFF); - ((unsigned char*) p) [1] = (unsigned char) (n >> 8) & (0xFF); - ((unsigned char*) p) [2] = (unsigned char) (n >> 16) & (0xFF); - ((unsigned char*) p) [3] = (unsigned char) (n >> 24) & (0xFF); -} - -void wave_close( void ) -{ - if ( file ) - { - /* generate header */ - unsigned char h [header_size] = - { - 'R','I','F','F', - 0,0,0,0, /* length of rest of file */ - 'W','A','V','E', - 'f','m','t',' ', - 0x10,0,0,0, /* size of fmt chunk */ - 1,0, /* uncompressed format */ - 0,0, /* channel count */ - 0,0,0,0, /* sample rate */ - 0,0,0,0, /* bytes per second */ - 0,0, /* bytes per sample frame */ - 16,0, /* bits per sample */ - 'd','a','t','a', - 0,0,0,0, /* size of sample data */ - /* ... */ /* sample data */ - }; - long ds = sample_count_ * (long)sizeof (sample_t); - int frame_size = chan_count * (long)sizeof (sample_t); - - set_le32( h + 0x04, header_size - 8 + ds ); - h [0x16] = (unsigned char)chan_count; - set_le32( h + 0x18, (unsigned long)sample_rate_ ); - set_le32( h + 0x1C, (unsigned long)sample_rate_ * (unsigned long)frame_size ); - h [0x20] = (unsigned char)frame_size; - set_le32( h + 0x28, (unsigned long)ds ); - - flush_(); - - /* write header */ - fseek( file, 0, SEEK_SET ); - fwrite( h, header_size, 1, file ); - fclose( file ); - file = 0; - free( buf ); - buf = 0; - } -} diff --git a/src/midiplay/wave_writer.h b/src/midiplay/wave_writer.h deleted file mode 100755 index 6d49718..0000000 --- a/src/midiplay/wave_writer.h +++ /dev/null @@ -1,21 +0,0 @@ -/* WAVE sound file writer for recording 16-bit output during program development */ - -#pragma once -#ifndef WAVE_WRITER_H -#define WAVE_WRITER_H - -#ifdef __cplusplus - extern "C" { -#endif - -int wave_open( long sample_rate, const char* filename ); -void wave_enable_stereo( void ); -void wave_write( short const* in, long count ); -long wave_sample_count( void ); -void wave_close( void ); - -#ifdef __cplusplus - } -#endif - -#endif diff --git a/src/test/adldatatest.cc b/src/test/adldatatest.cc deleted file mode 100644 index 9f992c0..0000000 --- a/src/test/adldatatest.cc +++ /dev/null @@ -1,2 +0,0 @@ -static const int adldata[2184] = { -1,1,1,129,1,1,1,1,12,7,23,152,24,21,69,3,113,114,112,35,97,36,97,33,2,3,35,3,3,35,35,9,33,49,49,49,1,33,49,49,49,49,113,33,241,2,2,16,33,161,161,33,49,161,113,144,33,33,33,49,33,97,161,33,49,49,49,49,33,49,49,50,225,225,161,49,225,98,98,98,34,33,34,33,33,162,32,33,119,97,97,113,33,161,33,161,58,33,6,34,65,97,97,164,2,17,17,147,4,33,49,32,5,7,5,24,16,17,1,14,6,14,14,213,53,14,38,0,16,16,2,0,0,0,0,12,0,12,0,12,0,0,14,0,14,14,14,2,78,17,14,128,14,6,1,1,1,1,1,0,3,3,14,14,215,215,128,128,6,6,6,1,65,10,10,14,14,5,2,1,0,0,1,1,1,65,1,1,22,1,129,17,1,129,1,1,129,129,49,48,177,177,177,177,33,161,65,17,33,33,33,33,33,132,162,49,49,50,33,33,49,49,33,33,49,35,225,1,1,17,162,33,97,97,114,97,114,65,33,33,97,33,33,34,33,33,97,97,97,97,33,33,50,33,225,225,33,33,161,161,161,161,33,33,33,161,34,97,96,33,161,177,97,114,162,33,97,33,81,33,1,97,66,163,161,97,7,19,17,145,1,34,33,33,3,2,1,18,0,16,16,192,3,208,192,218,20,208,228,0,17,17,17,0,1,0,0,18,0,18,0,18,0,0,208,0,7,208,7,5,158,16,208,16,7,2,2,1,2,2,0,0,12,12,0,3,199,199,17,17,21,18,18,2,66,30,30,0,7,4,21,2,0,0,143,75,73,18,87,147,128,146,92,151,33,98,35,145,89,73,146,20,68,147,19,72,19,19,156,84,95,135,71,74,74,161,30,18,141,91,139,139,139,18,21,22,73,77,64,26,29,65,155,152,147,24,91,144,87,0,146,148,148,67,155,138,134,77,143,142,145,142,75,144,129,144,31,70,156,139,76,203,153,147,89,14,70,69,139,158,26,143,165,31,23,93,151,28,137,21,206,21,91,146,77,148,140,76,133,12,6,145,79,73,133,4,106,21,157,150,134,65,142,0,128,0,0,149,92,0,0,0,68,68,7,0,2,0,0,0,0,0,0,0,0,0,0,0,8,0,10,3,0,69,0,0,8,11,0,81,84,89,0,128,128,133,64,64,220,220,0,0,63,63,63,88,69,64,124,64,10,5,63,79,0,0,6,0,0,0,0,0,14,0,0,128,0,0,0,0,128,128,0,0,0,0,128,0,0,137,128,0,0,128,0,5,0,128,0,0,0,0,64,8,0,0,0,0,0,128,0,128,128,0,1,0,0,0,131,0,0,0,1,5,0,0,0,6,131,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,64,0,128,0,128,0,0,0,0,3,0,0,0,0,131,0,128,128,0,3,128,0,0,0,0,0,129,128,0,0,0,3,3,0,0,136,5,0,64,8,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,74,10,93,10,0,8,0,13,74,0,0,0,0,0,0,0,8,0,8,0,0,0,0,9,0,0,0,0,8,78,82,8,64,64,0,0,0,0,242,242,242,242,241,241,161,194,246,243,84,243,246,246,211,117,246,199,170,151,151,152,145,113,243,243,241,246,249,145,149,32,148,241,241,81,161,162,244,241,221,221,209,113,241,245,245,245,177,127,193,193,244,116,84,84,133,117,118,158,97,117,114,84,147,147,147,147,170,126,117,155,133,136,117,132,102,118,87,119,255,255,134,102,146,223,239,241,83,168,145,84,33,161,17,17,248,33,116,177,241,17,17,243,210,163,246,212,250,124,221,218,241,236,103,250,168,248,241,31,248,248,246,55,178,246,255,243,248,248,249,252,255,252,246,246,246,246,246,246,246,246,246,246,248,245,228,180,246,248,246,255,248,245,250,250,250,250,249,249,248,248,118,200,173,168,246,245,0,0,0,103,248,224,224,122,228,249,0,250,246,0,242,242,242,242,242,242,242,194,243,242,244,242,231,246,163,181,241,199,138,85,85,70,97,97,243,241,242,243,246,132,148,209,195,241,241,113,242,161,241,241,86,102,97,114,111,133,243,242,114,63,79,79,138,113,122,165,143,143,130,98,127,116,113,166,114,114,130,114,143,139,97,114,101,101,117,101,101,85,86,118,255,255,100,150,145,111,143,244,160,37,85,106,66,49,66,207,134,65,165,242,242,17,29,129,242,162,242,235,194,111,86,143,195,248,223,248,250,243,243,31,86,52,31,86,244,79,18,246,243,243,248,250,255,250,246,251,246,123,246,203,246,246,159,246,244,159,245,151,159,243,159,255,244,245,200,250,248,248,250,246,246,246,119,155,141,136,103,70,247,247,247,117,117,255,255,123,85,214,247,248,246,0,244,244,244,247,247,247,242,248,244,242,244,246,246,246,243,245,20,88,24,35,4,42,6,6,148,154,58,34,84,65,25,79,6,40,232,40,154,22,232,40,19,19,28,18,33,117,117,5,37,3,18,34,21,57,5,99,23,23,21,23,106,31,85,60,2,3,3,15,22,23,25,33,95,95,31,88,86,70,7,7,3,15,85,18,42,5,1,41,148,17,52,1,67,119,51,71,246,35,149,129,81,81,49,115,83,17,65,50,86,32,51,5,229,38,53,40,7,71,6,0,36,0,0,163,97,0,1,240,119,119,255,5,7,5,12,8,12,8,12,2,12,12,0,12,66,48,228,4,0,55,0,3,66,12,191,135,141,136,10,137,136,136,79,73,5,4,6,5,244,244,244,231,72,240,240,74,228,50,243,141,12,0,247,247,246,247,247,247,245,248,245,241,244,246,247,246,243,245,7,8,8,20,4,26,7,7,200,231,248,248,58,25,25,248,166,24,120,72,223,223,120,24,38,6,12,6,22,53,244,195,8,7,5,5,5,103,5,69,9,9,55,44,10,15,24,28,11,9,9,15,10,12,25,23,26,26,10,26,38,54,7,7,15,15,24,10,42,7,6,9,5,3,22,3,53,71,37,7,2,19,114,38,245,19,3,35,246,229,230,17,5,12,22,11,229,22,5,229,3,3,2,255,132,4,2,55,21,245,22,201,6,6,255,23,8,23,6,71,6,71,6,67,6,6,2,6,228,2,229,247,2,5,2,20,228,8,151,183,184,182,6,108,182,182,24,105,5,4,23,22,245,245,245,7,5,5,2,27,57,165,245,181,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,1,1,1,0,1,1,0,1,0,1,1,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,0,0,1,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,2,1,0,0,1,0,0,0,0,0,0,0,0,1,0,1,0,1,0,0,1,1,0,1,0,1,1,0,0,0,1,2,0,0,0,0,0,2,2,0,0,0,0,0,2,0,0,0,2,2,0,2,0,2,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,2,0,3,0,0,0,0,0,0,3,3,3,3,0,0,3,3,3,2,0,3,0,0,0,3,3,0,3,3,3,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,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,2,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,2,1,0,1,0,0,0,0,0,0,0,0,0,3,2,3,3,0,0,3,1,2,0,0,0,0,0,0,0,2,0,2,0,2,0,0,3,0,3,0,1,0,3,0,3,0,3,0,0,0,0,0,0,0,0,0,2,2,0,0,3,3,0,0,0,0,0,0,0,2,1,0,0,0,0,0,8,8,8,6,0,0,8,10,0,2,2,0,0,4,12,4,2,2,4,4,0,12,10,6,12,12,0,6,0,8,8,8,2,10,10,12,8,8,10,10,8,8,8,2,2,0,0,2,14,0,10,12,0,0,12,8,12,12,12,2,2,8,0,8,8,8,10,10,8,6,0,4,0,0,2,0,0,0,11,11,0,0,0,0,0,2,0,10,2,10,12,0,8,0,10,0,2,0,0,12,0,6,6,4,0,0,4,8,12,6,10,6,6,10,8,10,6,4,14,14,14,14,14,0,10,14,14,14,8,8,8,14,0,14,4,10,4,10,4,10,4,4,14,4,14,14,6,14,14,8,14,12,14,6,7,6,6,6,14,14,15,15,14,14,14,14,14,14,1,0,1,0,0,8,8,14,6,14,8,7,4,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,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,0,0,0,35,35,52,48,58,60,47,43,49,43,51,43,54,57,72,60,76,84,36,65,84,83,84,24,77,60,65,59,51,45,71,60,58,53,64,71,61,61,44,40,69,68,63,74,60,80,64,72,73,70,68,48,53,0}; diff --git a/src/test/test.cc b/src/test/test.cc deleted file mode 100644 index ff8515b..0000000 --- a/src/test/test.cc +++ /dev/null @@ -1,202 +0,0 @@ -#include -static const unsigned char adl[182][12] = -{ -// The data bytes are: -// [0,1] AM/VIB/EG/KSR/Multiple bits for carrier and modulator respectively -// [2,3] KSL/Attenuation settings for carrier and modulator respectively -// [4,5] Attack and decay rates for carrier and modulator respectively -// [6,7] Sustain and release rates for carrier and modulator respectively -// [8,9] Wave select settings for carrier and modulator respectively -// [10] Feedback/connection bits for the channel (also stereo/pan bits) -// [11] For percussive instruments (GP35..GP87), the tone to play - { 1, 1,143, 6,242,242,244,247,0,0, 56, 0}, // GM1:AcouGrandPiano - { 1, 1, 75, 0,242,242,244,247,0,0, 56, 0}, // GM2:BrightAcouGrand - { 1, 1, 73, 0,242,242,244,246,0,0, 56, 0}, // GM3:ElecGrandPiano - { 129, 65, 18, 0,242,242,247,247,0,0, 54, 0}, // GM4:Honky-tonkPiano - { 1, 1, 87, 0,241,242,247,247,0,0, 48, 0}, // GM5:Rhodes Piano - { 1, 1,147, 0,241,242,247,247,0,0, 48, 0}, // GM6:Chorused Piano - { 1, 22,128, 14,161,242,242,245,0,0, 56, 0}, // GM7:Harpsichord - { 1, 1,146, 0,194,194,248,248,0,0, 58, 0}, // GM8:Clavinet - { 12,129, 92, 0,246,243,244,245,0,0, 48, 0}, // GM9:Celesta - { 7, 17,151,128,243,242,242,241,0,0, 50, 0}, // GM10:Glockenspiel - { 23, 1, 33, 0, 84,244,244,244,0,0, 50, 0}, // GM11:Music box - { 152,129, 98, 0,243,242,246,246,0,0, 48, 0}, // GM12:Vibraphone - { 24, 1, 35, 0,246,231,246,247,0,0, 48, 0}, // GM13:Marimba - { 21, 1,145, 0,246,246,246,246,0,0, 52, 0}, // GM14:Xylophone - { 69,129, 89,128,211,163,243,243,0,0, 60, 0}, // GM15:Tubular Bells - { 3,129, 73,128,117,181,245,245,1,0, 52, 0}, // GM16:Dulcimer - { 113, 49,146, 0,246,241, 20, 7,0,0, 50, 0}, // GM17:Hammond Organ - { 114, 48, 20, 0,199,199, 88, 8,0,0, 50, 0}, // GM18:Percussive Organ - { 112,177, 68, 0,170,138, 24, 8,0,0, 52, 0}, // GM19:Rock Organ - { 35,177,147, 0,151, 85, 35, 20,1,0, 52, 0}, // GM20:Church Organ - { 97,177, 19,128,151, 85, 4, 4,1,0, 48, 0}, // GM21:Reed Organ - { 36,177, 72, 0,152, 70, 42, 26,1,0, 60, 0}, // GM22:Accordion - { 97, 33, 19, 0,145, 97, 6, 7,1,0, 58, 0}, // GM23:Harmonica - { 33,161, 19,137,113, 97, 6, 7,0,0, 54, 0}, // GM24:Tango Accordion - { 2, 65,156,128,243,243,148,200,1,0, 60, 0}, // GM25:Acoustic Guitar1 - { 3, 17, 84, 0,243,241,154,231,1,0, 60, 0}, // GM26:Acoustic Guitar2 - { 35, 33, 95, 0,241,242, 58,248,0,0, 48, 0}, // GM27:Electric Guitar1 - { 3, 33,135,128,246,243, 34,248,1,0, 54, 0}, // GM28:Electric Guitar2 - { 3, 33, 71, 0,249,246, 84, 58,0,0, 48, 0}, // GM29:Electric Guitar3 - { 35, 33, 74, 5,145,132, 65, 25,1,0, 56, 0}, // GM30:Overdrive Guitar - { 35, 33, 74, 0,149,148, 25, 25,1,0, 56, 0}, // GM31:Distorton Guitar - { 9,132,161,128, 32,209, 79,248,0,0, 56, 0}, // GM32:Guitar Harmonics - { 33,162, 30, 0,148,195, 6,166,0,0, 50, 0}, // GM33:Acoustic Bass - { 49, 49, 18, 0,241,241, 40, 24,0,0, 58, 0}, // GM34:Electric Bass 1 - { 49, 49,141, 0,241,241,232,120,0,0, 58, 0}, // GM35:Electric Bass 2 - { 49, 50, 91, 0, 81,113, 40, 72,0,0, 60, 0}, // GM36:Fretless Bass - { 1, 33,139, 64,161,242,154,223,0,0, 56, 0}, // GM37:Slap Bass 1 - { 33, 33,139, 8,162,161, 22,223,0,0, 56, 0}, // GM38:Slap Bass 2 - { 49, 49,139, 0,244,241,232,120,0,0, 58, 0}, // GM39:Synth Bass 1 - { 49, 49, 18, 0,241,241, 40, 24,0,0, 58, 0}, // GM40:Synth Bass 2 - { 49, 33, 21, 0,221, 86, 19, 38,1,0, 56, 0}, // GM41:Violin - { 49, 33, 22, 0,221,102, 19, 6,1,0, 56, 0}, // GM42:Viola - { 113, 49, 73, 0,209, 97, 28, 12,1,0, 56, 0}, // GM43:Cello - { 33, 35, 77,128,113,114, 18, 6,1,0, 50, 0}, // GM44:Contrabass - { 241,225, 64, 0,241,111, 33, 22,1,0, 50, 0}, // GM45:Tremulo Strings - { 2, 1, 26,128,245,133,117, 53,1,0, 48, 0}, // GM46:Pizzicato String - { 2, 1, 29,128,245,243,117,244,1,0, 48, 0}, // GM47:Orchestral Harp - { 16, 17, 65, 0,245,242, 5,195,1,0, 50, 0}, // GM48:Timpany - { 33,162,155, 1,177,114, 37, 8,1,0, 62, 0}, // GM49:String Ensemble1 - { 161, 33,152, 0,127, 63, 3, 7,1,1, 48, 0}, // GM50:String Ensemble2 - { 161, 97,147, 0,193, 79, 18, 5,0,0, 58, 0}, // GM51:Synth Strings 1 - { 33, 97, 24, 0,193, 79, 34, 5,0,0, 60, 0}, // GM52:SynthStrings 2 - { 49,114, 91,131,244,138, 21, 5,0,0, 48, 0}, // GM53:Choir Aahs - { 161, 97,144, 0,116,113, 57,103,0,0, 48, 0}, // GM54:Voice Oohs - { 113,114, 87, 0, 84,122, 5, 5,0,0, 60, 0}, // GM55:Synth Voice - { 144, 65, 0, 0, 84,165, 99, 69,0,0, 56, 0}, // GM56:Orchestra Hit - { 33, 33,146, 1,133,143, 23, 9,0,0, 60, 0}, // GM57:Trumpet - { 33, 33,148, 5,117,143, 23, 9,0,0, 60, 0}, // GM58:Trombone - { 33, 97,148, 0,118,130, 21, 55,0,0, 60, 0}, // GM59:Tuba - { 49, 33, 67, 0,158, 98, 23, 44,1,1, 50, 0}, // GM60:Muted Trumpet - { 33, 33,155, 0, 97,127,106, 10,0,0, 50, 0}, // GM61:French Horn - { 97, 34,138, 6,117,116, 31, 15,0,0, 56, 0}, // GM62:Brass Section - { 161, 33,134,131,114,113, 85, 24,1,0, 48, 0}, // GM63:Synth Brass 1 - { 33, 33, 77, 0, 84,166, 60, 28,0,0, 56, 0}, // GM64:Synth Brass 2 - { 49, 97,143, 0,147,114, 2, 11,1,0, 56, 0}, // GM65:Soprano Sax - { 49, 97,142, 0,147,114, 3, 9,1,0, 56, 0}, // GM66:Alto Sax - { 49, 97,145, 0,147,130, 3, 9,1,0, 58, 0}, // GM67:Tenor Sax - { 49, 97,142, 0,147,114, 15, 15,1,0, 58, 0}, // GM68:Baritone Sax - { 33, 33, 75, 0,170,143, 22, 10,1,0, 56, 0}, // GM69:Oboe - { 49, 33,144, 0,126,139, 23, 12,1,1, 54, 0}, // GM70:English Horn - { 49, 50,129, 0,117, 97, 25, 25,1,0, 48, 0}, // GM71:Bassoon - { 50, 33,144, 0,155,114, 33, 23,0,0, 52, 0}, // GM72:Clarinet - { 225,225, 31, 0,133,101, 95, 26,0,0, 48, 0}, // GM73:Piccolo - { 225,225, 70, 0,136,101, 95, 26,0,0, 48, 0}, // GM74:Flute - { 161, 33,156, 0,117,117, 31, 10,0,0, 50, 0}, // GM75:Recorder - { 49, 33,139, 0,132,101, 88, 26,0,0, 48, 0}, // GM76:Pan Flute - { 225,161, 76, 0,102,101, 86, 38,0,0, 48, 0}, // GM77:Bottle Blow - { 98,161,203, 0,118, 85, 70, 54,0,0, 48, 0}, // GM78:Shakuhachi - { 98,161,153, 0, 87, 86, 7, 7,0,0, 59, 0}, // GM79:Whistle - { 98,161,147, 0,119,118, 7, 7,0,0, 59, 0}, // GM80:Ocarina - { 34, 33, 89, 0,255,255, 3, 15,2,0, 48, 0}, // GM81:Lead 1 squareea - { 33, 33, 14, 0,255,255, 15, 15,1,1, 48, 0}, // GM82:Lead 2 sawtooth - { 34, 33, 70,128,134,100, 85, 24,0,0, 48, 0}, // GM83:Lead 3 calliope - { 33,161, 69, 0,102,150, 18, 10,0,0, 48, 0}, // GM84:Lead 4 chiff - { 33, 34,139, 0,146,145, 42, 42,1,0, 48, 0}, // GM85:Lead 5 charang - { 162, 97,158, 64,223,111, 5, 7,0,0, 50, 0}, // GM86:Lead 6 voice - { 32, 96, 26, 0,239,143, 1, 6,0,2, 48, 0}, // GM87:Lead 7 fifths - { 33, 33,143,128,241,244, 41, 9,0,0, 58, 0}, // GM88:Lead 8 brass - { 119,161,165, 0, 83,160,148, 5,0,0, 50, 0}, // GM89:Pad 1 new age - { 97,177, 31,128,168, 37, 17, 3,0,0, 58, 0}, // GM90:Pad 2 warm - { 97, 97, 23, 0,145, 85, 52, 22,0,0, 60, 0}, // GM91:Pad 3 polysynth - { 113,114, 93, 0, 84,106, 1, 3,0,0, 48, 0}, // GM92:Pad 4 choir - { 33,162,151, 0, 33, 66, 67, 53,0,0, 56, 0}, // GM93:Pad 5 bowedpad - { 161, 33, 28, 0,161, 49,119, 71,1,1, 48, 0}, // GM94:Pad 6 metallic - { 33, 97,137, 3, 17, 66, 51, 37,0,0, 58, 0}, // GM95:Pad 7 halo - { 161, 33, 21, 0, 17,207, 71, 7,1,0, 48, 0}, // GM96:Pad 8 sweep - { 58, 81,206, 0,248,134,246, 2,0,0, 50, 0}, // GM97:FX 1 rain - { 33, 33, 21, 0, 33, 65, 35, 19,1,0, 48, 0}, // GM98:FX 2 soundtrack - { 6, 1, 91, 0,116,165,149,114,0,0, 48, 0}, // GM99:FX 3 crystal - { 34, 97,146,131,177,242,129, 38,0,0, 60, 0}, // GM100:FX 4 atmosphere - { 65, 66, 77, 0,241,242, 81,245,1,0, 48, 0}, // GM101:FX 5 brightness - { 97,163,148,128, 17, 17, 81, 19,1,0, 54, 0}, // GM102:FX 6 goblins - { 97,161,140,128, 17, 29, 49, 3,0,0, 54, 0}, // GM103:FX 7 echoes - { 164, 97, 76, 0,243,129,115, 35,1,0, 52, 0}, // GM104:FX 8 sci-fi - { 2, 7,133, 3,210,242, 83,246,0,1, 48, 0}, // GM105:Sitar - { 17, 19, 12,128,163,162, 17,229,1,0, 48, 0}, // GM106:Banjo - { 17, 17, 6, 0,246,242, 65,230,1,2, 52, 0}, // GM107:Shamisen - { 147,145,145, 0,212,235, 50, 17,0,1, 56, 0}, // GM108:Koto - { 4, 1, 79, 0,250,194, 86, 5,0,0, 60, 0}, // GM109:Kalimba - { 33, 34, 73, 0,124,111, 32, 12,0,1, 54, 0}, // GM110:Bagpipe - { 49, 33,133, 0,221, 86, 51, 22,1,0, 58, 0}, // GM111:Fiddle - { 32, 33, 4,129,218,143, 5, 11,2,0, 54, 0}, // GM112:Shanai - { 5, 3,106,128,241,195,229,229,0,0, 54, 0}, // GM113:Tinkle Bell - { 7, 2, 21, 0,236,248, 38, 22,0,0, 58, 0}, // GM114:Agogo Bells - { 5, 1,157, 0,103,223, 53, 5,0,0, 56, 0}, // GM115:Steel Drums - { 24, 18,150, 0,250,248, 40,229,0,0, 58, 0}, // GM116:Woodblock - { 16, 0,134, 3,168,250, 7, 3,0,0, 54, 0}, // GM117:Taiko Drum - { 17, 16, 65, 3,248,243, 71, 3,2,0, 52, 0}, // GM118:Melodic Tom - { 1, 16,142, 0,241,243, 6, 2,2,0, 62, 0}, // GM119:Synth Drum - { 14,192, 0, 0, 31, 31, 0,255,0,3, 62, 0}, // GM120:Reverse Cymbal - { 6, 3,128,136,248, 86, 36,132,0,2, 62, 0}, // GM121:Guitar FretNoise - { 14,208, 0, 5,248, 52, 0, 4,0,3, 62, 0}, // GM122:Breath Noise - { 14,192, 0, 0,246, 31, 0, 2,0,3, 62, 0}, // GM123:Seashore - { 213,218,149, 64, 55, 86,163, 55,0,0, 48, 0}, // GM124:Bird Tweet - { 53, 20, 92, 8,178,244, 97, 21,2,0, 58, 0}, // GM125:Telephone - { 14,208, 0, 0,246, 79, 0,245,0,3, 62, 0}, // GM126:Helicopter - { 38,228, 0, 0,255, 18, 1, 22,0,1, 62, 0}, // GM127:Applause/Noise - { 0, 0, 0, 0,243,246,240,201,0,2, 62, 0}, // GM128:Gunshot - { 16, 17, 68, 0,248,243,119, 6,2,0, 56, 35}, // GP35:Ac Bass Drum - { 16, 17, 68, 0,248,243,119, 6,2,0, 56, 35}, // GP36:Bass Drum 1 - { 2, 17, 7, 0,249,248,255,255,0,0, 56, 52}, // GP37:Side Stick - { 0, 0, 0, 0,252,250, 5, 23,2,0, 62, 48}, // GP38:Acoustic Snare - { 0, 1, 2, 0,255,255, 7, 8,0,0, 48, 58}, // GP39:Hand Clap - { 0, 0, 0, 0,252,250, 5, 23,2,0, 62, 60}, // GP40:Electric Snare - { 0, 0, 0, 0,246,246, 12, 6,0,0, 52, 47}, // GP41:Low Floor Tom - { 12, 18, 0, 0,246,251, 8, 71,0,2, 58, 43}, // GP42:Closed High Hat - { 0, 0, 0, 0,246,246, 12, 6,0,0, 52, 49}, // GP43:High Floor Tom - { 12, 18, 0, 5,246,123, 8, 71,0,2, 58, 43}, // GP44:Pedal High Hat - { 0, 0, 0, 0,246,246, 12, 6,0,0, 52, 51}, // GP45:Low Tom - { 12, 18, 0, 0,246,203, 2, 67,0,2, 58, 43}, // GP46:Open High Hat - { 0, 0, 0, 0,246,246, 12, 6,0,0, 52, 54}, // GP47:Low-Mid Tom - { 0, 0, 0, 0,246,246, 12, 6,0,0, 52, 57}, // GP48:High-Mid Tom - { 14,208, 0, 0,246,159, 0, 2,0,3, 62, 72}, // GP49:Crash Cymbal 1 - { 0, 0, 0, 0,246,246, 12, 6,0,0, 52, 60}, // GP50:High Tom - { 14, 7, 8, 74,248,244, 66,228,0,3, 62, 76}, // GP51:Ride Cymbal 1 - { 14,208, 0, 10,245,159, 48, 2,0,0, 62, 84}, // GP52:Chinese Cymbal - { 14, 7, 10, 93,228,245,228,229,3,1, 54, 36}, // GP53:Ride Bell - { 2, 5, 3, 10,180,151, 4,247,0,0, 62, 65}, // GP54:Tambourine - { 78,158, 0, 0,246,159, 0, 2,0,3, 62, 84}, // GP55:Splash Cymbal - { 17, 16, 69, 8,248,243, 55, 5,2,0, 56, 83}, // GP56:Cow Bell - { 14,208, 0, 0,246,159, 0, 2,0,3, 62, 84}, // GP57:Crash Cymbal 2 - { 128, 16, 0, 13,255,255, 3, 20,3,0, 60, 24}, // GP58:Vibraslap - { 14, 7, 8, 74,248,244, 66,228,0,3, 62, 77}, // GP59:Ride Cymbal 2 - { 6, 2, 11, 0,245,245, 12, 8,0,0, 54, 60}, // GP60:High Bongo - { 1, 2, 0, 0,250,200,191,151,0,0, 55, 65}, // GP61:Low Bongo - { 1, 1, 81, 0,250,250,135,183,0,0, 54, 59}, // GP62:Mute High Conga - { 1, 2, 84, 0,250,248,141,184,0,0, 54, 51}, // GP63:Open High Conga - { 1, 2, 89, 0,250,248,136,182,0,0, 54, 45}, // GP64:Low Conga - { 1, 0, 0, 0,249,250, 10, 6,3,0, 62, 71}, // GP65:High Timbale - { 0, 0,128, 0,249,246,137,108,3,0, 62, 60}, // GP66:Low Timbale - { 3, 12,128, 8,248,246,136,182,3,0, 63, 58}, // GP67:High Agogo - { 3, 12,133, 0,248,246,136,182,3,0, 63, 53}, // GP68:Low Agogo - { 14, 0, 64, 8,118,119, 79, 24,0,2, 62, 64}, // GP69:Cabasa - { 14, 3, 64, 0,200,155, 73,105,0,2, 62, 71}, // GP70:Maracas - { 215,199,220, 0,173,141, 5, 5,3,0, 62, 61}, // GP71:Short Whistle - { 215,199,220, 0,168,136, 4, 4,3,0, 62, 61}, // GP72:Long Whistle - { 128, 17, 0, 0,246,103, 6, 23,3,3, 62, 44}, // GP73:Short Guiro - { 128, 17, 0, 9,245, 70, 5, 22,2,3, 62, 40}, // GP74:Long Guiro - { 6, 21, 63, 0, 0,247,244,245,0,0, 49, 69}, // GP75:Claves - { 6, 18, 63, 0, 0,247,244,245,3,0, 48, 68}, // GP76:High Wood Block - { 6, 18, 63, 0, 0,247,244,245,0,0, 49, 63}, // GP77:Low Wood Block - { 1, 2, 88, 0,103,117,231, 7,0,0, 48, 74}, // GP78:Mute Cuica - { 65, 66, 69, 8,248,117, 72, 5,0,0, 48, 60}, // GP79:Open Cuica - { 10, 30, 64, 78,224,255,240, 5,3,0, 56, 80}, // GP80:Mute Triangle - { 10, 30,124, 82,224,255,240, 2,3,0, 56, 64}, // GP81:Open Triangle - { 14, 0, 64, 8,122,123, 74, 27,0,2, 62, 72}, // GP82 - { 14, 7, 10, 64,228, 85,228, 57,3,1, 54, 73}, // GP83 - { 5, 4, 5, 64,249,214, 50,165,3,0, 62, 70}, // GP84 - { 2, 21, 63, 0, 0,247,243,245,3,0, 56, 68}, // GP85 - { 1, 2, 79, 0,250,248,141,181,0,0, 55, 48}, // GP86 - { 0, 0, 0, 0,246,246, 12, 6,0,0, 52, 53} // GP87 (low-low-mid tom?) -}; -int main() -{ - printf("static const int adldata[2184] = {\n"); - for(unsigned x=0; x<12; ++x) - for(unsigned i=0; i<182; ++i) - printf(",%d", - (x==10 ? adl[i][x]&~0x30 : adl[i][x])); - printf("};\n"); -} diff --git a/test.wopl b/test.wopl new file mode 100644 index 0000000..f2573e1 Binary files /dev/null and b/test.wopl differ diff --git a/utils/dumpbank/dumpbank.cpp b/utils/dumpbank/dumpbank.cpp new file mode 100644 index 0000000..6996681 --- /dev/null +++ b/utils/dumpbank/dumpbank.cpp @@ -0,0 +1,179 @@ +//#ifdef __MINGW32__ +//typedef struct vswprintf {} swprintf; +//#endif +#include +#include +#include + +struct BNK1_header +{ + char maj_vers, min_vers; + char signature[6]; // "ADLIB-" + unsigned short ins_used, ins_entries; + unsigned name_list, inst_data; +} __attribute__((packed)); +struct BNK1_record +{ + unsigned short index; + unsigned char used; + char name[9]; +} __attribute__((packed)); +struct OPL2_op +{ + unsigned char key_scale_lvl; + unsigned char freq_mult; + unsigned char feedback; + unsigned char attack; + unsigned char sustain_lvl; + unsigned char sustain_sound; + unsigned char decay; + unsigned char release; + unsigned char out_lvl; + unsigned char amp_vib; + unsigned char pitch_vib; + unsigned char env_scaling; + unsigned char connection; +} __attribute__((packed)); +struct BNK1_instrument +{ + unsigned char sound_mode; + unsigned char voice_num; + OPL2_op ops[2]; + unsigned char waveforms[2]; +} __attribute__((packed)); // conventional Ad Lib instrument maker bankfile patch + +struct BNK2_header +{ + char signature[28]; // "Accomp. Bank, (C) AdLib Inc" + unsigned short file_ver; + char filler[10]; + unsigned short ins_entries, ins_used; + int lostSpace; +} __attribute__((packed)); +struct BNK2_record +{ + char O3_sig[3]; + char key[12]; + char used; + int attrib, dataOffset; + unsigned short blockSize, allocBSize; +} __attribute__((packed)); +struct OPL3_op +{ + unsigned char AVEKMMMM, KKLLLLLL; + unsigned char AAAADDDD, SSSSRRRR; + unsigned char DxxxxWWW, xxxxxxxx; +} __attribute__((packed)); +struct BNK2_instrument +{ + OPL3_op ops[4]; + unsigned char C4xxxFFFC; + unsigned char xxP24NNN; + unsigned char TTTTTTTT; + unsigned char xxxxxxxx; +} __attribute__((packed)); // Ad Lib Gold instrument maker bankfile patch + +static void LoadBNK1(const std::vector& data) +{ + const BNK1_header& bnk1 = *(const BNK1_header*) &data[0]; + const BNK1_record* names = (const BNK1_record*) &data[ bnk1.name_list ]; + const BNK1_instrument* ins = (const BNK1_instrument*) &data[ bnk1.inst_data ]; + std::printf("BNK1 version: %d.%d\n", bnk1.maj_vers, bnk1.min_vers); + for(unsigned a=0; a& data) +{ + const BNK2_header& bnk2 = *(const BNK2_header*) &data[0]; + const BNK2_record* names = (const BNK2_record*) &data[ sizeof(bnk2) ]; + std::printf("BNK2 version: %d, lost space %d\n", bnk2.file_ver, bnk2.lostSpace); + for(unsigned a=0; a data(ftell(fp)); + std::rewind(fp); + size_t got = std::fread(&data[0], 1, data.size(), fp); + std::fclose(fp); + + if(got == 0) + { + std::fprintf(stderr, "ERROR: Can't read %s file!", fn); + return; + } + + const BNK1_header& bnk1 = *(const BNK1_header*) &data[0]; + const BNK2_header& bnk2 = *(const BNK2_header*) &data[0]; + + if(std::memcmp(bnk1.signature, "ADLIB-", 6) == 0) + LoadBNK1(data); + else if(std::memcmp(bnk2.signature, "Accomp. Bank, (C) AdLib Inc", 28) == 0) + LoadBNK2(data); + else + std::fprintf(stderr, "%s: Unknown format\n", fn); +} + +int main(int argc, const char* const* argv) +{ + LoadBNK(argv[1]); +} diff --git a/utils/dumpmiles/dumpmiles.cpp b/utils/dumpmiles/dumpmiles.cpp new file mode 100644 index 0000000..832da93 --- /dev/null +++ b/utils/dumpmiles/dumpmiles.cpp @@ -0,0 +1,52 @@ +//#ifdef __MINGW32__ +//typedef struct vswprintf {} swprintf; +//#endif +#include +#include + +static void LoadMiles(const char* fn) +{ + FILE* fp = fopen(fn, "rb"); + if(!fp) + { + std::fprintf(stderr, "ERROR: Can't open %s file!", fn); + return; + } + + std::fseek(fp, 0, SEEK_END); + std::vector data(ftell(fp)); + std::rewind(fp); + size_t got = std::fread(&data[0], 1, data.size(), fp); + std::fclose(fp); + + if(got == 0) + { + std::fprintf(stderr, "ERROR: Can't read %s file!", fn); + return; + } + + for(unsigned a=0; a<500; ++a) + { + unsigned gmnumber = data[a*6+0]; + unsigned gmnumber2 = data[a*6+1]; + unsigned offset = *(unsigned*)&data[a*6+2]; + + if(gmnumber == 0xFF) break; + int gmno = gmnumber2==0x7F ? gmnumber+0x80 : gmnumber; + unsigned length = data[offset] + data[offset+1]*256; + signed char notenum = data[offset+2]; + + std::printf("%02X %02X ", gmnumber,gmnumber2); //, offset); + for(unsigned b=0; b 3 && (b-3)%11 == 0) printf("\n "); + std::printf("%02X ", data[offset+b]); + } + std::printf("\n"); + } +} + +int main(int argc, const char* const* argv) +{ + LoadMiles(argv[1]); +} diff --git a/utils/gen_adldata/file_formats/common.h b/utils/gen_adldata/file_formats/common.h new file mode 100644 index 0000000..d06059e --- /dev/null +++ b/utils/gen_adldata/file_formats/common.h @@ -0,0 +1,28 @@ +#ifndef COMMON_H +#define COMMON_H + +#include + +inline uint16_t toUint16BE(const uint8_t *arr) +{ + uint16_t num = arr[1]; + num |= ((arr[0] << 8) & 0xFF00); + return num; +} + +inline int16_t toSint16BE(const uint8_t *arr) +{ + int16_t num = *reinterpret_cast(&arr[0]); + num *= 1 << 8; + num |= arr[1]; + return num; +} + +inline uint16_t toUint16LE(const uint8_t *arr) +{ + uint16_t num = arr[0]; + num |= ((arr[1] << 8) & 0xFF00); + return num; +} + +#endif // COMMON_H diff --git a/utils/gen_adldata/file_formats/load_ail.h b/utils/gen_adldata/file_formats/load_ail.h new file mode 100644 index 0000000..4c6c482 --- /dev/null +++ b/utils/gen_adldata/file_formats/load_ail.h @@ -0,0 +1,102 @@ +#ifndef LOAD_AIL_H +#define LOAD_AIL_H + +#include "../progs_cache.h" +#include "../midi_inst_list.h" + +static bool LoadMiles(const char *fn, unsigned bank, const char *prefix) +{ + #ifdef HARD_BANKS + writeIni("AIL", fn, prefix, bank, INI_Both); + #endif + FILE *fp = std::fopen(fn, "rb"); + if(!fp) + return false; + std::fseek(fp, 0, SEEK_END); + std::vector data(size_t(std::ftell(fp))); + std::rewind(fp); + if(std::fread(&data[0], 1, data.size(), fp) != data.size()) + { + std::fclose(fp); + return false; + } + std::fclose(fp); + + for(unsigned a = 0; a < 2000; ++a) + { + unsigned gm_patch = data[a * 6 + 0]; + unsigned gm_bank = data[a * 6 + 1]; + unsigned offset = *(unsigned *)&data[a * 6 + 2]; + + if(gm_patch == 0xFF) + break; + + int gmno = gm_bank == 0x7F ? int(gm_patch + 0x80) : int(gm_patch); + int midi_index = gmno < 128 ? gmno + : gmno < 128 + 35 ? -1 + : gmno < 128 + 88 ? gmno - 35 + : -1; + unsigned length = data[offset] + data[offset + 1] * 256; + signed char notenum = ((signed char)data[offset + 2]); + + /*printf("%02X %02X %08X ", gmnumber,gmnumber2, offset); + for(unsigned b=0; b 3 && (b-3)%11 == 0) printf("\n "); + printf("%02X ", data[offset+b]); + } + printf("\n");*/ + + if(gm_bank != 0 && gm_bank != 0x7F) + continue; + + char name2[512]; + sprintf(name2, "%s%c%u", prefix, + (gmno < 128 ? 'M' : 'P'), gmno & 127); + + insdata tmp[200]; + + const unsigned inscount = (length - 3) / 11; + for(unsigned i = 0; i < inscount; ++i) + { + unsigned o = offset + 3 + i * 11; + tmp[i].finetune = (gmno < 128 && i == 0) ? notenum : 0; + tmp[i].diff = false; + tmp[i].data[0] = data[o + 0]; // 20 + tmp[i].data[8] = data[o + 1]; // 40 (vol) + tmp[i].data[2] = data[o + 2]; // 60 + tmp[i].data[4] = data[o + 3]; // 80 + tmp[i].data[6] = data[o + 4]; // E0 + tmp[i].data[1] = data[o + 6]; // 23 + tmp[i].data[9] = data[o + 7]; // 43 (vol) + tmp[i].data[3] = data[o + 8]; // 63 + tmp[i].data[5] = data[o + 9]; // 83 + tmp[i].data[7] = data[o + 10]; // E3 + + unsigned fb_c = data[offset + 3 + 5]; + tmp[i].data[10] = uint8_t(fb_c); + if(i == 1) + { + tmp[0].data[10] = fb_c & 0x0F; + tmp[1].data[10] = uint8_t((fb_c & 0x0E) | (fb_c >> 7)); + } + } + if(inscount == 1) + tmp[1] = tmp[0]; + + if(inscount <= 2) + { + struct ins tmp2; + tmp2.notenum = gmno < 128 ? 0 : (unsigned char)notenum; + tmp2.pseudo4op = false; + tmp2.voice2_fine_tune = 0.0; + std::string name; + if(midi_index >= 0) name = std::string(1, '\377') + MidiInsName[midi_index]; + size_t resno = InsertIns(tmp[0], tmp[1], tmp2, name, name2); + SetBank(bank, (unsigned int)gmno, resno); + } + } + return true; +} + +#endif // LOAD_AIL_H diff --git a/utils/gen_adldata/file_formats/load_bisqwit.h b/utils/gen_adldata/file_formats/load_bisqwit.h new file mode 100644 index 0000000..4928efa --- /dev/null +++ b/utils/gen_adldata/file_formats/load_bisqwit.h @@ -0,0 +1,53 @@ +#ifndef LOAD_BISQWIT_H +#define LOAD_BISQWIT_H + +#include "../progs_cache.h" +#include "../midi_inst_list.h" + +static bool LoadBisqwit(const char *fn, unsigned bank, const char *prefix) +{ + #ifdef HARD_BANKS + writeIni("Bisqwit", fn, prefix, bank, INI_Both); + #endif + FILE *fp = std::fopen(fn, "rb"); + if(!fp) + return false; + + for(uint32_t a = 0; a < 256; ++a) + { + //unsigned offset = a * 25; + uint32_t gmno = a; + int32_t midi_index = gmno < 128 ? int32_t(gmno) + : gmno < 128 + 35 ? -1 + : gmno < 128 + 88 ? int32_t(gmno - 35) + : -1; + + struct ins tmp2; + tmp2.notenum = (uint8_t)std::fgetc(fp); + tmp2.pseudo4op = false; + tmp2.voice2_fine_tune = 0.0; + + insdata tmp[2]; + for(int side = 0; side < 2; ++side) + { + tmp[side].finetune = (int8_t)std::fgetc(fp); + tmp[side].diff = false; + if(std::fread(tmp[side].data, 1, 11, fp) != 11) + return false; + } + + std::string name; + if(midi_index >= 0) name = std::string(1, '\377') + MidiInsName[midi_index]; + + char name2[512]; + sprintf(name2, "%s%c%u", prefix, + (gmno < 128 ? 'M' : 'P'), gmno & 127); + + size_t resno = InsertIns(tmp[0], tmp[1], tmp2, name, name2); + SetBank(bank, gmno, resno); + } + std::fclose(fp); + return true; +} + +#endif // LOAD_BISQWIT_H diff --git a/utils/gen_adldata/file_formats/load_bnk.h b/utils/gen_adldata/file_formats/load_bnk.h new file mode 100644 index 0000000..79ce5f5 --- /dev/null +++ b/utils/gen_adldata/file_formats/load_bnk.h @@ -0,0 +1,152 @@ +#ifndef LOAD_BNK_H +#define LOAD_BNK_H + +#include "../progs_cache.h" + +#include +#include +#include + +static bool LoadBNK(const char *fn, unsigned bank, const char *prefix, bool is_fat, bool percussive) +{ + #ifdef HARD_BANKS + writeIni("HMI", fn, prefix, bank, percussive ? INI_Drums : INI_Melodic); + #endif + FILE *fp = std::fopen(fn, "rb"); + if(!fp) + return false; + std::fseek(fp, 0, SEEK_END); + std::vector data(size_t(std::ftell(fp))); + std::rewind(fp); + if(std::fread(&data[0], 1, data.size(), fp) != data.size()) + { + std::fclose(fp); + return false; + } + std::fclose(fp); + + /*printf("%s:\n", fn);*/ + //unsigned short version = *(short*)&data[0]; // major,minor (2 bytes) + // "ADLIB-" (6 bytes) + uint16_t entries_used = *(uint16_t *)&data[8]; // entries used + //unsigned short total_entries = *(short*)&data[10]; // total entries + unsigned name_offset = *(unsigned *)&data[12]; // name_offset + unsigned data_offset = *(unsigned *)&data[16]; // data_offset + // 16..23: 8 byte sof filler + /*printf("version=%u %u %u %u %u\n", + version, entries_used,total_entries,name_offset,data_offset);*/ + + for(unsigned n = 0; n < entries_used; ++n) + { + const size_t offset1 = name_offset + n * 12; + + unsigned short data_index = data[offset1 + 0] + data[offset1 + 1] * 256; + unsigned char usage_flag = data[offset1 + 2]; + std::string name; + for(unsigned p = 0; p < 9; ++p) + { + if(data[offset1 + 3 + p] == '\0') break; + name += char(data[offset1 + 3 + p]); + } + + const size_t offset2 = data_offset + data_index * 30; + //const unsigned char mode = data[offset2+0]; + const unsigned char voice_num = data[offset2 + 1]; + const unsigned char *op1 = &data[offset2 + 2]; // 13 bytes + const unsigned char *op2 = &data[offset2 + 15]; + const unsigned char waveform_mod = data[offset2 + 28]; + const unsigned char waveform_car = data[offset2 + 29]; + + /*printf("%5d %3d %8s mode=%02X voice=%02X: ", data_index,usage_flag, name.c_str(), + mode,voice_num);*/ + + int gmno = int(is_fat + ? ((n & 127) + percussive * 128) + : (n + percussive * 128)); + + if(is_fat && percussive) + { + if(name[2] == 'O' + || name[2] == 'S') + { + gmno = 128 + std::stoi(name.substr(3)); + } + } + + char name2[512]; + if(is_fat) + sprintf(name2, "%s%c%u", prefix, percussive ? 'P' : 'M', gmno & 127); + else + sprintf(name2, "%s%u", prefix, n); + + insdata tmp; + tmp.data[0] = uint8_t( + (op1[ 9] << 7) // TREMOLO FLAG + + (op1[10] << 6) // VIBRATO FLAG + + (op1[ 5] << 5) // SUSTAIN FLAG + + (op1[11] << 4) // SCALING FLAG + + op1[ 1]); // FREQMUL + + tmp.data[1] = uint8_t((op2[ 9] << 7) + + (op2[10] << 6) + + (op2[ 5] << 5) + + (op2[11] << 4) + + op2[ 1]); + tmp.data[2] = op1[3] * 0x10 + op1[6]; // ATTACK, DECAY + tmp.data[3] = op2[3] * 0x10 + op2[6]; + tmp.data[4] = op1[4] * 0x10 + op1[7]; // SUSTAIN, RELEASE + tmp.data[5] = op2[4] * 0x10 + op2[7]; + tmp.data[6] = waveform_mod; + tmp.data[7] = waveform_car; + tmp.data[8] = op1[0] * 0x40 + op1[8]; // KSL , LEVEL + tmp.data[9] = op2[0] * 0x40 + op2[8]; // KSL , LEVEL + tmp.data[10] = op1[2] * 2 + op1[12]; // FEEDBACK, ADDITIVEFLAG + tmp.finetune = 0; + tmp.diff = false; + // Note: op2[2] and op2[12] are unused and contain garbage. + ins tmp2; + tmp2.notenum = is_fat ? voice_num : (percussive ? usage_flag : 0); + tmp2.pseudo4op = false; + tmp2.voice2_fine_tune = 0.0; + + if(is_fat) tmp.data[10] ^= 1; + + size_t resno = InsertIns(tmp, tmp, tmp2, std::string(1, '\377') + name, name2); + + if(!is_fat) + { + SetBank(bank, (unsigned int)gmno, resno); + } + else + { + if(name[2] == 'O' || name[1] == 'M') SetBank(bank + 0, (unsigned int)gmno, resno); + if(name[2] == 'S' || name[1] == 'M') SetBank(bank + 1, (unsigned int)gmno, resno); + } + + /* + for(unsigned p=0; p<30; ++p) + { + unsigned char value = data[offset2+p]; + if(value > maxvalues[p]) maxvalues[p] = value; + + #define dot(maxval) if(value<=maxval) printf("."); else printf("?[%u]%X",p,value); + + { + //if(p==6 || p==7 || p==19||p==20) value=15-value; + + if(p==4 || p==10 || p==17 || p==23)// || p==25) + printf(" %2X", value); + else + printf(" %X", value); + } + nl:; + //if(p == 12) printf("\n%*s", 22, ""); + //if(p == 25) printf("\n%*s", 22, ""); + } + printf("\n"); + */ + } + return true; +} + +#endif // LOAD_BNK_H diff --git a/utils/gen_adldata/file_formats/load_bnk2.h b/utils/gen_adldata/file_formats/load_bnk2.h new file mode 100644 index 0000000..202402c --- /dev/null +++ b/utils/gen_adldata/file_formats/load_bnk2.h @@ -0,0 +1,102 @@ +#ifndef LOAD_BNK2_H +#define LOAD_BNK2_H + +#include "../progs_cache.h" + +static bool LoadBNK2(const char *fn, unsigned bank, const char *prefix, + const std::string &melo_filter, + const std::string &perc_filter) +{ + #ifdef HARD_BANKS + writeIni("AdLibGold", fn, prefix, bank, INI_Both, melo_filter.c_str(), perc_filter.c_str()); + #endif + FILE *fp = std::fopen(fn, "rb"); + if(!fp) + return false; + std::fseek(fp, 0, SEEK_END); + std::vector data(size_t(std::ftell(fp))); + std::rewind(fp); + if(std::fread(&data[0], 1, data.size(), fp) != data.size()) + { + std::fclose(fp); + return false; + } + std::fclose(fp); + + unsigned short ins_entries = *(unsigned short *)&data[28 + 2 + 10]; + unsigned char *records = &data[48]; + + for(unsigned n = 0; n < ins_entries; ++n) + { + const size_t offset1 = n * 28; + int used = records[offset1 + 15]; + //int attrib = *(int*)&records[offset1 + 16]; + int offset2 = *(int *)&records[offset1 + 20]; + if(used == 0) continue; + + std::string name; + for(unsigned p = 0; p < 12; ++p) + { + if(records[offset1 + 3 + p] == '\0') break; + name += char(records[offset1 + 3 + p]); + } + + int gmno = 0; + if(name.substr(0, melo_filter.size()) == melo_filter) + gmno = std::stoi(name.substr(melo_filter.size())); + else if(name.substr(0, perc_filter.size()) == perc_filter) + gmno = std::stoi(name.substr(perc_filter.size())) + 128; + else + continue; + + const unsigned char *insdata = &data[size_t(offset2)]; + const unsigned char *ops[4] = { insdata + 0, insdata + 6, insdata + 12, insdata + 18 }; + unsigned char C4xxxFFFC = insdata[24]; + unsigned char xxP24NNN = insdata[25]; + unsigned char TTTTTTTT = insdata[26]; + //unsigned char xxxxxxxx = insdata[27]; + + char name2[512]; + sprintf(name2, "%s%c%u", prefix, (gmno & 128) ? 'P' : 'M', gmno & 127); + + struct insdata tmp[2]; + for(unsigned a = 0; a < 2; ++a) + { + tmp[a].data[0] = ops[a * 2 + 0][0]; + tmp[a].data[1] = ops[a * 2 + 1][0]; + tmp[a].data[2] = ops[a * 2 + 0][2]; + tmp[a].data[3] = ops[a * 2 + 1][2]; + tmp[a].data[4] = ops[a * 2 + 0][3]; + tmp[a].data[5] = ops[a * 2 + 1][3]; + tmp[a].data[6] = ops[a * 2 + 0][4] & 0x07; + tmp[a].data[7] = ops[a * 2 + 1][4] & 0x07; + tmp[a].data[8] = ops[a * 2 + 0][1]; + tmp[a].data[9] = ops[a * 2 + 1][1]; + tmp[a].finetune = (int8_t)TTTTTTTT; + tmp[a].diff = false; + } + tmp[0].data[10] = C4xxxFFFC & 0x0F; + tmp[1].data[10] = (tmp[0].data[10] & 0x0E) | (C4xxxFFFC >> 7); + + ins tmp2; + tmp2.notenum = (gmno & 128) ? 35 : 0; + tmp2.pseudo4op = false; + tmp2.voice2_fine_tune = 0.0; + + if(xxP24NNN & 8) + { + // dual-op + size_t resno = InsertIns(tmp[0], tmp[1], tmp2, std::string(1, '\377') + name, name2); + SetBank(bank, (unsigned int)gmno, resno); + } + else + { + // single-op + size_t resno = InsertIns(tmp[0], tmp[0], tmp2, std::string(1, '\377') + name, name2); + SetBank(bank, (unsigned int)gmno, resno); + } + } + return true; +} + +#endif // LOAD_BNK2_H diff --git a/utils/gen_adldata/file_formats/load_ibk.h b/utils/gen_adldata/file_formats/load_ibk.h new file mode 100644 index 0000000..6370ad0 --- /dev/null +++ b/utils/gen_adldata/file_formats/load_ibk.h @@ -0,0 +1,72 @@ +#ifndef LOAD_IBK_H +#define LOAD_IBK_H + +#include "../progs_cache.h" + +static bool LoadIBK(const char *fn, unsigned bank, const char *prefix, bool percussive) +{ + #ifdef HARD_BANKS + writeIni("IBK", fn, prefix, bank, percussive ? INI_Drums : INI_Melodic); + #endif + FILE *fp = std::fopen(fn, "rb"); + if(!fp) + return false; + std::fseek(fp, 0, SEEK_END); + std::vector data(size_t(std::ftell(fp))); + std::rewind(fp); + if(std::fread(&data[0], 1, data.size(), fp) != data.size()) + { + std::fclose(fp); + return false; + } + std::fclose(fp); + + unsigned offs1_base = 0x804, offs1_len = 9; + unsigned offs2_base = 0x004, offs2_len = 16; + + for(unsigned a = 0; a < 128; ++a) + { + unsigned offset1 = offs1_base + a * offs1_len; + unsigned offset2 = offs2_base + a * offs2_len; + + std::string name; + for(unsigned p = 0; p < 9; ++p) + if(data[offset1] != '\0') + name += char(data[offset1 + p]); + + int gmno = int(a + 128 * percussive); + /*int midi_index = gmno < 128 ? gmno + : gmno < 128+35 ? -1 + : gmno < 128+88 ? gmno-35 + : -1;*/ + char name2[512]; + sprintf(name2, "%s%c%u", prefix, + (gmno < 128 ? 'M' : 'P'), gmno & 127); + + insdata tmp; + tmp.data[0] = data[offset2 + 0]; + tmp.data[1] = data[offset2 + 1]; + tmp.data[8] = data[offset2 + 2]; + tmp.data[9] = data[offset2 + 3]; + tmp.data[2] = data[offset2 + 4]; + tmp.data[3] = data[offset2 + 5]; + tmp.data[4] = data[offset2 + 6]; + tmp.data[5] = data[offset2 + 7]; + tmp.data[6] = data[offset2 + 8]; + tmp.data[7] = data[offset2 + 9]; + tmp.data[10] = data[offset2 + 10]; + // [+11] seems to be used also, what is it for? + tmp.finetune = 0; + tmp.diff = false; + struct ins tmp2; + tmp2.notenum = gmno < 128 ? 0 : 35; + tmp2.pseudo4op = false; + tmp2.voice2_fine_tune = 0.0; + + size_t resno = InsertIns(tmp, tmp, tmp2, std::string(1, '\377') + name, name2); + SetBank(bank, (unsigned int)gmno, resno); + } + return true; +} + +#endif // LOAD_IBK_H diff --git a/utils/gen_adldata/file_formats/load_jv.h b/utils/gen_adldata/file_formats/load_jv.h new file mode 100644 index 0000000..f35de03 --- /dev/null +++ b/utils/gen_adldata/file_formats/load_jv.h @@ -0,0 +1,105 @@ +#ifndef LOAD_JV_H +#define LOAD_JV_H + +#include "../progs_cache.h" +#include "../midi_inst_list.h" + +static bool LoadJunglevision(const char *fn, unsigned bank, const char *prefix) +{ + #ifdef HARD_BANKS + writeIni("Junglevision", fn, prefix, bank, INI_Both); + #endif + FILE *fp = std::fopen(fn, "rb"); + if(!fp) + return false; + std::fseek(fp, 0, SEEK_END); + std::vector data(size_t(std::ftell(fp))); + std::rewind(fp); + if(std::fread(&data[0], 1, data.size(), fp) != data.size()) + { + std::fclose(fp); + return false; + } + std::fclose(fp); + + uint16_t ins_count = uint16_t(data[0x20] + (data[0x21] << 8)); + uint16_t drum_count = uint16_t(data[0x22] + (data[0x23] << 8)); + uint16_t first_ins = uint16_t(data[0x24] + (data[0x25] << 8)); + uint16_t first_drum = uint16_t(data[0x26] + (data[0x27] << 8)); + + unsigned total_ins = ins_count + drum_count; + + for(unsigned a = 0; a < total_ins; ++a) + { + unsigned offset = 0x28 + a * 0x18; + unsigned gmno = (a < ins_count) ? (a + first_ins) : (a + first_drum); + int midi_index = gmno < 128 ? int(gmno) + : gmno < 128 + 35 ? -1 + : gmno < 128 + 88 ? int(gmno - 35) + : -1; + + insdata tmp[2]; + + tmp[0].data[0] = data[offset + 2]; + tmp[0].data[1] = data[offset + 8]; + tmp[0].data[2] = data[offset + 4]; + tmp[0].data[3] = data[offset + 10]; + tmp[0].data[4] = data[offset + 5]; + tmp[0].data[5] = data[offset + 11]; + tmp[0].data[6] = data[offset + 6]; + tmp[0].data[7] = data[offset + 12]; + tmp[0].data[8] = data[offset + 3]; + tmp[0].data[9] = data[offset + 9]; + tmp[0].data[10] = data[offset + 7] & 0x0F;//~0x30; + tmp[0].finetune = 0; + tmp[0].diff = false; + + tmp[1].data[0] = data[offset + 2 + 11]; + tmp[1].data[1] = data[offset + 8 + 11]; + tmp[1].data[2] = data[offset + 4 + 11]; + tmp[1].data[3] = data[offset + 10 + 11]; + tmp[1].data[4] = data[offset + 5 + 11]; + tmp[1].data[5] = data[offset + 11 + 11]; + tmp[1].data[6] = data[offset + 6 + 11]; + tmp[1].data[7] = data[offset + 12 + 11]; + tmp[1].data[8] = data[offset + 3 + 11]; + tmp[1].data[9] = data[offset + 9 + 11]; + tmp[1].data[10] = data[offset + 7 + 11] & 0x0F;//~0x30; + tmp[1].finetune = 0; + tmp[1].diff = false; + + struct ins tmp2; + tmp2.notenum = data[offset + 1]; + tmp2.pseudo4op = false; + tmp2.voice2_fine_tune = 0.0; + + while(tmp2.notenum && tmp2.notenum < 20) + { + tmp2.notenum += 12; + tmp[0].finetune -= 12; + tmp[1].finetune -= 12; + } + + std::string name; + if(midi_index >= 0) name = std::string(1, '\377') + MidiInsName[midi_index]; + + char name2[512]; + sprintf(name2, "%s%c%u", prefix, + (gmno < 128 ? 'M' : 'P'), gmno & 127); + + if(!data[offset]) + { + size_t resno = InsertIns(tmp[0], tmp[0], tmp2, name, name2); + SetBank(bank, gmno, resno); + } + else // Double instrument + { + size_t resno = InsertIns(tmp[0], tmp[1], tmp2, name, name2); + SetBank(bank, gmno, resno); + } + } + return true; +} + +#endif // LOAD_JV_H + diff --git a/utils/gen_adldata/file_formats/load_op2.h b/utils/gen_adldata/file_formats/load_op2.h new file mode 100644 index 0000000..30a118f --- /dev/null +++ b/utils/gen_adldata/file_formats/load_op2.h @@ -0,0 +1,148 @@ +#ifndef LOAD_OP2_H +#define LOAD_OP2_H + +#include "../progs_cache.h" + +#pragma pack(push, 1) +struct Doom_OPL2instrument +{ + unsigned char trem_vibr_1; /* OP 1: tremolo/vibrato/sustain/KSR/multi */ + unsigned char att_dec_1; /* OP 1: attack rate/decay rate */ + unsigned char sust_rel_1; /* OP 1: sustain level/release rate */ + unsigned char wave_1; /* OP 1: waveform select */ + unsigned char scale_1; /* OP 1: key scale level */ + unsigned char level_1; /* OP 1: output level */ + unsigned char feedback; /* feedback/AM-FM (both operators) */ + unsigned char trem_vibr_2; /* OP 2: tremolo/vibrato/sustain/KSR/multi */ + unsigned char att_dec_2; /* OP 2: attack rate/decay rate */ + unsigned char sust_rel_2; /* OP 2: sustain level/release rate */ + unsigned char wave_2; /* OP 2: waveform select */ + unsigned char scale_2; /* OP 2: key scale level */ + unsigned char level_2; /* OP 2: output level */ + unsigned char unused; + short basenote; /* base note offset */ +} __attribute__((packed)); +#pragma pack(pop) + +struct Doom_opl_instr +{ + unsigned short flags; +#define FL_FIXED_PITCH 0x0001 // note has fixed pitch (drum note) +#define FL_UNKNOWN 0x0002 // ??? (used in instrument #65 only) +#define FL_DOUBLE_VOICE 0x0004 // use two voices instead of one + + unsigned char finetune; + unsigned char note; + struct Doom_OPL2instrument patchdata[2]; +} __attribute__((packed)); + + +static bool LoadDoom(const char *fn, unsigned bank, const char *prefix) +{ + #ifdef HARD_BANKS + writeIni("OP2", fn, prefix, bank, INI_Both); + #endif + FILE *fp = std::fopen(fn, "rb"); + if(!fp) + return false; + std::fseek(fp, 0, SEEK_END); + std::vector data(size_t(std::ftell(fp))); + std::rewind(fp); + + if(std::fread(&data[0], 1, data.size(), fp) != data.size()) + { + std::fclose(fp); + return false; + } + std::fclose(fp); + + for(unsigned a = 0; a < 175; ++a) + { + const size_t offset1 = 0x18A4 + a * 32; + const size_t offset2 = 8 + a * 36; + + std::string name; + for(unsigned p = 0; p < 32; ++p) + if(data[offset1] != '\0') + name += char(data[offset1 + p]); + + //printf("%3d %3d %3d %8s: ", a,b,c, name.c_str()); + int gmno = int(a < 128 ? a : ((a | 128) + 35)); + + char name2[512]; + sprintf(name2, "%s%c%u", prefix, (gmno < 128 ? 'M' : 'P'), gmno & 127); + + Doom_opl_instr &ins = *(Doom_opl_instr *) &data[offset2]; + + insdata tmp[2]; + tmp[0].diff = false; + tmp[1].diff = true; + for(unsigned index = 0; index < 2; ++index) + { + const Doom_OPL2instrument &src = ins.patchdata[index]; + tmp[index].data[0] = src.trem_vibr_1; + tmp[index].data[1] = src.trem_vibr_2; + tmp[index].data[2] = src.att_dec_1; + tmp[index].data[3] = src.att_dec_2; + tmp[index].data[4] = src.sust_rel_1; + tmp[index].data[5] = src.sust_rel_2; + tmp[index].data[6] = src.wave_1; + tmp[index].data[7] = src.wave_2; + tmp[index].data[8] = src.scale_1 | src.level_1; + tmp[index].data[9] = src.scale_2 | src.level_2; + tmp[index].data[10] = src.feedback; + tmp[index].finetune = int8_t(src.basenote + 12); + } + struct ins tmp2; + tmp2.notenum = ins.note; + tmp2.pseudo4op = false; + tmp2.voice2_fine_tune = 0.0; + while(tmp2.notenum && tmp2.notenum < 20) + { + tmp2.notenum += 12; + tmp[0].finetune -= 12; + tmp[1].finetune -= 12; + } + + if(!(ins.flags & 4)) + { + size_t resno = InsertIns(tmp[0], tmp[0], tmp2, std::string(1, '\377') + name, name2); + SetBank(bank, (unsigned int)gmno, resno); + } + else // Double instrument + { + tmp2.pseudo4op = true; + tmp2.voice2_fine_tune = (((double)ins.finetune - 128.0) * 15.625) / 1000.0; + if(ins.finetune == 129) + tmp2.voice2_fine_tune = 0.000025; + else if(ins.finetune == 127) + tmp2.voice2_fine_tune = -0.000025; + //printf("/*DOOM FINE TUNE (flags %000X instrument is %d) IS %d -> %lf*/\n", ins.flags, a, ins.finetune, tmp2.fine_tune); + size_t resno = InsertIns(tmp[0], tmp[1], tmp2, std::string(1, '\377') + name, name2); + SetBank(bank, (unsigned int)gmno, resno); + } + + /*const Doom_OPL2instrument& A = ins.patchdata[0]; + const Doom_OPL2instrument& B = ins.patchdata[1]; + printf( + "flags:%04X fine:%02X note:%02X\n" + "{t:%02X a:%02X s:%02X w:%02X s:%02X l:%02X f:%02X\n" + " t:%02X a:%02X s:%02X w:%02X s:%02X l:%02X ?:%02X base:%d}\n" + "{t:%02X a:%02X s:%02X w:%02X s:%02X l:%02X f:%02X\n" + " t:%02X a:%02X s:%02X w:%02X s:%02X l:%02X ?:%02X base:%d} ", + ins.flags, ins.finetune, ins.note, + A.trem_vibr_1, A.att_dec_1, A.sust_rel_1, + A.wave_1, A.scale_1, A.level_1, A.feedback, + A.trem_vibr_2, A.att_dec_2, A.sust_rel_2, + A.wave_2, A.scale_2, A.level_2, A.unused, A.basenote, + B.trem_vibr_1, B.att_dec_1, B.sust_rel_1, + B.wave_1, B.scale_1, B.level_1, B.feedback, + B.trem_vibr_2, B.att_dec_2, B.sust_rel_2, + B.wave_2, B.scale_2, B.level_2, B.unused, B.basenote); + printf(" %s VS %s\n", name.c_str(), MidiInsName[a]); + printf("------------------------------------------------------------\n");*/ + } + return true; +} + +#endif // LOAD_OP2_H diff --git a/utils/gen_adldata/file_formats/load_tmb.h b/utils/gen_adldata/file_formats/load_tmb.h new file mode 100644 index 0000000..c5a3f60 --- /dev/null +++ b/utils/gen_adldata/file_formats/load_tmb.h @@ -0,0 +1,68 @@ +#ifndef LOAD_TMB_H +#define LOAD_TMB_H + +#include "../progs_cache.h" +#include "../midi_inst_list.h" + +static bool LoadTMB(const char *fn, unsigned bank, const char *prefix) +{ + #ifdef HARD_BANKS + writeIni("TMB", fn, prefix, bank, INI_Both); + #endif + FILE *fp = std::fopen(fn, "rb"); + if(!fp) + return false; + std::fseek(fp, 0, SEEK_END); + std::vector data(size_t(std::ftell(fp))); + std::rewind(fp); + if(std::fread(&data[0], 1, data.size(), fp) != data.size()) + { + std::fclose(fp); + return false; + } + std::fclose(fp); + + for(unsigned a = 0; a < 256; ++a) + { + unsigned offset = a * 0x0D; + unsigned gmno = a; + int midi_index = gmno < 128 ? int(gmno) + : gmno < 128 + 35 ? -1 + : gmno < 128 + 88 ? int(gmno - 35) + : -1; + + insdata tmp; + + tmp.data[0] = data[offset + 0]; + tmp.data[1] = data[offset + 1]; + tmp.data[2] = data[offset + 4]; + tmp.data[3] = data[offset + 5]; + tmp.data[4] = data[offset + 6]; + tmp.data[5] = data[offset + 7]; + tmp.data[6] = data[offset + 8]; + tmp.data[7] = data[offset + 9]; + tmp.data[8] = data[offset + 2]; + tmp.data[9] = data[offset + 3]; + tmp.data[10] = data[offset + 10]; + tmp.finetune = 0; //data[offset + 12]; + tmp.diff = false; + + struct ins tmp2; + tmp2.notenum = data[offset + 11]; + tmp2.pseudo4op = false; + tmp2.voice2_fine_tune = 0.0; + + std::string name; + if(midi_index >= 0) name = std::string(1, '\377') + MidiInsName[midi_index]; + + char name2[512]; + sprintf(name2, "%s%c%u", prefix, + (gmno < 128 ? 'M' : 'P'), gmno & 127); + + size_t resno = InsertIns(tmp, tmp, tmp2, name, name2); + SetBank(bank, gmno, resno); + } + return true; +} + +#endif // LOAD_TMB_H diff --git a/utils/gen_adldata/file_formats/load_wopl.h b/utils/gen_adldata/file_formats/load_wopl.h new file mode 100644 index 0000000..300a3a0 --- /dev/null +++ b/utils/gen_adldata/file_formats/load_wopl.h @@ -0,0 +1,265 @@ +#ifndef LOAD_WOPL_H +#define LOAD_WOPL_H + +#include "../progs_cache.h" +#include "../midi_inst_list.h" +#include "common.h" + +static uint8_t wopl_latest_version = 2; + +static bool LoadWopl(const char *fn, unsigned bank, const char *prefix) +{ + FILE *fp = std::fopen(fn, "rb"); + if(!fp) + { + std::fprintf(stderr, "WOPL: CAN'T OPEN FILE %s\n", fn); + std::fflush(stderr); + return false; + } + std::fseek(fp, 0, SEEK_END); + std::vector data(size_t(std::ftell(fp))); + std::rewind(fp); + if(std::fread(&data[0], 1, data.size(), fp) != data.size()) + { + std::fclose(fp); + std::fprintf(stderr, "WOPL: CAN'T READ FILE %s\n", fn); + std::fflush(stderr); + return false; + } + std::fclose(fp); + + if(data.size() < 19) // Smaller than header size + { + std::fprintf(stderr, "WOPL: Too small header %s\n", fn); + std::fflush(stderr); + return false; + } + + uint16_t version = toUint16LE((const uint8_t *)data.data() + 11); + if(version > wopl_latest_version) + { + std::fprintf(stderr, "WOPL: Version %d is not supported (latest %d) %s\n", version, wopl_latest_version, fn); + std::fflush(stderr); + return false; + } + + uint16_t mbanks_count = toUint16BE((const uint8_t *)data.data() + 0x0d); + uint16_t pbanks_count = toUint16BE((const uint8_t *)data.data() + 0x0f); + + // Validate file format by size calculation + if(version == 1) + { + //Header size + melodic banks + percussion banks + if(data.size() < size_t(19 + (62 * 128 * mbanks_count) + (62 * 128 * pbanks_count))) + { + std::fprintf(stderr, "WOPL: Version 1 size calculation failed %s\n", fn); + std::fflush(stderr); + return false; + } + } + else if(version >= 2) + { + //Header size + melodic bank meta data + percussion bank meta data + melodic banks + percussion banks + if(data.size() < size_t(19 + (34 * mbanks_count) + (34 * pbanks_count) + (62 * 128 * mbanks_count) + (62 * 128 * pbanks_count))) + { + std::fprintf(stderr, "WOPL: Version %d size calculation failed %s\n", version, fn); + std::fflush(stderr); + return false; + } + } + + uint32_t melodic_offset = 0; + uint32_t percussion_offset = 0; + if(version < 2) + melodic_offset = 0x13; + else + melodic_offset = 0x13 + 34 * mbanks_count + 34 * pbanks_count; + + percussion_offset = melodic_offset + (62 * 128 * mbanks_count); + + for(uint32_t mbank = 0; mbank < 1; mbank++) // only first melodic bank (Until multi-banks support will be implemented) + { + uint32_t bank_offset = melodic_offset + (mbank * 62 * 128); + + for(unsigned i = 0; i < 128; i++) + { + uint32_t offset = bank_offset + uint32_t(i * 62); + std::string name; + insdata tmp[2]; + + name.resize(32); + std::memcpy(&name[0], data.data() + offset, 32); + name.resize(std::strlen(&name[0])); + + tmp[0].data[0] = data[offset + 42 + 5]; + tmp[0].data[1] = data[offset + 42 + 0]; + tmp[0].data[2] = data[offset + 42 + 7]; + tmp[0].data[3] = data[offset + 42 + 2]; + tmp[0].data[4] = data[offset + 42 + 8]; + tmp[0].data[5] = data[offset + 42 + 3]; + tmp[0].data[6] = data[offset + 42 + 9]; + tmp[0].data[7] = data[offset + 42 + 4]; + tmp[0].data[8] = data[offset + 42 + 6]; + tmp[0].data[9] = data[offset + 42 + 1]; + tmp[0].data[10] = data[offset + 40]; + + tmp[1].data[0] = data[offset + 52 + 5]; + tmp[1].data[1] = data[offset + 52 + 0]; + tmp[1].data[2] = data[offset + 52 + 7]; + tmp[1].data[3] = data[offset + 52 + 2]; + tmp[1].data[4] = data[offset + 52 + 8]; + tmp[1].data[5] = data[offset + 52 + 3]; + tmp[1].data[6] = data[offset + 52 + 9]; + tmp[1].data[7] = data[offset + 52 + 4]; + tmp[1].data[8] = data[offset + 52 + 6]; + tmp[1].data[9] = data[offset + 52 + 1]; + tmp[1].data[10] = data[offset + 41]; + + tmp[0].finetune = int8_t(toSint16BE((const uint8_t *)data.data() + offset + 32)); + tmp[1].finetune = int8_t(toSint16BE((const uint8_t *)data.data() + offset + 34)); + + uint8_t flags = data[offset + 39]; + + struct ins tmp2; + tmp2.notenum = 0; + tmp2.pseudo4op = (flags & 0x02) != 0; + tmp2.voice2_fine_tune = 0; + tmp[0].diff = false; + tmp[1].diff = tmp2.pseudo4op; + + int8_t fine_tune = (int8_t)data[offset + 37]; + if(fine_tune != 0) + { + if(fine_tune == 1) + tmp2.voice2_fine_tune = 0.000025; + else if(fine_tune == -1) + tmp2.voice2_fine_tune = -0.000025; + else + tmp2.voice2_fine_tune = ((fine_tune * 15.625) / 1000.0); + } + + if(name.empty()) + name = std::string(1, '\377') + MidiInsName[i]; + else + name.insert(0, 1, '\377'); + + char name2[512]; + sprintf(name2, "%sM%u", prefix, i); + + if((flags & 0x03) == 0) + { + size_t resno = InsertIns(tmp[0], tmp[0], tmp2, name, name2); + SetBank(bank, i, resno); + } + else + { + size_t resno = InsertIns(tmp[0], tmp[1], tmp2, name, name2); + SetBank(bank, i, resno); + } + } + } + + for(uint32_t pbank = 0; pbank < 1; pbank++) // only first percussion bank (Until multi-banks support will be implemented) + { + uint32_t bank_offset = percussion_offset + (pbank * 62 * 128); + + for(uint32_t i = 0; i < 128; i++) + { + uint32_t offset = bank_offset + (i * 62); + std::string name; + insdata tmp[2]; + + name.resize(32); + std::memcpy(&name[0], data.data() + offset, 32); + name.resize(std::strlen(&name[0])); +/* + WOPL's + + 0 AM/Vib/Env/Ksr/FMult characteristics + 1 Key Scale Level / Total level register data + 2 Attack / Decay + 3 Systain and Release register data + 4 Wave form + + 5 AM/Vib/Env/Ksr/FMult characteristics + 6 Key Scale Level / Total level register data + 7 Attack / Decay + 8 Systain and Release register data + 9 Wave form +*/ + tmp[0].data[0] = data[offset + 42 + 5];//AMVIB op1 + tmp[0].data[1] = data[offset + 42 + 0];//AMVIB op2 + tmp[0].data[2] = data[offset + 42 + 7];//AtDec op1 + tmp[0].data[3] = data[offset + 42 + 2];//AtDec op2 + tmp[0].data[4] = data[offset + 42 + 8];//SusRel op1 + tmp[0].data[5] = data[offset + 42 + 3];//SusRel op2 + tmp[0].data[6] = data[offset + 42 + 9];//Wave op1 + tmp[0].data[7] = data[offset + 42 + 4];//Wave op2 + tmp[0].data[8] = data[offset + 42 + 6];//KSL op1 + tmp[0].data[9] = data[offset + 42 + 1];//KSL op2 + tmp[0].data[10] = data[offset + 40]; + + tmp[1].data[0] = data[offset + 52 + 5]; + tmp[1].data[1] = data[offset + 52 + 0]; + tmp[1].data[2] = data[offset + 52 + 7]; + tmp[1].data[3] = data[offset + 52 + 2]; + tmp[1].data[4] = data[offset + 52 + 8]; + tmp[1].data[5] = data[offset + 52 + 3]; + tmp[1].data[6] = data[offset + 52 + 9]; + tmp[1].data[7] = data[offset + 52 + 4]; + tmp[1].data[8] = data[offset + 52 + 6]; + tmp[1].data[9] = data[offset + 52 + 1]; + tmp[1].data[10] = data[offset + 41]; + + tmp[0].finetune = int8_t(toSint16BE((const uint8_t *)data.data() + offset + 32)); + tmp[1].finetune = int8_t(toSint16BE((const uint8_t *)data.data() + offset + 34)); + uint8_t flags = data[offset + 39]; + + struct ins tmp2; + tmp2.notenum = data[offset + 38]; + tmp2.pseudo4op = (flags & 0x02) != 0; + tmp2.voice2_fine_tune = 0; + tmp[0].diff = false; + tmp[1].diff = tmp2.pseudo4op; + + int8_t fine_tune = (int8_t)data[offset + 37]; + if(fine_tune != 0) + { + if(fine_tune == 1) + tmp2.voice2_fine_tune = 0.000025; + else if(fine_tune == -1) + tmp2.voice2_fine_tune = -0.000025; + else + tmp2.voice2_fine_tune = ((fine_tune * 15.625) / 1000.0); + } + + uint32_t gmno = i + 128; + int midi_index = (gmno < (128 + 35)) ? -1 + : (gmno < (128 + 88)) ? int(gmno) - 35 + : -1; + + if(name.empty() && (midi_index >= 0)) + name = std::string(1, '\377') + MidiInsName[midi_index]; + if(!name.empty()) + name.insert(0, 1, '\377'); + + char name2[512]; + sprintf(name2, "%sP%u", prefix, gmno & 127); + + if((flags & 0x03) == 0) + { + size_t resno = InsertIns(tmp[0], tmp[0], tmp2, name, name2); + SetBank(bank, gmno, resno); + } + else + { + size_t resno = InsertIns(tmp[0], tmp[1], tmp2, name, name2); + SetBank(bank, gmno, resno); + } + } + } + return true; +} + + +#endif // LOAD_WOPL_H diff --git a/utils/gen_adldata/gen_adldata.cc b/utils/gen_adldata/gen_adldata.cc new file mode 100644 index 0000000..6c77a12 --- /dev/null +++ b/utils/gen_adldata/gen_adldata.cc @@ -0,0 +1,506 @@ +//#ifdef __MINGW32__ +//typedef struct vswprintf {} swprintf; +//#endif +#include +#include +#include + +#include "ini/ini_processing.h" + +#include "progs_cache.h" +#include "measurer.h" + +#include "midi_inst_list.h" + +#include "file_formats/load_ail.h" +#include "file_formats/load_bisqwit.h" +#include "file_formats/load_bnk2.h" +#include "file_formats/load_bnk.h" +#include "file_formats/load_ibk.h" +#include "file_formats/load_jv.h" +#include "file_formats/load_op2.h" +#include "file_formats/load_tmb.h" +#include "file_formats/load_wopl.h" + +int main(int argc, char**argv) +{ + if(argc == 1) + { + printf("Usage:\n" + "\n" + "bin/gen_adldata src/adldata.cpp\n" + "\n"); + return 1; + } + + const char *outFile_s = argv[1]; + + FILE *outFile = fopen(outFile_s, "w"); + if(!outFile) + { + fprintf(stderr, "Can't open %s file for write!\n", outFile_s); + return 1; + } + + fprintf(outFile, "\ +#include \"adldata.hh\"\n\ +\n\ +/* THIS OPL-3 FM INSTRUMENT DATA IS AUTOMATICALLY GENERATED\n\ + * FROM A NUMBER OF SOURCES, MOSTLY PC GAMES.\n\ + * PREPROCESSED, CONVERTED, AND POSTPROCESSED OFF-SCREEN.\n\ + */\n\ +"); + { + IniProcessing ini; + if(!ini.open("banks.ini")) + { + fprintf(stderr, "Can't open banks.ini!\n"); + return 1; + } + + uint32_t banks_count; + ini.beginGroup("General"); + ini.read("banks", banks_count, 0); + ini.endGroup(); + + if(!banks_count) + { + fprintf(stderr, "Zero count of banks found in banks.ini!\n"); + return 1; + } + + for(uint32_t bank = 0; bank < banks_count; bank++) + { + if(!ini.beginGroup(std::string("bank-") + std::to_string(bank))) + { + fprintf(stderr, "Failed to find bank %u!\n", bank); + return 1; + } + std::string bank_name; + std::string filepath; + std::string filepath_d; + std::string prefix; + std::string prefix_d; + std::string filter_m; + std::string filter_p; + std::string format; + + ini.read("name", bank_name, "Untitled"); + ini.read("format", format, "Unknown"); + ini.read("file", filepath, ""); + ini.read("file-p", filepath_d, ""); + ini.read("prefix", prefix, ""); + ini.read("prefix-p", prefix_d, ""); + ini.read("filter-m", filter_m, ""); + ini.read("filter-p", filter_p, ""); + + if(filepath.empty()) + { + fprintf(stderr, "Failed to load bank %u, file is empty!\n", bank); + return 1; + } + + banknames.push_back(bank_name); + + //printf("Loading %s...\n", filepath.c_str()); + + if(format == "AIL") + { + if(!LoadMiles(filepath.c_str(), bank, prefix.c_str())) + { + fprintf(stderr, "Failed to load bank %u, file %s!\n", bank, filepath.c_str()); + return 1; + } + } + else + if(format == "Bisqwit") + { + if(!LoadBisqwit(filepath.c_str(), bank, prefix.c_str())) + { + fprintf(stderr, "Failed to load bank %u, file %s!\n", bank, filepath.c_str()); + return 1; + } + } + else + if(format == "WOPL") + { + if(!LoadWopl(filepath.c_str(), bank, prefix.c_str())) + { + fprintf(stderr, "Failed to load bank %u, file %s!\n", bank, filepath.c_str()); + return 1; + } + } + else + if(format == "OP2") + { + if(!LoadDoom(filepath.c_str(), bank, prefix.c_str())) + { + fprintf(stderr, "Failed to load bank %u, file %s!\n", bank, filepath.c_str()); + return 1; + } + } + else + if(format == "TMB") + { + if(!LoadTMB(filepath.c_str(), bank, prefix.c_str())) + { + fprintf(stderr, "Failed to load bank %u, file %s!\n", bank, filepath.c_str()); + return 1; + } + } + else + if(format == "Junglevision") + { + if(!LoadJunglevision(filepath.c_str(), bank, prefix.c_str())) + { + fprintf(stderr, "Failed to load bank %u, file %s!\n", bank, filepath.c_str()); + return 1; + } + } + else + if(format == "AdLibGold") + { + if(!LoadBNK2(filepath.c_str(), bank, prefix.c_str(), filter_m, filter_p)) + { + fprintf(stderr, "Failed to load bank %u, file %s!\n", bank, filepath.c_str()); + return 1; + } + } + else + if(format == "HMI") + { + if(!LoadBNK(filepath.c_str(), bank, prefix.c_str(), false, false)) + { + fprintf(stderr, "Failed to load bank %u, file %s!\n", bank, filepath.c_str()); + return 1; + } + if(!filepath_d.empty()) + { + if(!LoadBNK(filepath_d.c_str(),bank, prefix_d.c_str(), false, true)) + { + fprintf(stderr, "Failed to load bank %u, file %s!\n", bank, filepath.c_str()); + return 1; + } + } + } + else + if(format == "IBK") + { + if(!LoadIBK(filepath.c_str(), bank, prefix.c_str(), false)) + { + fprintf(stderr, "Failed to load bank %u, file %s!\n", bank, filepath.c_str()); + return 1; + } + if(!filepath_d.empty()) + { + //printf("Loading %s... \n", filepath_d.c_str()); + if(!LoadIBK(filepath_d.c_str(),bank, prefix_d.c_str(), true)) + { + fprintf(stderr, "Failed to load bank %u, file %s!\n", bank, filepath.c_str()); + return 1; + } + } + } + else + { + fprintf(stderr, "Failed to load bank %u, file %s!\nUnknown format type %s\n", + bank, + filepath.c_str(), + format.c_str()); + return 1; + } + + + ini.endGroup(); + } + + printf("Loaded %u banks!\n", banks_count); + fflush(stdout); + } + + #if 0 + for(unsigned a = 0; a < 36 * 8; ++a) + { + if((1 << (a % 8)) > maxvalues[a / 8]) continue; + + const std::map &data = Correlate[a]; + if(data.empty()) continue; + std::vector< std::pair > correlations; + for(std::map::const_iterator + i = data.begin(); + i != data.end(); + ++i) + { + correlations.push_back(std::make_pair(i->second, i->first)); + } + std::sort(correlations.begin(), correlations.end()); + fprintf(outFile, "Byte %2u bit %u=mask %02X:\n", a / 8, a % 8, 1 << (a % 8)); + for(size_t c = 0; c < correlations.size() && c < 10; ++c) + { + unsigned count = correlations[correlations.size() - 1 - c ].first; + unsigned index = correlations[correlations.size() - 1 - c ].second; + fprintf(outFile, "\tAdldata index %u, bit %u=mask %02X (%u matches)\n", + index / 8, index % 8, 1 << (index % 8), count); + } + } + #endif + + printf("Writing raw instrument data...\n"); + fflush(stdout); + { + fprintf(outFile, + /* + "static const struct\n" + "{\n" + " unsigned modulator_E862, carrier_E862; // See below\n" + " unsigned char modulator_40, carrier_40; // KSL/attenuation settings\n" + " unsigned char feedconn; // Feedback/connection bits for the channel\n" + " signed char finetune; // Finetune\n" + "} adl[] =\n"*/ + "const adldata adl[%u] =\n" + "{ // ,---------+-------- Wave select settings\n" + " // | ,-------ч-+------ Sustain/release rates\n" + " // | | ,-----ч-ч-+---- Attack/decay rates\n" + " // | | | ,---ч-ч-ч-+-- AM/VIB/EG/KSR/Multiple bits\n" + " // | | | | | | | |\n" + " // | | | | | | | | ,----+-- KSL/attenuation settings\n" + " // | | | | | | | | | | ,----- Feedback/connection bits\n" + " // | | | | | | | | | | | ,----- Fine tune\n\n" + " // | | | | | | | | | | | |\n" + " // | | | | | | | | | | | |\n", (unsigned)insdatatab.size()); + + for(size_t b = insdatatab.size(), c = 0; c < b; ++c) + { + for(std::map > > + ::const_iterator + i = insdatatab.begin(); + i != insdatatab.end(); + ++i) + { + if(i->second.first != c) continue; + fprintf(outFile, " { "); + + uint32_t carrier_E862 = + uint32_t(i->first.data[6] << 24) + + uint32_t(i->first.data[4] << 16) + + uint32_t(i->first.data[2] << 8) + + uint32_t(i->first.data[0] << 0); + uint32_t modulator_E862 = + uint32_t(i->first.data[7] << 24) + + uint32_t(i->first.data[5] << 16) + + uint32_t(i->first.data[3] << 8) + + uint32_t(i->first.data[1] << 0); + + fprintf(outFile, "0x%07X,0x%07X, 0x%02X,0x%02X, 0x%X, %+d", + carrier_E862, + modulator_E862, + i->first.data[8], + i->first.data[9], + i->first.data[10], + i->first.finetune); + + std::string names; + for(std::set::const_iterator + j = i->second.second.begin(); + j != i->second.second.end(); + ++j) + { + if(!names.empty()) names += "; "; + if((*j)[0] == '\377') + names += j->substr(1); + else + names += *j; + } + fprintf(outFile, " }, // %u: %s\n", (unsigned)c, names.c_str()); + } + } + fprintf(outFile, "};\n"); + } + + /*fprintf(outFile, "static const struct\n" + "{\n" + " unsigned short adlno1, adlno2;\n" + " unsigned char tone;\n" + " unsigned char flags;\n" + " long ms_sound_kon; // Number of milliseconds it produces sound;\n" + " long ms_sound_koff;\n" + "} adlins[] =\n");*/ + + fprintf(outFile, "const struct adlinsdata adlins[%u] =\n", (unsigned)instab.size()); + fprintf(outFile, "{\n"); + + MeasureThreaded measureCounter; + { + std::printf("Beginning to generate measures data... (Hardware concurrency: %d)\n", std::thread::hardware_concurrency()); + std::fflush(stdout); + measureCounter.LoadCache("fm_banks/adldata-cache.dat"); + measureCounter.m_total = instab.size(); + for(size_t b = instab.size(), c = 0; c < b; ++c) + { + for(std::map > >::const_iterator i = instab.begin(); i != instab.end(); ++i) + { + if(i->second.first != c) continue; + measureCounter.run(i); + } + } + std::fflush(stdout); + measureCounter.waitAll(); + measureCounter.SaveCache("fm_banks/adldata-cache.dat"); + } + + std::printf("Writing generated measure data...\n"); + std::fflush(stdout); + + std::vector adlins_flags; + + for(size_t b = instab.size(), c = 0; c < b; ++c) + for(std::map > > + ::const_iterator + i = instab.begin(); + i != instab.end(); + ++i) + { + if(i->second.first != c) continue; + //DurationInfo info = MeasureDurations(i->first); + MeasureThreaded::DurationInfoCache::iterator indo_i = measureCounter.m_durationInfo.find(i->first); + DurationInfo info = indo_i->second; + { + if(info.peak_amplitude_time == 0) + { + fprintf(outFile, + " // Amplitude begins at %6.1f,\n" + " // fades to 20%% at %.1fs, keyoff fades to 20%% in %.1fs.\n", + info.begin_amplitude, + info.quarter_amplitude_time / double(info.interval), + info.keyoff_out_time / double(info.interval)); + } + else + { + fprintf(outFile, + " // Amplitude begins at %6.1f, peaks %6.1f at %.1fs,\n" + " // fades to 20%% at %.1fs, keyoff fades to 20%% in %.1fs.\n", + info.begin_amplitude, + info.peak_amplitude_value, + info.peak_amplitude_time / double(info.interval), + info.quarter_amplitude_time / double(info.interval), + info.keyoff_out_time / double(info.interval)); + } + } + + unsigned flags = (i->first.pseudo4op ? 1 : 0) | (info.nosound ? 2 : 0); + + fprintf(outFile, " {"); + fprintf(outFile, "%4d,%4d,%3d, %d, %6ld,%6ld,%lf", + (unsigned) i->first.insno1, + (unsigned) i->first.insno2, + (int)(i->first.notenum), + flags, + info.ms_sound_kon, + info.ms_sound_koff, + i->first.voice2_fine_tune); + std::string names; + for(std::set::const_iterator + j = i->second.second.begin(); + j != i->second.second.end(); + ++j) + { + if(!names.empty()) names += "; "; + if((*j)[0] == '\377') + names += j->substr(1); + else + names += *j; + } + fprintf(outFile, " }, // %u: %s\n\n", (unsigned)c, names.c_str()); + fflush(outFile); + adlins_flags.push_back(flags); + } + fprintf(outFile, "};\n\n"); + + + printf("Writing banks data...\n"); + fflush(stdout); + + //fprintf(outFile, "static const unsigned short banks[][256] =\n"); + #ifdef HARD_BANKS + const unsigned bankcount = sizeof(banknames) / sizeof(*banknames); + #else + const size_t bankcount = banknames.size(); + #endif + + size_t nosound = InsertNoSoundIns(); + + std::map > bank_data; + for(size_t bank = 0; bank < bankcount; ++bank) + { + //bool redundant = true; + std::vector data(256); + for(size_t p = 0; p < 256; ++p) + { + size_t v = progs[bank][p]; + if(v == 0 || (adlins_flags[v - 1] & 2)) + v = nosound; // Blank.in + else + v -= 1; + data[p] = v; + } + bank_data[bank] = data; + } + std::set listed; + + fprintf(outFile, + "\n\n//Returns total number of generated banks\n" + "int maxAdlBanks()\n" + "{" + " return %u;\n" + "}\n\n" + "const char* const banknames[%u] =\n", (unsigned int)bankcount, (unsigned int)bankcount); + fprintf(outFile, "{\n"); + for(unsigned bank = 0; bank < bankcount; ++bank) + fprintf(outFile, " \"%s\",\n", banknames[bank].c_str()); + fprintf(outFile, "};\n"); + + fprintf(outFile, "const unsigned short banks[%u][256] =\n", (unsigned int)bankcount); + fprintf(outFile, "{\n"); + for(unsigned bank = 0; bank < bankcount; ++bank) + { + fprintf(outFile, " { // bank %u, %s\n", bank, banknames[bank].c_str()); + bool redundant = true; + for(unsigned p = 0; p < 256; ++p) + { + size_t v = bank_data[bank][p]; + if(listed.find(v) == listed.end()) + { + listed.insert(v); + redundant = false; + } + fprintf(outFile, "%4d,", (unsigned int)v); + if(p % 16 == 15) fprintf(outFile, "\n"); + } + fprintf(outFile, " },\n"); + if(redundant) + { + fprintf(outFile, " // Bank %u defines nothing new.\n", bank); + for(unsigned refbank = 0; refbank < bank; ++refbank) + { + bool match = true; + for(unsigned p = 0; p < 256; ++p) + if(bank_data[bank][p] != nosound + && bank_data[bank][p] != bank_data[refbank][p]) + { + match = false; + break; + } + if(match) + fprintf(outFile, " // Bank %u is just a subset of bank %u!\n", + bank, refbank); + } + } + } + + fprintf(outFile, "};\n"); + fflush(outFile); + fclose(outFile); + + printf("Generation of ADLMIDI data has been completed!\n"); + fflush(stdout); +} diff --git a/utils/gen_adldata/gen_adldata.pro b/utils/gen_adldata/gen_adldata.pro new file mode 100644 index 0000000..74c504e --- /dev/null +++ b/utils/gen_adldata/gen_adldata.pro @@ -0,0 +1,38 @@ +TEMPLATE=app +CONFIG-=qt +CONFIG+=console +TARGET=gen_adldata +DESTDIR=$$PWD/../../bin +CONFIG += c++11 + +include($$PWD/ini/IniProcessor.pri) + +#DEFINES += ADLMIDI_USE_DOSBOX_OPL + +QMAKE_CXXFLAGS_RELEASE += -O3 -finline-functions +LIBS += -lpthread + +HEADERS += \ + midi_inst_list.h \ + ../nukedopl3.h \ + ../dbopl.h \ + progs_cache.h \ + file_formats/load_bnk.h \ + file_formats/load_bnk2.h \ + file_formats/load_op2.h \ + file_formats/load_ail.h \ + file_formats/load_ibk.h \ + file_formats/load_jv.h \ + file_formats/load_tmb.h \ + file_formats/load_bisqwit.h \ + file_formats/load_wopl.h \ + measurer.h \ + file_formats/common.h + +SOURCES += \ + gen_adldata.cc \ + ../nukedopl3.c \ + ../dbopl.cpp \ + progs_cache.cpp \ + measurer.cpp + diff --git a/utils/gen_adldata/ini/IniProcessor.pri b/utils/gen_adldata/ini/IniProcessor.pri new file mode 100644 index 0000000..cdadb59 --- /dev/null +++ b/utils/gen_adldata/ini/IniProcessor.pri @@ -0,0 +1,10 @@ + +INCLUDEPATH += $$PWD + +HEADERS += \ + $$PWD/ini_processing.h \ + $$PWD/ini_processing_variant.h \ + +SOURCES += \ + $$PWD/ini_processing.cpp + diff --git a/utils/gen_adldata/ini/ini_processing.cpp b/utils/gen_adldata/ini/ini_processing.cpp new file mode 100644 index 0000000..2f15821 --- /dev/null +++ b/utils/gen_adldata/ini/ini_processing.cpp @@ -0,0 +1,1385 @@ +/* +INI Processor - a small library which allows you parsing INI-files + +Copyright (c) 2017 Vitaliy Novichkov + +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. + +*/ + +//#define USE_FILE_MAPPER + +/* Stop parsing on first error (default is to keep parsing). */ +//#define INI_STOP_ON_FIRST_ERROR + +#include "ini_processing.h" +#include +#include +#include +#include +#include +#include +#include +#ifdef _WIN32 +#include +#endif + +#ifdef USE_FILE_MAPPER +/*****Replace this with right path to file mapper class*****/ +#include "../fileMapper/file_mapper.h" +#endif + +static const unsigned char utfbom[3] = {0xEF, 0xBB, 0xBF}; + +enum { Space = 0x01, Special = 0x02, INIParamEq = 0x04 }; + +static const unsigned char charTraits[256] = +{ + // Space: '\t', '\n', '\r', ' ' + // Special: '\n', '\r', '"', ';', '=', '\\' + // INIParamEq: ':', '=' + + 0, 0, 0, 0, 0, 0, 0, 0, 0, Space, Space | Special, 0, 0, Space | Special, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Space, 0, Special, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, INIParamEq, + Special, 0, Special | INIParamEq, 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, Special, 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, 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, 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 +}; + +#if 0//for speed comparison who faster - macro or inline function. Seems speeds are same +#define IS_SPACE(c) (charTraits[static_cast(c)] & Space) +#define IS_SPECIAL(c) (charTraits[static_cast(c)] & Special) +#define IS_INIEQUAL(c) (charTraits[static_cast(c)] & INIParamEq) +#else +inline unsigned char IS_SPACE(char &c) +{ + return (charTraits[static_cast(c)] & Space); +} +inline unsigned char IS_SPECIAL(char &c) +{ + return (charTraits[static_cast(c)] & Special); +} +inline unsigned char IS_INIEQUAL(char &c) +{ + return (charTraits[static_cast(c)] & INIParamEq); +} +#endif + +/* Strip whitespace chars off end of given string, in place. Return s. */ +inline char *rstrip(char *s) +{ + char *p = s + strlen(s); + + while(p > s && IS_SPACE(*--p)) + *p = '\0'; + + return s; +} + +/* Return pointer to first non-whitespace char in given string. */ +inline char *lskip(char *s) +{ + while(*s && IS_SPACE(*s)) + s++; + + return reinterpret_cast(s); +} + +inline char *lrtrim(char *s) +{ + while(*s && IS_SPACE(*s)) + s++; + + char *p = s + strlen(s); + + while(p > s && IS_SPACE(*--p)) + *p = '\0'; + + return s; +} + +/* Return pointer to first char c or ';' comment in given string, or pointer to + null at end of string if neither found. ';' must be prefixed by a whitespace + character to register as a comment. */ +inline char *find_char_or_comment(char *s, char c) +{ + unsigned char was_whitespace = 0; + + while(*s && *s != c && !(was_whitespace && *s == ';')) + { + was_whitespace = IS_SPACE(*s); + s++; + } + + return s; +} + +inline char *find_inieq_or_comment(char *s) +{ + unsigned char was_whitespace = 0; + + while(*s && (!IS_INIEQUAL(*s)) && !(was_whitespace && *s == ';')) + { + was_whitespace = IS_SPACE(*s); + s++; + } + + return s; +} + +inline char *removeQuotes(char *begin, char *end) +{ + if((*begin == '\0') || (begin == end)) + return begin; + + if((*begin == '"') && (begin + 1 != end)) + begin++; + else + return begin; + + if(*(end - 1) == '"') + *(end - 1) = '\0'; + + return begin; +} + +inline char *unescapeString(char* str) +{ + char *src, *dst; + src = str; + dst = str; + while(*src) + { + if(*src == '\\') + { + src++; + switch(*src) + { + case 'n': *dst = '\n'; break; + case 'r': *dst = '\r'; break; + case 't': *dst = '\t'; break; + default: *dst = *src; break; + } + } + else + if(src != dst) + { + *dst = *src; + } + src++; dst++; + } + *dst = '\0'; + return str; +} + +//Remove comment line from a tail of value +inline void skipcomment(char *value) +{ + unsigned char quoteDepth = 0; + + while(*value) + { + if(quoteDepth > 0) + { + if(*value == '\\') + { + value++; + continue; + } + + if(*value == '"') + --quoteDepth; + } + else if(*value == '"') + ++quoteDepth; + + if((quoteDepth == 0) && (*value == ';')) + { + *value = '\0'; + break; + } + + value++; + } +} + +inline bool memfgets(char *&line, char *data, char *&pos, char *end) +{ + line = pos; + + while(pos != end) + { + if(*pos == '\n') + { + if((pos > data) && (*(pos - 1) == '\r')) + *((pos++) - 1) = '\0';//Support CRLF too + else + *(pos++) = '\0'; + + break; + } + + ++pos; + } + + return (pos != line); + //EOF is a moment when position wasn't changed. + //If do check "pos != end", will be an inability to read last line. + //this logic allows detect true EOF when line is really eof +} + +/* See documentation in header file. */ +bool IniProcessing::parseHelper(char *data, size_t size) +{ + char *section = nullptr; + #if defined(INI_ALLOW_MULTILINE) + char *prev_name = nullptr; + #endif + char *start; + char *end; + char *name; + char *value; + int lineno = 0; + int error = 0; + char *line; + char *pos_end = data + size; + char *pos_cur = data; + params::IniKeys *recentKeys = nullptr; + + /* Scan through file line by line */ + //while (fgets(line, INI_MAX_LINE, file) != NULL) + while(memfgets(line, data, pos_cur, pos_end)) + { + lineno++; + start = line; + + if((lineno == 1) && (size >= 3) && (memcmp(start, utfbom, 3) == 0)) + start += 3; + + start = lrtrim(start); + + if(!*start)//if empty line - skip it away! + continue; + + switch(*start) + { + case ';': + case '#': + //if (*start == ';' || *start == '#') { + // /* Per Python ConfigParser, allow '#' comments at start of line */ + //} + continue; + + case '[': + { + /* A "[section]" line */ + end = find_char_or_comment(start + 1, ']'); + + if(*end == ']') + { + *end = '\0'; + section = start + 1; + //#if defined(INI_ALLOW_MULTILINE) + // prev_name = nullptr; + //#endif + recentKeys = &m_params.iniData[section]; + } + else if(!error) + { + /* No ']' found on section line */ + m_params.errorCode = ERR_SECTION_SYNTAX; + error = lineno; + } + } + break; + + default: + { + /* Not a comment, must be a name[=:]value pair */ + end = find_inieq_or_comment(start); + + if(IS_INIEQUAL(*end)) + { + *end = '\0'; + name = rstrip(start); + value = lskip(end + 1); + end = find_char_or_comment(value, '\0'); + + #ifndef CASE_SENSITIVE_KEYS + for(char *iter = name; *iter != '\0'; ++iter) + *iter = (char)tolower(*iter); + #endif + + if(*end == ';') + *end = '\0'; + + rstrip(value); + { + char *v = value; + skipcomment(v); + v = rstrip(v); + + if(!recentKeys) + recentKeys = &m_params.iniData["General"]; + + #ifdef INIDEBUG + printf("-> [%s]; %s = %s\n", section, name, v); + #endif + (*recentKeys)[name] = unescapeString( removeQuotes(v, v + strlen(v)) ); + } + } + else if(!error) + { + /* No '=' or ':' found on name[=:]value line */ + m_params.errorCode = ERR_KEY_SYNTAX; + error = lineno; + } + + break; + } + }//switch(*start) + + #if defined(INI_STOP_ON_FIRST_ERROR) + + if(error) + break; + + #endif + } + + m_params.lineWithError = error; + return (error == 0); +} + +/* See documentation in header file. */ +bool IniProcessing::parseFile(const char *filename) +{ + bool valid = true; + char *tmp = nullptr; + #ifdef USE_FILE_MAPPER + //By mystical reasons, reading whole file form fread() is faster than mapper :-P + PGE_FileMapper file(filename); + + if(!file.data) + { + m_params.errorCode = ERR_NOFILE; + return -1; + } + + tmp = reinterpret_cast(malloc(static_cast(file.size + 1))); + + if(!tmp) + { + m_params.errorCode = ERR_NO_MEMORY; + return false; + } + + memcpy(tmp, file.data, static_cast(file.size)); + *(tmp + file.size) = '\0';//null terminate last line + valid = ini_parse_file(tmp, static_cast(file.size)); + #else + #ifdef _WIN32 + //Convert UTF8 file path into UTF16 to support non-ASCII paths on Windows + std::wstring dest; + dest.resize(std::strlen(filename)); + int newSize = MultiByteToWideChar(CP_UTF8, + 0, + filename, + dest.size(), + (wchar_t *)dest.c_str(), + dest.size()); + dest.resize(newSize); + FILE *cFile = _wfopen(dest.c_str(), L"rb"); + #else + FILE *cFile = fopen(filename, "rb"); + #endif + + if(!cFile) + { + m_params.errorCode = ERR_NOFILE; + return false; + } + + fseek(cFile, 0, SEEK_END); + ssize_t size = static_cast(ftell(cFile)); + if(size < 0) + { + m_params.errorCode = ERR_KEY_SYNTAX; + fclose(cFile); + return false; + } + fseek(cFile, 0, SEEK_SET); + tmp = reinterpret_cast(malloc(static_cast(size + 1))); + if(!tmp) + { + fclose(cFile); + m_params.errorCode = ERR_NO_MEMORY; + return false; + } + + if(fread(tmp, 1, static_cast(size), cFile) != static_cast(size)) + valid = false; + + fclose(cFile); + if(valid) + { + *(tmp + size) = '\0';//null terminate last line + try + { + valid = parseHelper(tmp, static_cast(size)); + } + catch(...) + { + valid = false; + m_params.errorCode = ERR_SECTION_SYNTAX; + } + } + #endif + + free(tmp); + return valid; +} + +bool IniProcessing::parseMemory(char *mem, size_t size) +{ + bool valid = true; + char *tmp = nullptr; + tmp = reinterpret_cast(malloc(size + 1)); + + if(!tmp) + { + m_params.errorCode = ERR_NO_MEMORY; + return false; + } + + memcpy(tmp, mem, static_cast(size)); + *(tmp + size) = '\0';//null terminate last line + valid = parseHelper(tmp, size); + free(tmp); + return valid; +} + + +IniProcessing::IniProcessing() : + m_params{"", false, -1, ERR_OK, false, params::IniSections(), nullptr, ""} +{} + +IniProcessing::IniProcessing(const char *iniFileName, int) : + m_params{iniFileName, false, -1, ERR_OK, false, params::IniSections(), nullptr, ""} +{ + open(iniFileName); +} + +IniProcessing::IniProcessing(const std::string &iniFileName, int) : + m_params{iniFileName, false, -1, ERR_OK, false, params::IniSections(), nullptr, ""} +{ + open(iniFileName); +} + +#ifdef INI_PROCESSING_ALLOW_QT_TYPES +IniProcessing::IniProcessing(const QString &iniFileName, int) : + m_params{iniFileName.toStdString(), false, -1, ERR_OK, false, params::IniSections(), nullptr, ""} +{ + open(m_params.filePath); +} +#endif + +IniProcessing::IniProcessing(char *memory, size_t size): + m_params{"", false, -1, ERR_OK, false, params::IniSections(), nullptr, ""} +{ + openMem(memory, size); +} + +IniProcessing::IniProcessing(const IniProcessing &ip) : + m_params(ip.m_params) +{} + +bool IniProcessing::open(const std::string &iniFileName) +{ + std::setlocale(LC_NUMERIC, "C"); + + if(!iniFileName.empty()) + { + close(); + m_params.errorCode = ERR_OK; + m_params.filePath = iniFileName; + bool res = parseFile(m_params.filePath.c_str()); + #ifdef INIDEBUG + + if(res) + printf("\n==========WOOHOO!!!==============\n\n"); + else + printf("\n==========OOOUCH!!!==============\n\n"); + + #endif + m_params.opened = res; + return res; + } + + m_params.errorCode = ERR_NOFILE; + return false; +} + +bool IniProcessing::openMem(char *memory, size_t size) +{ + std::setlocale(LC_NUMERIC, "C"); + + if((memory != nullptr) && (size > 0)) + { + close(); + m_params.errorCode = ERR_OK; + m_params.filePath.clear(); + bool res = parseMemory(memory, size); + m_params.opened = res; + return res; + } + + m_params.errorCode = ERR_NOFILE; + return false; +} + +void IniProcessing::close() +{ + m_params.errorCode = ERR_OK; + m_params.iniData.clear(); + m_params.opened = false; + m_params.lineWithError = -1; +} + +IniProcessing::ErrCode IniProcessing::lastError() +{ + return m_params.errorCode; +} + +int IniProcessing::lineWithError() +{ + return m_params.lineWithError; +} + +bool IniProcessing::isOpened() +{ + return m_params.opened; +} + +bool IniProcessing::beginGroup(const std::string &groupName) +{ + //Keep the group name. If not exist, will be created on value write + m_params.currentGroupName = groupName; + + params::IniSections::iterator e = m_params.iniData.find(groupName); + + if(e == m_params.iniData.end()) + return false; + + params::IniKeys &k = e->second; + m_params.currentGroup = &k; + return true; +} + +bool IniProcessing::contains(const std::string &groupName) +{ + if(!m_params.opened) + return false; + + params::IniSections::iterator e = m_params.iniData.find(groupName); + return (e != m_params.iniData.end()); +} + +std::string IniProcessing::fileName() +{ + return m_params.filePath; +} + +std::string IniProcessing::group() +{ + return m_params.currentGroupName; +} + +std::vector IniProcessing::childGroups() +{ + std::vector groups; + groups.reserve(m_params.iniData.size()); + for(params::IniSections::iterator e = m_params.iniData.begin(); + e != m_params.iniData.end(); + e++) + { + groups.push_back(e->first); + } + return groups; +} + +bool IniProcessing::hasKey(const std::string &keyName) +{ + if(!m_params.opened) + return false; + + if(!m_params.currentGroup) + return false; + + params::IniKeys::iterator e = m_params.currentGroup->find(keyName); + return (e != m_params.currentGroup->end()); +} + +std::vector IniProcessing::allKeys() +{ + std::vector keys; + if(!m_params.opened) + return keys; + if(!m_params.currentGroup) + return keys; + + keys.reserve(m_params.currentGroup->size()); + + for(params::IniKeys::iterator it = m_params.currentGroup->begin(); + it != m_params.currentGroup->end(); + it++) + { + keys.push_back( it->first ); + } + + return keys; +} + +void IniProcessing::endGroup() +{ + m_params.currentGroup = nullptr; + m_params.currentGroupName.clear(); +} + +void IniProcessing::read(const char *key, bool &dest, bool defVal) +{ + bool ok = false; + params::IniKeys::iterator e = readHelper(key, ok); + + if(!ok) + { + dest = defVal; + return; + } + + std::string &k = e->second; + size_t i = 0; + size_t ss = std::min(static_cast(4ul), k.size()); + char buff[4] = {0, 0, 0, 0}; + const char *pbufi = k.c_str(); + char *pbuff = buff; + + for(; i < ss; i++) + (*pbuff++) = static_cast(std::tolower(*pbufi++)); + + if(ss < 4) + { + if(ss == 0) + { + dest = false; + return; + } + + if(ss == 1) + { + dest = (buff[0] == '1'); + return; + } + + bool isNum = true; + isNum &= std::isdigit(buff[i]) || (buff[i] == '-') || (buff[i] == '+'); + + for(size_t i = 1; i < ss; i++) + isNum &= std::isdigit(buff[i]); + + if(isNum) + { + long num = std::strtol(buff, 0, 0); + dest = num != 0l; + return; + } + else + { + dest = (std::memcmp(buff, "yes", 3) == 0) || + (std::memcmp(buff, "on", 2) == 0); + return; + } + } + + if(std::memcmp(buff, "true", 4) == 0) + { + dest = true; + return; + } + + try + { + long num = std::strtol(buff, 0, 0); + dest = num != 0l; + return; + } + catch(...) + { + dest = false; + return; + } +} + +void IniProcessing::read(const char *key, unsigned char &dest, unsigned char defVal) +{ + bool ok = false; + params::IniKeys::iterator e = readHelper(key, ok); + + if(!ok) + { + dest = defVal; + return; + } + + std::string &k = e->second; + + if(k.size() >= 1) + dest = static_cast(k[0]); + else + dest = defVal; +} + +void IniProcessing::read(const char *key, char &dest, char defVal) +{ + bool ok = false; + params::IniKeys::iterator e = readHelper(key, ok); + + if(!ok) + { + dest = defVal; + return; + } + + std::string &k = e->second; + + if(k.size() >= 1) + dest = k[0]; + else + dest = defVal; +} + +void IniProcessing::read(const char *key, unsigned short &dest, unsigned short defVal) +{ + bool ok = false; + params::IniKeys::iterator e = readHelper(key, ok); + + if(!ok) + { + dest = defVal; + return; + } + + dest = static_cast(std::strtoul(e->second.c_str(), nullptr, 0)); +} + +void IniProcessing::read(const char *key, short &dest, short defVal) +{ + bool ok = false; + params::IniKeys::iterator e = readHelper(key, ok); + + if(!ok) + { + dest = defVal; + return; + } + + dest = static_cast(std::strtol(e->second.c_str(), nullptr, 0)); +} + +void IniProcessing::read(const char *key, unsigned int &dest, unsigned int defVal) +{ + bool ok = false; + params::IniKeys::iterator e = readHelper(key, ok); + + if(!ok) + { + dest = defVal; + return; + } + + dest = static_cast(std::strtoul(e->second.c_str(), nullptr, 0)); +} + +void IniProcessing::read(const char *key, int &dest, int defVal) +{ + bool ok = false; + params::IniKeys::iterator e = readHelper(key, ok); + + if(!ok) + { + dest = defVal; + return; + } + + dest = static_cast(std::strtol(e->second.c_str(), nullptr, 0)); +} + +void IniProcessing::read(const char *key, unsigned long &dest, unsigned long defVal) +{ + bool ok = false; + params::IniKeys::iterator e = readHelper(key, ok); + + if(!ok) + { + dest = defVal; + return; + } + + dest = std::strtoul(e->second.c_str(), nullptr, 0); +} + +void IniProcessing::read(const char *key, long &dest, long defVal) +{ + bool ok = false; + params::IniKeys::iterator e = readHelper(key, ok); + + if(!ok) + { + dest = defVal; + return; + } + + dest = std::strtol(e->second.c_str(), nullptr, 0); +} + +void IniProcessing::read(const char *key, unsigned long long &dest, unsigned long long defVal) +{ + bool ok = false; + params::IniKeys::iterator e = readHelper(key, ok); + + if(!ok) + { + dest = defVal; + return; + } + + dest = std::strtoull(e->second.c_str(), nullptr, 0); +} + +void IniProcessing::read(const char *key, long long &dest, long long defVal) +{ + bool ok = false; + params::IniKeys::iterator e = readHelper(key, ok); + + if(!ok) + { + dest = defVal; + return; + } + + dest = std::strtoll(e->second.c_str(), nullptr, 0); +} + +void IniProcessing::read(const char *key, float &dest, float defVal) +{ + bool ok = false; + params::IniKeys::iterator e = readHelper(key, ok); + if(!ok) + { + dest = defVal; + return; + } + dest = std::strtof(e->second.c_str(), nullptr); +} + +void IniProcessing::read(const char *key, double &dest, double defVal) +{ + bool ok = false; + params::IniKeys::iterator e = readHelper(key, ok); + + if(!ok) + { + dest = defVal; + return; + } + dest = std::strtod(e->second.c_str(), nullptr); +} + +void IniProcessing::read(const char *key, long double &dest, long double defVal) +{ + bool ok = false; + params::IniKeys::iterator e = readHelper(key, ok); + if(!ok) + { + dest = defVal; + return; + } + dest = std::strtold(e->second.c_str(), nullptr); +} + +void IniProcessing::read(const char *key, std::string &dest, const std::string &defVal) +{ + bool ok = false; + params::IniKeys::iterator e = readHelper(key, ok); + + if(!ok) + { + dest = defVal; + return; + } + + dest = e->second; +} + +#ifdef INI_PROCESSING_ALLOW_QT_TYPES +void IniProcessing::read(const char *key, QString &dest, const QString &defVal) +{ + bool ok = false; + params::IniKeys::iterator e = readHelper(key, ok); + + if(!ok) + { + dest = defVal; + return; + } + + dest = QString::fromStdString(e->second); +} +#endif + +template +inline void StrToNumVectorHelper(const std::string &source, TList &dest, const typename TList::value_type &def) +{ + typedef typename TList::value_type T; + dest.clear(); + + if(!source.empty()) + { + std::stringstream ss(source); + std::string item; + while(std::getline(ss, item, ',')) + { + std::remove(item.begin(), item.end(), ' '); + try + { + if(std::is_same::value || + std::is_same::value || + std::is_same::value) + dest.push_back(static_cast(std::strtol(item.c_str(), NULL, 0))); + else if(std::is_same::value || + std::is_same::value || + std::is_same::value) + dest.push_back(static_cast(std::strtoul(item.c_str(), NULL, 0))); + else if(std::is_same::value) + dest.push_back(std::strtof(item.c_str(), NULL)); + else + dest.push_back(std::strtod(item.c_str(), NULL)); + } + catch(...) + { + dest.pop_back(); + } + } + + if(dest.empty()) + dest.push_back(def); + } + else + dest.push_back(def); +} + +template +void readNumArrHelper(IniProcessing *self, const char *key, TList &dest, const TList &defVal) +{ + bool ok = false; + IniProcessing::params::IniKeys::iterator e = self->readHelper(key, ok); + + if(!ok) + { + dest = defVal; + return; + } + + StrToNumVectorHelper(e->second, dest, static_cast(0)); +} + +void IniProcessing::read(const char *key, std::vector &dest, const std::vector &defVal) +{ + readNumArrHelper, unsigned short>(this, key, dest, defVal); +} +void IniProcessing::read(const char *key, std::vector &dest, const std::vector &defVal) +{ + readNumArrHelper, short>(this, key, dest, defVal); +} +void IniProcessing::read(const char *key, std::vector &dest, const std::vector &defVal) +{ + readNumArrHelper, unsigned int>(this, key, dest, defVal); +} +void IniProcessing::read(const char *key, std::vector &dest, const std::vector &defVal) +{ + readNumArrHelper, int>(this, key, dest, defVal); +} +void IniProcessing::read(const char *key, std::vector &dest, const std::vector &defVal) +{ + readNumArrHelper, unsigned long>(this, key, dest, defVal); +} +void IniProcessing::read(const char *key, std::vector &dest, const std::vector &defVal) +{ + readNumArrHelper, long>(this, key, dest, defVal); +} +void IniProcessing::read(const char *key, std::vector &dest, const std::vector &defVal) +{ + readNumArrHelper, unsigned long long>(this, key, dest, defVal); +} +void IniProcessing::read(const char *key, std::vector &dest, const std::vector &defVal) +{ + readNumArrHelper, long long>(this, key, dest, defVal); +} +void IniProcessing::read(const char *key, std::vector &dest, const std::vector &defVal) +{ + readNumArrHelper, float>(this, key, dest, defVal); +} +void IniProcessing::read(const char *key, std::vector &dest, const std::vector &defVal) +{ + readNumArrHelper, double>(this, key, dest, defVal); +} + +void IniProcessing::read(const char *key, std::vector &dest, const std::vector &defVal) +{ + readNumArrHelper, long double>(this, key, dest, defVal); +} + +#ifdef INI_PROCESSING_ALLOW_QT_TYPES +void IniProcessing::read(const char *key, QList &dest, const QList &defVal) +{ + readNumArrHelper, short>(this, key, dest, defVal); +} + +void IniProcessing::read(const char *key, QList &dest, const QList &defVal) +{ + readNumArrHelper, unsigned short>(this, key, dest, defVal); +} + +void IniProcessing::read(const char *key, QList &dest, const QList &defVal) +{ + readNumArrHelper, int>(this, key, dest, defVal); +} +void IniProcessing::read(const char *key, QList &dest, const QList &defVal) +{ + readNumArrHelper, unsigned int>(this, key, dest, defVal); +} +void IniProcessing::read(const char *key, QList &dest, const QList &defVal) +{ + readNumArrHelper, long>(this, key, dest, defVal); +} +void IniProcessing::read(const char *key, QList &dest, const QList &defVal) +{ + readNumArrHelper, unsigned long>(this, key, dest, defVal); +} +void IniProcessing::read(const char *key, QList &dest, const QList &defVal) +{ + readNumArrHelper, long long>(this, key, dest, defVal); +} +void IniProcessing::read(const char *key, QList &dest, const QList &defVal) +{ + readNumArrHelper, unsigned long long>(this, key, dest, defVal); +} +void IniProcessing::read(const char *key, QList &dest, const QList &defVal) +{ + readNumArrHelper, float>(this, key, dest, defVal); +} +void IniProcessing::read(const char *key, QList &dest, const QList &defVal) +{ + readNumArrHelper, double>(this, key, dest, defVal); +} + +void IniProcessing::read(const char *key, QList &dest, const QList &defVal) +{ + readNumArrHelper, long double>(this, key, dest, defVal); +} + +void IniProcessing::read(const char *key, QVector &dest, const QVector &defVal) +{ + readNumArrHelper, short>(this, key, dest, defVal); +} +void IniProcessing::read(const char *key, QVector &dest, const QVector &defVal) +{ + readNumArrHelper, unsigned short>(this, key, dest, defVal); +} +void IniProcessing::read(const char *key, QVector &dest, const QVector &defVal) +{ + readNumArrHelper, int>(this, key, dest, defVal); +} +void IniProcessing::read(const char *key, QVector &dest, const QVector &defVal) +{ + readNumArrHelper, unsigned int>(this, key, dest, defVal); +} +void IniProcessing::read(const char *key, QVector &dest, const QVector &defVal) +{ + readNumArrHelper, long>(this, key, dest, defVal); +} +void IniProcessing::read(const char *key, QVector &dest, const QVector &defVal) +{ + readNumArrHelper, unsigned long>(this, key, dest, defVal); +} +void IniProcessing::read(const char *key, QVector &dest, const QVector &defVal) +{ + readNumArrHelper, long long>(this, key, dest, defVal); +} +void IniProcessing::read(const char *key, QVector &dest, const QVector &defVal) +{ + readNumArrHelper, unsigned long long>(this, key, dest, defVal); +} +void IniProcessing::read(const char *key, QVector &dest, const QVector &defVal) +{ + readNumArrHelper, float>(this, key, dest, defVal); +} +void IniProcessing::read(const char *key, QVector &dest, const QVector &defVal) +{ + readNumArrHelper, double>(this, key, dest, defVal); +} + +void IniProcessing::read(const char *key, QVector &dest, const QVector &defVal) +{ + readNumArrHelper, long double>(this, key, dest, defVal); +} +#endif + +IniProcessingVariant IniProcessing::value(const char *key, const IniProcessingVariant &defVal) +{ + bool ok = false; + params::IniKeys::iterator e = readHelper(key, ok); + + if(!ok) + return defVal; + + std::string &k = e->second; + return IniProcessingVariant(&k); +} + +void IniProcessing::writeIniParam(const char *key, const std::string &value) +{ + if(m_params.currentGroupName.empty()) + return; + + bool ok = false; + params::IniKeys::iterator e = readHelper(key, ok); + if(ok) + { + e->second = value; + } + else + { + if(!m_params.currentGroup) + { + m_params.iniData.insert({m_params.currentGroupName, params::IniKeys()}); + m_params.currentGroup = &m_params.iniData[m_params.currentGroupName]; + } + m_params.currentGroup->insert({std::string(key), value}); + //Mark as opened + m_params.opened = true; + } +} + +void IniProcessing::setValue(const char *key, unsigned short value) +{ + writeIniParam(key, std::to_string(value)); +} + +void IniProcessing::setValue(const char *key, short value) +{ + writeIniParam(key, std::to_string(value)); +} + +void IniProcessing::setValue(const char *key, unsigned int value) +{ + writeIniParam(key, std::to_string(value)); +} + +void IniProcessing::setValue(const char *key, int value) +{ + writeIniParam(key, std::to_string(value)); +} + +void IniProcessing::setValue(const char *key, unsigned long value) +{ + writeIniParam(key, std::to_string(value)); +} + +void IniProcessing::setValue(const char *key, long value) +{ + writeIniParam(key, std::to_string(value)); +} + +void IniProcessing::setValue(const char *key, unsigned long long value) +{ + writeIniParam(key, std::to_string(value)); +} + +void IniProcessing::setValue(const char *key, long long value) +{ + writeIniParam(key, std::to_string(value)); +} + +void IniProcessing::setValue(const char *key, float value) +{ + writeIniParam(key, IniProcessing::to_string_with_precision(value)); +} + +void IniProcessing::setValue(const char *key, double value) +{ + writeIniParam(key, IniProcessing::to_string_with_precision(value)); +} + +void IniProcessing::setValue(const char *key, long double value) +{ + writeIniParam(key, IniProcessing::to_string_with_precision(value)); +} + +void IniProcessing::setValue(const char *key, const char *value) +{ + writeIniParam(key, value); +} + +void IniProcessing::setValue(const char *key, const std::string &value) +{ + writeIniParam(key, value); +} + +#ifdef INI_PROCESSING_ALLOW_QT_TYPES +void IniProcessing::setValue(const char *key, const QString &value) +{ + writeIniParam(key, value.toStdString()); +} +#endif + +static inline bool isFloatValue(const std::string &str) +{ + enum State + { + ST_SIGN = 0, + ST_DOT, + ST_EXPONENT, + ST_EXPONENT_SIGN, + ST_TAIL + } st = ST_SIGN; + + for(const char &c : str) + { + if(!isdigit(c)) + { + switch(st) + { + case ST_SIGN: + if(c != '-') + return false; + st = ST_DOT; + continue; + case ST_DOT: + if(c != '.') + return false; + else + if((c == 'E') || (c == 'e')) + st = ST_EXPONENT_SIGN; + else + st = ST_EXPONENT; + continue; + case ST_EXPONENT: + if((c != 'E') && (c != 'e')) + return false; + st = ST_EXPONENT_SIGN; + continue; + case ST_EXPONENT_SIGN: + if(c != '-') + return false; + st = ST_TAIL; + continue; + case ST_TAIL: + return false; + } + return false; + } + else + { + if(st == ST_SIGN) + st = ST_DOT; + } + } + return true; +} + +bool IniProcessing::writeIniFile() +{ + #ifdef _WIN32 + //Convert UTF8 file path into UTF16 to support non-ASCII paths on Windows + std::wstring dest; + dest.resize(m_params.filePath.size()); + int newSize = MultiByteToWideChar(CP_UTF8, + 0, + m_params.filePath.c_str(), + dest.size(), + (wchar_t *)dest.c_str(), + dest.size()); + dest.resize(newSize); + FILE *cFile = _wfopen(dest.c_str(), L"wb"); + #else + FILE *cFile = fopen(m_params.filePath.c_str(), "wb"); + #endif + if(!cFile) + return false; + + for(params::IniSections::iterator group = m_params.iniData.begin(); + group != m_params.iniData.end(); + group++) + { + fprintf(cFile, "[%s]\n", group->first.c_str()); + for(params::IniKeys::iterator key = group->second.begin(); + key != group->second.end(); + key++) + { + if(isFloatValue(key->second)) + { + //Store as-is without quoting + fprintf(cFile, "%s = %s\n", key->first.c_str(), key->second.c_str()); + } + else + { + //Set escape quotes and put the string with a quotes + std::string &s = key->second; + std::string escaped; + escaped.reserve(s.length() * 2); + for(char &c : s) + { + switch(c) + { + case '\n': escaped += "\\n"; break; + case '\r': escaped += "\\r"; break; + case '\t': escaped += "\\t"; break; + default: + if((c == '\\') || (c == '"')) + escaped.push_back('\\'); + escaped.push_back(c); + } + } + fprintf(cFile, "%s = \"%s\"\n", key->first.c_str(), escaped.c_str()); + } + } + fprintf(cFile, "\n"); + fflush(cFile); + } + fclose(cFile); + return true; +} + diff --git a/utils/gen_adldata/ini/ini_processing.h b/utils/gen_adldata/ini/ini_processing.h new file mode 100644 index 0000000..52ab2e2 --- /dev/null +++ b/utils/gen_adldata/ini/ini_processing.h @@ -0,0 +1,677 @@ +/* +INI Processor - a small library which allows you parsing INI-files + +Copyright (c) 2017 Vitaliy Novichkov + +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 INIPROCESSING_H +#define INIPROCESSING_H + +#include +#include +#include +#include +#include +#ifdef INI_PROCESSING_ALLOW_QT_TYPES +#include +#include +#include +#endif + +#include "ini_processing_variant.h" + +/** + * @brief INI Processor - an utility which providing fast and flexible INI file parsing API + */ +class IniProcessing +{ +public: + /** + * @brief Available error codes + */ + enum ErrCode + { + //! Everything is fine + ERR_OK = 0, + //! File not found or memory pointer is null + ERR_NOFILE, + //! Invalid section declaration syntax + ERR_SECTION_SYNTAX, + //! Invalid key declaration syntax + ERR_KEY_SYNTAX, + //! No available memory + ERR_NO_MEMORY + }; + +private: + struct params + { + std::string filePath; + bool opened; + int lineWithError; + ErrCode errorCode; + bool modified; + typedef std::unordered_map IniKeys; + typedef std::unordered_map IniSections; + IniSections iniData; + IniKeys *currentGroup; + std::string currentGroupName; + } m_params; + + template + friend void readNumArrHelper(IniProcessing* self, const char *key, TList &dest, const TList &defVal); + + bool parseHelper(char *data, size_t size); + + bool parseFile(const char *filename); + bool parseMemory(char *mem, size_t size); + + inline params::IniKeys::iterator readHelper(const char *key, bool &ok) + { + if(!m_params.opened) + return params::IniKeys::iterator(); + + if(!m_params.currentGroup) + return params::IniKeys::iterator(); + + #ifndef CASE_SENSITIVE_KEYS + std::string key1(key); + for(char *iter = &key1[0]; *iter != '\0'; ++iter) + *iter = (char)tolower(*iter); + #endif + + params::IniKeys::iterator e = m_params.currentGroup->find(key1); + + if(e != m_params.currentGroup->end()) + ok = true; + + return e; + } + + void writeIniParam(const char *key, const std::string &value); + +public: + IniProcessing(); + IniProcessing(const char *iniFileName, int dummy = 0); + IniProcessing(const std::string &iniFileName, int dummy = 0); +#ifdef INI_PROCESSING_ALLOW_QT_TYPES + IniProcessing(const QString &iniFileName, int dummy = 0); +#endif + IniProcessing(char *memory, size_t size); + IniProcessing(const IniProcessing &ip); + + /** + * @brief Open INI-file from disk and parse it + * @param iniFileName full path to INI-file to parse + * @return true if INI file has been passed, false if any error happen + */ + bool open(const std::string &iniFileName); + + /** + * @brief Open raw INI-data from memory and parse it + * @param memory pointer to memory block + * @param size size of memory block to process + * @return + */ + bool openMem(char *memory, size_t size); + + /** + * @brief Clear all internal buffers and close the file + */ + void close(); + + /** + * @brief Returns last happen error code + * @return Error code + */ + ErrCode lastError(); + /** + * @brief Line number which contains error + * @return line number wit herror + */ + int lineWithError(); + + /** + * @brief State of INI Processor + * @return true if any file is opened + */ + bool isOpened(); + + /** + * @brief Select a section to process + * @param groupName name of section to process + * @return true if group exists and opened + */ + bool beginGroup(const std::string &groupName); + + /** + * @brief Is this INI file contains section of specific name + * @param groupName name of section + * @return true if section is exists + */ + bool contains(const std::string &groupName); + + /** + * @brief Currently opened file name + * @return path to currently opened file + */ + std::string fileName(); + + /** + * @brief Currently processing section + * @return name of current section + */ + std::string group(); + + /** + * @brief Get list of available groups + * @return Array of strings + */ + std::vector childGroups(); + + /** + * @brief Is current section contains specific key name + * @param keyName name of key + * @return true if key is presented in this section + */ + bool hasKey(const std::string &keyName); + + /** + * @brief Get list of available keys in current groul + * @return Array of strings + */ + std::vector allKeys(); + + /** + * @brief Release current section to choice another for process + */ + void endGroup(); + + /** + * @brief Retreive value by specific key and pass it via reference + * @param [_IN] key name of key with value to retrieved + * @param [_OUT] dest Reference to destination variable to store retrieved value + * @param [_IN] defVal Default value for case of non-existing key + */ + void read(const char *key, bool &dest, bool defVal); + /** + * @brief Retreive value by specific key and pass it via reference + * @param [_IN] key name of key with value to retrieved + * @param [_OUT] dest Reference to destination variable to store retrieved value + * @param [_IN] defVal Default value for case of non-existing key + */ + void read(const char *key, unsigned char &dest, unsigned char defVal); + /** + * @brief Retreive value by specific key and pass it via reference + * @param [_IN] key name of key with value to retrieved + * @param [_OUT] dest Reference to destination variable to store retrieved value + * @param [_IN] defVal Default value for case of non-existing key + */ + void read(const char *key, char &dest, char defVal); + /** + * @brief Retreive value by specific key and pass it via reference + * @param [_IN] key name of key with value to retrieved + * @param [_OUT] dest Reference to destination variable to store retrieved value + * @param [_IN] defVal Default value for case of non-existing key + */ + void read(const char *key, unsigned short &dest, unsigned short defVal); + /** + * @brief Retreive value by specific key and pass it via reference + * @param [_IN] key name of key with value to retrieved + * @param [_OUT] dest Reference to destination variable to store retrieved value + * @param [_IN] defVal Default value for case of non-existing key + */ + void read(const char *key, short &dest, short defVal); + /** + * @brief Retreive value by specific key and pass it via reference + * @param [_IN] key name of key with value to retrieved + * @param [_OUT] dest Reference to destination variable to store retrieved value + * @param [_IN] defVal Default value for case of non-existing key + */ + void read(const char *key, unsigned int &dest, unsigned int defVal); + /** + * @brief Retreive value by specific key and pass it via reference + * @param [_IN] key name of key with value to retrieved + * @param [_OUT] dest Reference to destination variable to store retrieved value + * @param [_IN] defVal Default value for case of non-existing key + */ + void read(const char *key, int &dest, int defVal); + /** + * @brief Retreive value by specific key and pass it via reference + * @param [_IN] key name of key with value to retrieved + * @param [_OUT] dest Reference to destination variable to store retrieved value + * @param [_IN] defVal Default value for case of non-existing key + */ + void read(const char *key, unsigned long &dest, unsigned long defVal); + /** + * @brief Retreive value by specific key and pass it via reference + * @param [_IN] key name of key with value to retrieved + * @param [_OUT] dest Reference to destination variable to store retrieved value + * @param [_IN] defVal Default value for case of non-existing key + */ + void read(const char *key, long &dest, long defVal); + /** + * @brief Retreive value by specific key and pass it via reference + * @param [_IN] key name of key with value to retrieved + * @param [_OUT] dest Reference to destination variable to store retrieved value + * @param [_IN] defVal Default value for case of non-existing key + */ + void read(const char *key, unsigned long long &dest, unsigned long long defVal); + /** + * @brief Retreive value by specific key and pass it via reference + * @param [_IN] key name of key with value to retrieved + * @param [_OUT] dest Reference to destination variable to store retrieved value + * @param [_IN] defVal Default value for case of non-existing key + */ + void read(const char *key, long long &dest, long long defVal); + /** + * @brief Retreive value by specific key and pass it via reference + * @param [_IN] key name of key with value to retrieved + * @param [_OUT] dest Reference to destination variable to store retrieved value + * @param [_IN] defVal Default value for case of non-existing key + */ + void read(const char *key, float &dest, float defVal); + /** + * @brief Retreive value by specific key and pass it via reference + * @param [_IN] key name of key with value to retrieved + * @param [_OUT] dest Reference to destination variable to store retrieved value + * @param [_IN] defVal Default value for case of non-existing key + */ + void read(const char *key, double &dest, double defVal); + /** + * @brief Retreive value by specific key and pass it via reference + * @param [_IN] key name of key with value to retrieved + * @param [_OUT] dest Reference to destination variable to store retrieved value + * @param [_IN] defVal Default value for case of non-existing key + */ + void read(const char *key, long double &dest, long double defVal); + /** + * @brief Retreive value by specific key and pass it via reference + * @param [_IN] key name of key with value to retrieved + * @param [_OUT] dest Reference to destination variable to store retrieved value + * @param [_IN] defVal Default value for case of non-existing key + */ + void read(const char *key, std::string &dest, const std::string &defVal); + + #ifdef INI_PROCESSING_ALLOW_QT_TYPES + /** + * @brief Retreive value by specific key and pass it via reference + * @param [_IN] key name of key with value to retrieved + * @param [_OUT] dest Reference to destination variable to store retrieved value + * @param [_IN] defVal Default value for case of non-existing key + */ + void read(const char *key, QString &dest, const QString &defVal); + #endif + + /** + * @brief Retreive value by specific key and pass it via reference + * @param [_IN] key name of key with value to retrieved + * @param [_OUT] dest Reference to destination variable to store retrieved value + * @param [_IN] defVal Default value for case of non-existing key + */ + void read(const char *key, std::vector &dest, const std::vector &defVal = std::vector()); + /** + * @brief Retreive value by specific key and pass it via reference + * @param [_IN] key name of key with value to retrieved + * @param [_OUT] dest Reference to destination variable to store retrieved value + * @param [_IN] defVal Default value for case of non-existing key + */ + void read(const char *key, std::vector &dest, const std::vector &defVal = std::vector()); + /** + * @brief Retreive value by specific key and pass it via reference + * @param [_IN] key name of key with value to retrieved + * @param [_OUT] dest Reference to destination variable to store retrieved value + * @param [_IN] defVal Default value for case of non-existing key + */ + void read(const char *key, std::vector &dest, const std::vector &defVal = std::vector()); + /** + * @brief Retreive value by specific key and pass it via reference + * @param [_IN] key name of key with value to retrieved + * @param [_OUT] dest Reference to destination variable to store retrieved value + * @param [_IN] defVal Default value for case of non-existing key + */ + void read(const char *key, std::vector &dest, const std::vector &defVal = std::vector()); + /** + * @brief Retreive value by specific key and pass it via reference + * @param [_IN] key name of key with value to retrieved + * @param [_OUT] dest Reference to destination variable to store retrieved value + * @param [_IN] defVal Default value for case of non-existing key + */ + void read(const char *key, std::vector &dest, const std::vector &defVal = std::vector()); + /** + * @brief Retreive value by specific key and pass it via reference + * @param [_IN] key name of key with value to retrieved + * @param [_OUT] dest Reference to destination variable to store retrieved value + * @param [_IN] defVal Default value for case of non-existing key + */ + void read(const char *key, std::vector &dest, const std::vector &defVal = std::vector()); + /** + * @brief Retreive value by specific key and pass it via reference + * @param [_IN] key name of key with value to retrieved + * @param [_OUT] dest Reference to destination variable to store retrieved value + * @param [_IN] defVal Default value for case of non-existing key + */ + void read(const char *key, std::vector &dest, const std::vector &defVal = std::vector()); + /** + * @brief Retreive value by specific key and pass it via reference + * @param [_IN] key name of key with value to retrieved + * @param [_OUT] dest Reference to destination variable to store retrieved value + * @param [_IN] defVal Default value for case of non-existing key + */ + void read(const char *key, std::vector &dest, const std::vector &defVal = std::vector()); + /** + * @brief Retreive value by specific key and pass it via reference + * @param [_IN] key name of key with value to retrieved + * @param [_OUT] dest Reference to destination variable to store retrieved value + * @param [_IN] defVal Default value for case of non-existing key + */ + void read(const char *key, std::vector &dest, const std::vector &defVal = std::vector()); + /** + * @brief Retreive value by specific key and pass it via reference + * @param [_IN] key name of key with value to retrieved + * @param [_OUT] dest Reference to destination variable to store retrieved value + * @param [_IN] defVal Default value for case of non-existing key + */ + void read(const char *key, std::vector &dest, const std::vector &defVal = std::vector()); + /** + * @brief Retreive value by specific key and pass it via reference + * @param [_IN] key name of key with value to retrieved + * @param [_OUT] dest Reference to destination variable to store retrieved value + * @param [_IN] defVal Default value for case of non-existing key + */ + void read(const char *key, std::vector &dest, const std::vector &defVal = std::vector()); + + #ifdef INI_PROCESSING_ALLOW_QT_TYPES + /** + * @brief Retreive value by specific key and pass it via reference + * @param [_IN] key name of key with value to retrieved + * @param [_OUT] dest Reference to destination variable to store retrieved value + * @param [_IN] defVal Default value for case of non-existing key + */ + void read(const char *key, QList &dest, const QList &defVal = QList()); + /** + * @brief Retreive value by specific key and pass it via reference + * @param [_IN] key name of key with value to retrieved + * @param [_OUT] dest Reference to destination variable to store retrieved value + * @param [_IN] defVal Default value for case of non-existing key + */ + void read(const char *key, QList &dest, const QList &defVal = QList()); + /** + * @brief Retreive value by specific key and pass it via reference + * @param [_IN] key name of key with value to retrieved + * @param [_OUT] dest Reference to destination variable to store retrieved value + * @param [_IN] defVal Default value for case of non-existing key + */ + void read(const char *key, QList &dest, const QList &defVal = QList()); + /** + * @brief Retreive value by specific key and pass it via reference + * @param [_IN] key name of key with value to retrieved + * @param [_OUT] dest Reference to destination variable to store retrieved value + * @param [_IN] defVal Default value for case of non-existing key + */ + void read(const char *key, QList &dest, const QList &defVal = QList()); + /** + * @brief Retreive value by specific key and pass it via reference + * @param [_IN] key name of key with value to retrieved + * @param [_OUT] dest Reference to destination variable to store retrieved value + * @param [_IN] defVal Default value for case of non-existing key + */ + void read(const char *key, QList &dest, const QList &defVal = QList()); + /** + * @brief Retreive value by specific key and pass it via reference + * @param [_IN] key name of key with value to retrieved + * @param [_OUT] dest Reference to destination variable to store retrieved value + * @param [_IN] defVal Default value for case of non-existing key + */ + void read(const char *key, QList &dest, const QList &defVal = QList()); + /** + * @brief Retreive value by specific key and pass it via reference + * @param [_IN] key name of key with value to retrieved + * @param [_OUT] dest Reference to destination variable to store retrieved value + * @param [_IN] defVal Default value for case of non-existing key + */ + void read(const char *key, QList &dest, const QList &defVal = QList()); + /** + * @brief Retreive value by specific key and pass it via reference + * @param [_IN] key name of key with value to retrieved + * @param [_OUT] dest Reference to destination variable to store retrieved value + * @param [_IN] defVal Default value for case of non-existing key + */ + void read(const char *key, QList &dest, const QList &defVal = QList()); + /** + * @brief Retreive value by specific key and pass it via reference + * @param [_IN] key name of key with value to retrieved + * @param [_OUT] dest Reference to destination variable to store retrieved value + * @param [_IN] defVal Default value for case of non-existing key + */ + void read(const char *key, QList &dest, const QList &defVal = QList()); + /** + * @brief Retreive value by specific key and pass it via reference + * @param [_IN] key name of key with value to retrieved + * @param [_OUT] dest Reference to destination variable to store retrieved value + * @param [_IN] defVal Default value for case of non-existing key + */ + void read(const char *key, QList &dest, const QList &defVal = QList()); + /** + * @brief Retreive value by specific key and pass it via reference + * @param [_IN] key name of key with value to retrieved + * @param [_OUT] dest Reference to destination variable to store retrieved value + * @param [_IN] defVal Default value for case of non-existing key + */ + void read(const char *key, QList &dest, const QList &defVal = QList()); + + /** + * @brief Retreive value by specific key and pass it via reference + * @param [_IN] key name of key with value to retrieved + * @param [_OUT] dest Reference to destination variable to store retrieved value + * @param [_IN] defVal Default value for case of non-existing key + */ + void read(const char *key, QVector &dest, const QVector &defVal = QVector()); + /** + * @brief Retreive value by specific key and pass it via reference + * @param [_IN] key name of key with value to retrieved + * @param [_OUT] dest Reference to destination variable to store retrieved value + * @param [_IN] defVal Default value for case of non-existing key + */ + void read(const char *key, QVector &dest, const QVector &defVal = QVector()); + /** + * @brief Retreive value by specific key and pass it via reference + * @param [_IN] key name of key with value to retrieved + * @param [_OUT] dest Reference to destination variable to store retrieved value + * @param [_IN] defVal Default value for case of non-existing key + */ + void read(const char *key, QVector &dest, const QVector &defVal = QVector()); + /** + * @brief Retreive value by specific key and pass it via reference + * @param [_IN] key name of key with value to retrieved + * @param [_OUT] dest Reference to destination variable to store retrieved value + * @param [_IN] defVal Default value for case of non-existing key + */ + void read(const char *key, QVector &dest, const QVector &defVal = QVector()); + /** + * @brief Retreive value by specific key and pass it via reference + * @param [_IN] key name of key with value to retrieved + * @param [_OUT] dest Reference to destination variable to store retrieved value + * @param [_IN] defVal Default value for case of non-existing key + */ + void read(const char *key, QVector &dest, const QVector &defVal = QVector()); + /** + * @brief Retreive value by specific key and pass it via reference + * @param [_IN] key name of key with value to retrieved + * @param [_OUT] dest Reference to destination variable to store retrieved value + * @param [_IN] defVal Default value for case of non-existing key + */ + void read(const char *key, QVector &dest, const QVector &defVal = QVector()); + /** + * @brief Retreive value by specific key and pass it via reference + * @param [_IN] key name of key with value to retrieved + * @param [_OUT] dest Reference to destination variable to store retrieved value + * @param [_IN] defVal Default value for case of non-existing key + */ + void read(const char *key, QVector &dest, const QVector &defVal = QVector()); + /** + * @brief Retreive value by specific key and pass it via reference + * @param [_IN] key name of key with value to retrieved + * @param [_OUT] dest Reference to destination variable to store retrieved value + * @param [_IN] defVal Default value for case of non-existing key + */ + void read(const char *key, QVector &dest, const QVector &defVal = QVector()); + /** + * @brief Retreive value by specific key and pass it via reference + * @param [_IN] key name of key with value to retrieved + * @param [_OUT] dest Reference to destination variable to store retrieved value + * @param [_IN] defVal Default value for case of non-existing key + */ + void read(const char *key, QVector &dest, const QVector &defVal = QVector()); + /** + * @brief Retreive value by specific key and pass it via reference + * @param [_IN] key name of key with value to retrieved + * @param [_OUT] dest Reference to destination variable to store retrieved value + * @param [_IN] defVal Default value for case of non-existing key + */ + void read(const char *key, QVector &dest, const QVector &defVal = QVector()); + /** + * @brief Retreive value by specific key and pass it via reference + * @param [_IN] key name of key with value to retrieved + * @param [_OUT] dest Reference to destination variable to store retrieved value + * @param [_IN] defVal Default value for case of non-existing key + */ + void read(const char *key, QVector &dest, const QVector &defVal = QVector()); + #endif + + //! Hash-table for the fast string to enum conversion + typedef std::unordered_map StrEnumMap; + + + template + /** + * @brief Retreive value by string-based enum key + * @param [_IN] key name of key with value to retrieved + * @param [_OUT] dest Reference to destination variable to store retrieved value + * @param [_IN] defVal Default value for case of non-existing key + * @param [_IN] enumMap + */ + void readEnum(const char *key, T &dest, T defVal, IniProcessing::StrEnumMap enumMap) + { + bool ok = false; + params::IniKeys::iterator e = readHelper(key, ok); + + if(!ok) + { + dest = defVal; + return; + } + + StrEnumMap::iterator em = enumMap.find(e->second); + + if(em == enumMap.end()) + { + dest = defVal; + return; + } + + dest = static_cast(em->second); + } + + /** + * @brief QSettings-compatible way to retreive value + * @param key key with value to retreive + * @param defVal default value key + * @return variant which contains a value + */ + IniProcessingVariant value(const char *key, const IniProcessingVariant &defVal = IniProcessingVariant()); + + void setValue(const char *key, unsigned short value); + void setValue(const char *key, short value); + void setValue(const char *key, unsigned int value); + void setValue(const char *key, int value); + void setValue(const char *key, unsigned long value); + void setValue(const char *key, long value); + void setValue(const char *key, unsigned long long value); + void setValue(const char *key, long long value); + void setValue(const char *key, float value); + void setValue(const char *key, double value); + void setValue(const char *key, long double value); + + template + static inline std::string to_string_with_precision(const T a_value) + { + char buf[35]; + memset(buf, 0, 35); + snprintf(buf, 34, "%.15g", static_cast(a_value)); + return buf; + } + + template + static inline std::string fromVector(const TList &value) + { + typedef typename TList::value_type T; + std::string out; + for(const T &f: value) + { + if(!out.empty()) + out.push_back(','); + if(std::is_same::value || + std::is_same::value || + std::is_same::value) + out.append(to_string_with_precision(f)); + else + out.append(std::to_string(f)); + } + return out; + } + + template + void setValue(const char *key, const std::vector &value) + { + static_assert(std::is_arithmetic::value, "Not arithmetic (integral or floating point required!)"); + writeIniParam(key, fromVector(value)); + } + + void setValue(const char *key, const char *value); + void setValue(const char *key, const std::string &value); + + #ifdef INI_PROCESSING_ALLOW_QT_TYPES + void setValue(const char *key, const QString &value); + + template + void setValue(const char *key, const QList &value) + { + static_assert(std::is_arithmetic::value, "Not arithmetic (integral or floating point required!)"); + writeIniParam(key, fromVector(value)); + } + + template + void setValue(const char *key, const QVector &value) + { + static_assert(std::is_arithmetic::value, "Not arithmetic (integral or floating point required!)"); + writeIniParam(key, fromVector(value)); + } + #endif + + /** + * @brief Write INI file by the recently given file path + * @return true if INI file was successfully written + */ + bool writeIniFile(); +}; + +#endif // INIPROCESSING_H diff --git a/utils/gen_adldata/ini/ini_processing_variant.h b/utils/gen_adldata/ini/ini_processing_variant.h new file mode 100644 index 0000000..34f999a --- /dev/null +++ b/utils/gen_adldata/ini/ini_processing_variant.h @@ -0,0 +1,243 @@ +/* +INI Processor - a small library which allows you parsing INI-files + +Copyright (c) 2017 Vitaliy Novichkov + +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. +*/ + +/* +A QVariant-like thing created just like a proxy between +INI Processor and target value (to be compatible with QSettings) +*/ + +#ifndef INI_PROCESSING_VARIANT_H +#define INI_PROCESSING_VARIANT_H + +#include +#include +#include +#ifdef INI_PROCESSING_ALLOW_QT_TYPES +#include +#endif + +class IniProcessingVariant +{ + std::string m_data; + std::string *m_dataP; + inline std::string &data() + { + if(m_dataP) + return *m_dataP; + else + return m_data; + } +public: + IniProcessingVariant(): + m_data(""), + m_dataP(nullptr) {} + + IniProcessingVariant(const std::string &data): + m_data(data), + m_dataP(nullptr) {} + IniProcessingVariant(const char *data): + m_data(data), + m_dataP(nullptr) {} + #ifdef INI_PROCESSING_ALLOW_QT_TYPES + IniProcessingVariant(const QString &data): + m_data(data.toStdString()), + m_dataP(nullptr) {} + #endif + IniProcessingVariant(std::string *dataPointer): + m_data(""), + m_dataP(dataPointer) {} + + IniProcessingVariant(const IniProcessingVariant &v): + m_data(v.m_data), + m_dataP(v.m_dataP) {} + + IniProcessingVariant(char data): + m_data(std::to_string(data)), + m_dataP(nullptr) {} + + IniProcessingVariant(unsigned char data): + m_data(std::to_string(data)), + m_dataP(nullptr) {} + + IniProcessingVariant(bool data): + m_data(std::to_string(data)), + m_dataP(nullptr) {} + + IniProcessingVariant(short data): + m_data(std::to_string(data)), + m_dataP(nullptr) {} + + IniProcessingVariant(unsigned short data): + m_data(std::to_string(data)), + m_dataP(nullptr) {} + + IniProcessingVariant(int data): + m_data(std::to_string(data)), + m_dataP(nullptr) {} + IniProcessingVariant(unsigned int data): + m_data(std::to_string(data)), + m_dataP(nullptr) {} + + IniProcessingVariant(long data): + m_data(std::to_string(data)), + m_dataP(nullptr) {} + IniProcessingVariant(unsigned long data): + m_data(std::to_string(data)), + m_dataP(nullptr) {} + + IniProcessingVariant(long long data): + m_data(std::to_string(data)), + m_dataP(nullptr) {} + IniProcessingVariant(unsigned long long data): + m_data(std::to_string(data)), + m_dataP(nullptr) {} + + IniProcessingVariant(float data): + m_data(std::to_string(data)), + m_dataP(nullptr) {} + + IniProcessingVariant(double data): + m_data(std::to_string(data)), + m_dataP(nullptr) {} + + IniProcessingVariant(long double data): + m_data(std::to_string(data)), + m_dataP(nullptr) {} + + bool isNull() + { + return (m_data.empty() && !m_dataP); + } + + bool isValid() + { + return ((!m_data.empty()) || (static_cast(m_dataP))); + } + + std::string toString() + { + std::string out = data(); + + if((out.size() > 2) && (out[0] == '"')) + out.erase(0, 1); + + if((out.size() > 1) && (out[out.size() - 1] == '"')) + out.erase((out.size() - 1), 1); + + return out; + } + + #ifdef INI_PROCESSING_ALLOW_QT_TYPES + QString toQString() + { + return QString::fromStdString(toString()); + } + #endif + + bool toBool() + { + size_t i = 0; + size_t ss = std::min(static_cast(4ul), data().size()); + char buff[4] = {0, 0, 0, 0}; + const char *pbufi = data().c_str(); + char *pbuff = buff; + + for(; i < ss; i++) + (*pbuff++) = static_cast(std::tolower(*pbufi++)); + + if(ss < 4) + { + if(ss == 0) + return false; + + if(ss == 1) + return (buff[0] == '1'); + + try + { + long num = std::strtol(buff, 0, 0); + return num != 0l; + } + catch(...) + { + bool res = (std::memcmp(buff, "yes", 3) == 0) || + (std::memcmp(buff, "on", 2) == 0); + return res; + } + } + + if(std::memcmp(buff, "true", 4) == 0) + return true; + + try + { + long num = std::strtol(buff, 0, 0); + return num != 0l; + } + catch(...) + { + return false; + } + } + + int toInt() + { + return std::atoi(data().c_str()); + } + unsigned int toUInt() + { + return static_cast(std::strtoul(data().c_str(), nullptr, 0)); + } + + long toLong() + { + return std::atol(data().c_str()); + } + unsigned long toULong() + { + return std::strtoul(data().c_str(), nullptr, 0); + } + + long long toLongLong() + { + return std::atoll(data().c_str()); + } + unsigned long long toULongLong() + { + return std::strtoull(data().c_str(), nullptr, 0); + } + + float toFloat() + { + return float(std::atof(data().c_str())); + } + + double toDouble() + { + return std::atof(data().c_str()); + } +}; + + +#endif // INI_PROCESSING_VARIANT_H diff --git a/utils/gen_adldata/measurer.cpp b/utils/gen_adldata/measurer.cpp new file mode 100644 index 0000000..8bb0772 --- /dev/null +++ b/utils/gen_adldata/measurer.cpp @@ -0,0 +1,543 @@ +#include "measurer.h" +#include + +#ifndef ADLMIDI_USE_DOSBOX_OPL +#include "nukedopl3.h" +#else +#include "dbopl.h" +#endif + +DurationInfo MeasureDurations(const ins &in) +{ + std::vector stereoSampleBuf; +#ifdef ADLMIDI_USE_DOSBOX_OPL + std::vector stereoSampleBuf_32; +#endif + insdata id[2]; + bool found[2] = {false, false}; + for(InstrumentDataTab::const_iterator j = insdatatab.begin(); + j != insdatatab.end(); + ++j) + { + if(j->second.first == in.insno1) + { + id[0] = j->first; + found[0] = true; + if(found[1]) break; + } + if(j->second.first == in.insno2) + { + id[1] = j->first; + found[1] = true; + if(found[0]) break; + } + } + const unsigned rate = 22010; + const unsigned interval = 150; + const unsigned samples_per_interval = rate / interval; + const int notenum = + in.notenum < 20 ? (44 + in.notenum) + : in.notenum >= 128 ? (44 + 128 - in.notenum) + : in.notenum; + +#ifndef ADLMIDI_USE_DOSBOX_OPL +#define WRITE_REG(key, value) OPL3_WriteReg(&opl, (Bit8u)(key), (Bit8u)(value)) + _opl3_chip opl; +#else +#define WRITE_REG(key, value) opl.WriteReg((Bit8u)(key), (Bit8u)(value)); + DBOPL::Handler opl; +#endif + + static const short initdata[(2 + 3 + 2 + 2) * 2] = + { + 0x004, 96, 0x004, 128, // Pulse timer + 0x105, 0, 0x105, 1, 0x105, 0, // Pulse OPL3 enable, leave disabled + 0x001, 32, 0x0BD, 0 // Enable wave & melodic +}; +#ifndef ADLMIDI_USE_DOSBOX_OPL + OPL3_Reset(&opl, rate); +#else + opl.Init(rate); +#endif + for(unsigned a = 0; a < 18; a += 2) WRITE_REG(initdata[a], initdata[a + 1]); + + const unsigned n_notes = in.insno1 == in.insno2 ? 1 : 2; + unsigned x[2]; + + if(n_notes == 2 && !in.pseudo4op) + { + WRITE_REG(0x105, 1); + WRITE_REG(0x104, 1); + } + + for(unsigned n = 0; n < n_notes; ++n) + { + static const unsigned char patchdata[11] = + {0x20, 0x23, 0x60, 0x63, 0x80, 0x83, 0xE0, 0xE3, 0x40, 0x43, 0xC0}; + for(unsigned a = 0; a < 10; ++a) WRITE_REG(patchdata[a] + n * 8, id[n].data[a]); + WRITE_REG(patchdata[10] + n * 8, id[n].data[10] | 0x30); + } + + for(unsigned n = 0; n < n_notes; ++n) + { + double hertz = 172.00093 * std::exp(0.057762265 * (notenum + id[n].finetune)); + if(hertz > 131071) + { + fprintf(stderr, "Why does note %d + finetune %d produce hertz %g?\n", + notenum, id[n].finetune, hertz); + hertz = 131071; + } + x[n] = 0x2000; + while(hertz >= 1023.5) + { + hertz /= 2.0; // Calculate octave + x[n] += 0x400; + } + x[n] += (unsigned int)(hertz + 0.5); + + // Keyon the note + WRITE_REG(0xA0 + n * 3, x[n] & 0xFF); + WRITE_REG(0xB0 + n * 3, x[n] >> 8); + } + + const unsigned max_on = 40; + const unsigned max_off = 60; + + // For up to 40 seconds, measure mean amplitude. + std::vector amplitudecurve_on; + double highest_sofar = 0; + for(unsigned period = 0; period < max_on * interval; ++period) + { + stereoSampleBuf.clear(); + stereoSampleBuf.resize(samples_per_interval * 2); +#ifndef ADLMIDI_USE_DOSBOX_OPL + OPL3_GenerateStream(&opl, stereoSampleBuf.data(), samples_per_interval); +#else + { + stereoSampleBuf_32.resize(samples_per_interval * 2); + Bitu samples = samples_per_interval; + opl.GenerateArr(stereoSampleBuf_32.data(), &samples); + size_t ssat = 0; + for(const int32_t &i : stereoSampleBuf_32) + stereoSampleBuf[ssat++] = (int16_t)i; + } +#endif + + double mean = 0.0; + for(unsigned long c = 0; c < samples_per_interval; ++c) + mean += stereoSampleBuf[c * 2]; + mean /= samples_per_interval; + double std_deviation = 0; + for(unsigned long c = 0; c < samples_per_interval; ++c) + { + double diff = (stereoSampleBuf[c * 2] - mean); + std_deviation += diff * diff; + } + std_deviation = std::sqrt(std_deviation / samples_per_interval); + amplitudecurve_on.push_back(std_deviation); + if(std_deviation > highest_sofar) + highest_sofar = std_deviation; + + if(period > 6 * interval && std_deviation < highest_sofar * 0.2) + break; + } + + // Keyoff the note + for(unsigned n = 0; n < n_notes; ++n) + WRITE_REG(0xB0 + n, (x[n] >> 8) & 0xDF); + + // Now, for up to 60 seconds, measure mean amplitude. + std::vector amplitudecurve_off; + for(unsigned period = 0; period < max_off * interval; ++period) + { + stereoSampleBuf.clear(); + stereoSampleBuf.resize(samples_per_interval * 2); +#ifndef ADLMIDI_USE_DOSBOX_OPL + OPL3_GenerateStream(&opl, stereoSampleBuf.data(), samples_per_interval); +#else + { + stereoSampleBuf_32.resize(samples_per_interval * 2); + Bitu samples = samples_per_interval; + opl.GenerateArr(stereoSampleBuf_32.data(), &samples); + size_t ssat = 0; + for(const int32_t &i : stereoSampleBuf_32) + stereoSampleBuf[ssat++] = (int16_t)i; + } +#endif + + double mean = 0.0; + for(unsigned long c = 0; c < samples_per_interval; ++c) + mean += stereoSampleBuf[c * 2]; + mean /= samples_per_interval; + double std_deviation = 0; + for(unsigned long c = 0; c < samples_per_interval; ++c) + { + double diff = (stereoSampleBuf[c * 2] - mean); + std_deviation += diff * diff; + } + std_deviation = std::sqrt(std_deviation / samples_per_interval); + amplitudecurve_off.push_back(std_deviation); + + if(std_deviation < highest_sofar * 0.2) break; + } + + /* Analyze the results */ + double begin_amplitude = amplitudecurve_on[0]; + double peak_amplitude_value = begin_amplitude; + size_t peak_amplitude_time = 0; + size_t quarter_amplitude_time = amplitudecurve_on.size(); + size_t keyoff_out_time = 0; + + for(size_t a = 1; a < amplitudecurve_on.size(); ++a) + { + if(amplitudecurve_on[a] > peak_amplitude_value) + { + peak_amplitude_value = amplitudecurve_on[a]; + peak_amplitude_time = a; + } + } + for(size_t a = peak_amplitude_time; a < amplitudecurve_on.size(); ++a) + { + if(amplitudecurve_on[a] <= peak_amplitude_value * 0.2) + { + quarter_amplitude_time = a; + break; + } + } + for(size_t a = 0; a < amplitudecurve_off.size(); ++a) + { + if(amplitudecurve_off[a] <= peak_amplitude_value * 0.2) + { + keyoff_out_time = a; + break; + } + } + + if(keyoff_out_time == 0 && amplitudecurve_on.back() < peak_amplitude_value * 0.2) + keyoff_out_time = quarter_amplitude_time; + + DurationInfo result; + result.peak_amplitude_time = peak_amplitude_time; + result.peak_amplitude_value = peak_amplitude_value; + result.begin_amplitude = begin_amplitude; + result.quarter_amplitude_time = quarter_amplitude_time; + result.keyoff_out_time = keyoff_out_time; + + result.ms_sound_kon = (long)(quarter_amplitude_time * 1000.0 / interval); + result.ms_sound_koff = (long)(keyoff_out_time * 1000.0 / interval); + result.nosound = (peak_amplitude_value < 0.5); + return result; +} + +static const char* spinner = "-\\|/"; + +void MeasureThreaded::LoadCache(const char *fileName) +{ + FILE *in = std::fopen(fileName, "rb"); + if(!in) + { + std::printf("Failed to load cache: file is not exists.\n" + "Complete data will be generated from scratch.\n"); + std::fflush(stdout); + return; + } + + char magic[32]; + if(std::fread(magic, 1, 32, in) != 32) + { + std::fclose(in); + std::printf("Failed to load cache: can't read magic.\n" + "Complete data will be generated from scratch.\n"); + std::fflush(stdout); + return; + } + + if(memcmp(magic, "ADLMIDI-DURATION-CACHE-FILE-V1.0", 32) != 0) + { + std::fclose(in); + std::printf("Failed to load cache: magic missmatch.\n" + "Complete data will be generated from scratch.\n"); + std::fflush(stdout); + return; + } + + while(!std::feof(in)) + { + DurationInfo info; + ins inst; + //got by instrument + insdata id[2]; + size_t insNo[2] = {0, 0}; + bool found[2] = {false, false}; + //got from file + insdata id_f[2]; + bool found_f[2] = {false, false}; + bool isMatches = false; + + memset(id, 0, sizeof(insdata) * 2); + memset(id_f, 0, sizeof(insdata) * 2); + memset(&info, 0, sizeof(DurationInfo)); + memset(&inst, 0, sizeof(ins)); + + //Instrument + uint64_t inval; + if(std::fread(&inval, 1, sizeof(uint64_t), in) != sizeof(uint64_t)) + break; + inst.insno1 = inval; + if(std::fread(&inval, 1, sizeof(uint64_t), in) != sizeof(uint64_t)) + break; + inst.insno2 = inval; + if(std::fread(&inst.notenum, 1, 1, in) != 1) + break; + if(std::fread(&inst.pseudo4op, 1, 1, in) != 1) + break; + if(std::fread(&inst.voice2_fine_tune, sizeof(double), 1, in) != 1) + break; + + //Instrument data + if(fread(found_f, 1, 2 * sizeof(bool), in) != sizeof(bool) * 2) + break; + for(size_t i = 0; i < 2; i++) + { + if(fread(id_f[i].data, 1, 11, in) != 11) + break; + if(fread(&id_f[i].finetune, 1, 1, in) != 1) + break; + if(fread(&id_f[i].diff, 1, sizeof(bool), in) != sizeof(bool)) + break; + } + + if(found_f[0] || found_f[1]) + { + for(InstrumentDataTab::const_iterator j = insdatatab.begin(); j != insdatatab.end(); ++j) + { + if(j->second.first == inst.insno1) + { + id[0] = j->first; + found[0] = (id[0] == id_f[0]); + insNo[0] = inst.insno1; + if(found[1]) break; + } + if(j->second.first == inst.insno2) + { + id[1] = j->first; + found[1] = (id[1] == id_f[1]); + insNo[1] = inst.insno2; + if(found[0]) break; + } + } + + //Find instrument entries are matching + if((found[0] != found_f[0]) || (found[1] != found_f[1])) + { + for(InstrumentDataTab::const_iterator j = insdatatab.begin(); j != insdatatab.end(); ++j) + { + if(found_f[0] && (j->first == id_f[0])) + { + found[0] = true; + insNo[0] = j->second.first; + } + if(found_f[1] && (j->first == id_f[1])) + { + found[1] = true; + insNo[1] = j->second.first; + } + if(found[0] && !found_f[1]) + { + isMatches = true; + break; + } + if(found[0] && found[1]) + { + isMatches = true; + break; + } + } + } + else + { + isMatches = true; + } + + //Then find instrument entry that uses found instruments + if(isMatches) + { + inst.insno1 = insNo[0]; + inst.insno2 = insNo[1]; + InstrumentsData::iterator d = instab.find(inst); + if(d == instab.end()) + isMatches = false; + } + } + + //Duration data + if(std::fread(&info.peak_amplitude_time, 1, sizeof(uint64_t), in) != sizeof(uint64_t)) + break; + if(std::fread(&info.peak_amplitude_value, 1, sizeof(double), in) != sizeof(double)) + break; + if(std::fread(&info.quarter_amplitude_time, 1, sizeof(double), in) != sizeof(double)) + break; + if(std::fread(&info.begin_amplitude, 1, sizeof(double), in) != sizeof(double)) + break; + if(std::fread(&info.interval, 1, sizeof(double), in) != sizeof(double)) + break; + if(std::fread(&info.keyoff_out_time, 1, sizeof(double), in) != sizeof(double)) + break; + if(std::fread(&info.ms_sound_kon, 1, sizeof(int64_t), in) != sizeof(int64_t)) + break; + if(std::fread(&info.ms_sound_koff, 1, sizeof(int64_t), in) != sizeof(int64_t)) + break; + if(std::fread(&info.nosound, 1, sizeof(bool), in) != sizeof(bool)) + break; + + if(isMatches)//Store only if cached entry matches actual raw instrument data + m_durationInfo.insert({inst, info}); + } + + std::printf("Cache loaded!\n"); + std::fflush(stdout); + + std::fclose(in); +} + +void MeasureThreaded::SaveCache(const char *fileName) +{ + FILE *out = std::fopen(fileName, "wb"); + fprintf(out, "ADLMIDI-DURATION-CACHE-FILE-V1.0"); + for(DurationInfoCache::iterator it = m_durationInfo.begin(); it != m_durationInfo.end(); it++) + { + const ins &in = it->first; + insdata id[2]; + bool found[2] = {false, false}; + memset(id, 0, sizeof(insdata) * 2); + + uint64_t outval; + outval = in.insno1; + fwrite(&outval, 1, sizeof(uint64_t), out); + outval = in.insno2; + fwrite(&outval, 1, sizeof(uint64_t), out); + fwrite(&in.notenum, 1, 1, out); + fwrite(&in.pseudo4op, 1, 1, out); + fwrite(&in.voice2_fine_tune, sizeof(double), 1, out); + + for(InstrumentDataTab::const_iterator j = insdatatab.begin(); j != insdatatab.end(); ++j) + { + if(j->second.first == in.insno1) + { + id[0] = j->first; + found[0] = true; + if(found[1]) break; + } + if(j->second.first == in.insno2) + { + id[1] = j->first; + found[1] = true; + if(found[0]) break; + } + } + + fwrite(found, 1, 2 * sizeof(bool), out); + for(size_t i = 0; i < 2; i++) + { + fwrite(id[i].data, 1, 11, out); + fwrite(&id[i].finetune, 1, 1, out); + fwrite(&id[i].diff, 1, sizeof(bool), out); + } + + fwrite(&it->second.peak_amplitude_time, 1, sizeof(uint64_t), out); + fwrite(&it->second.peak_amplitude_value, 1, sizeof(double), out); + fwrite(&it->second.quarter_amplitude_time, 1, sizeof(double), out); + fwrite(&it->second.begin_amplitude, 1, sizeof(double), out); + fwrite(&it->second.interval, 1, sizeof(double), out); + fwrite(&it->second.keyoff_out_time, 1, sizeof(double), out); + fwrite(&it->second.ms_sound_kon, 1, sizeof(int64_t), out); + fwrite(&it->second.ms_sound_koff, 1, sizeof(int64_t), out); + fwrite(&it->second.nosound, 1, sizeof(bool), out); + } + std::fclose(out); +} + +void MeasureThreaded::printProgress() +{ + std::printf("Calculating measures... [%c %3u%% (%4u/%4u) Threads %3u, Matches %u] \r", + spinner[m_done.load() % 4], + (unsigned int)(((double)m_done.load() / (double)(m_total)) * 100), + (unsigned int)m_done.load(), + (unsigned int)m_total, + (unsigned int)m_threads.size(), + (unsigned int)m_cache_matches + ); + std::fflush(stdout); +} + +void MeasureThreaded::printFinal() +{ + std::printf("Calculating measures completed! [Total entries %4u with %u cache matches]\n", + (unsigned int)m_total, + (unsigned int)m_cache_matches); + std::fflush(stdout); +} + +void MeasureThreaded::run(InstrumentsData::const_iterator i) +{ + m_semaphore.wait(); + if(m_threads.size() > 0) + { + for(std::vector::iterator it = m_threads.begin(); it != m_threads.end();) + { + if(!(*it)->m_works) + { + delete(*it); + it = m_threads.erase(it); + } + else + it++; + } + } + + destData *dd = new destData; + dd->i = i; + dd->myself = this; + dd->start(); + m_threads.push_back(dd); + printProgress(); +} + +void MeasureThreaded::waitAll() +{ + for(auto &th : m_threads) + { + printProgress(); + delete th; + } + m_threads.clear(); + printFinal(); +} + +void MeasureThreaded::destData::start() +{ + m_work = std::thread(&destData::callback, this); +} + +void MeasureThreaded::destData::callback(void *myself) +{ + destData *s = reinterpret_cast(myself); + DurationInfo info; + DurationInfoCache::iterator cachedEntry = s->myself->m_durationInfo.find(s->i->first); + + if(cachedEntry != s->myself->m_durationInfo.end()) + { + s->myself->m_cache_matches++; + goto endWork; + } + + info = MeasureDurations(s->i->first); + s->myself->m_durationInfo_mx.lock(); + s->myself->m_durationInfo.insert({s->i->first, info}); + s->myself->m_durationInfo_mx.unlock(); + +endWork: + s->myself->m_semaphore.notify(); + s->myself->m_done++; + s->m_works = false; +} diff --git a/utils/gen_adldata/measurer.h b/utils/gen_adldata/measurer.h new file mode 100644 index 0000000..b9ae3c6 --- /dev/null +++ b/utils/gen_adldata/measurer.h @@ -0,0 +1,105 @@ +#ifndef MEASURER_H +#define MEASURER_H + +#include +#include +#include +#include +#include + +#include "progs_cache.h" + +struct DurationInfo +{ + uint64_t peak_amplitude_time; + double peak_amplitude_value; + double quarter_amplitude_time; + double begin_amplitude; + double interval; + double keyoff_out_time; + int64_t ms_sound_kon; + int64_t ms_sound_koff; + bool nosound; + uint8_t padding[7]; +}; + +class Semaphore +{ +public: + Semaphore(int count_ = 0) + : m_count(count_) {} + + inline void notify() + { + std::unique_lock lock(mtx); + m_count++; + cv.notify_one(); + } + + inline void wait() + { + std::unique_lock lock(mtx); + while(m_count == 0) + { + cv.wait(lock); + } + m_count--; + } + +private: + std::mutex mtx; + std::condition_variable cv; + std::atomic_int m_count; +}; + +struct MeasureThreaded +{ + typedef std::map DurationInfoCache; + + MeasureThreaded() : + m_semaphore(int(std::thread::hardware_concurrency()) * 2), + m_done(0), + m_cache_matches(0) + {} + + Semaphore m_semaphore; + std::mutex m_durationInfo_mx; + DurationInfoCache m_durationInfo; + std::atomic_bool m_delete_tail; + size_t m_total = 0; + std::atomic m_done; + std::atomic m_cache_matches; + + void LoadCache(const char *fileName); + void SaveCache(const char *fileName); + + struct destData + { + destData() + { + m_works = true; + } + ~destData() + { + m_work.join(); + } + MeasureThreaded *myself; + std::map > >::const_iterator i; + std::thread m_work; + std::atomic_bool m_works; + + void start(); + static void callback(void *myself); + }; + + std::vector m_threads; + + void printProgress(); + void printFinal(); + void run(InstrumentsData::const_iterator i); + void waitAll(); +}; + +extern DurationInfo MeasureDurations(const ins &in); + +#endif // MEASURER_H diff --git a/utils/gen_adldata/midi_inst_list.h b/utils/gen_adldata/midi_inst_list.h new file mode 100644 index 0000000..61c9119 --- /dev/null +++ b/utils/gen_adldata/midi_inst_list.h @@ -0,0 +1,185 @@ +#pragma once +#ifndef MIDI_INS_LIST +#define MIDI_INS_LIST + +static const char *const MidiInsName[] = { +"AcouGrandPiano", +"BrightAcouGrand", +"ElecGrandPiano", +"Honky-tonkPiano", +"Rhodes Piano", +"Chorused Piano", +"Harpsichord", +"Clavinet", +"Celesta", +"Glockenspiel", +"Music box", +"Vibraphone", +"Marimba", +"Xylophone", +"Tubular Bells", +"Dulcimer", +"Hammond Organ", +"Percussive Organ", +"Rock Organ", +"Church Organ", +"Reed Organ", +"Accordion", +"Harmonica", +"Tango Accordion", +"Acoustic Guitar1", +"Acoustic Guitar2", +"Electric Guitar1", +"Electric Guitar2", +"Electric Guitar3", +"Overdrive Guitar", +"Distorton Guitar", +"Guitar Harmonics", +"Acoustic Bass", +"Electric Bass 1", +"Electric Bass 2", +"Fretless Bass", +"Slap Bass 1", +"Slap Bass 2", +"Synth Bass 1", +"Synth Bass 2", +"Violin", +"Viola", +"Cello", +"Contrabass", +"Tremulo Strings", +"Pizzicato String", +"Orchestral Harp", +"Timpany", +"String Ensemble1", +"String Ensemble2", +"Synth Strings 1", +"SynthStrings 2", +"Choir Aahs", +"Voice Oohs", +"Synth Voice", +"Orchestra Hit", +"Trumpet", +"Trombone", +"Tuba", +"Muted Trumpet", +"French Horn", +"Brass Section", +"Synth Brass 1", +"Synth Brass 2", +"Soprano Sax", +"Alto Sax", +"Tenor Sax", +"Baritone Sax", +"Oboe", +"English Horn", +"Bassoon", +"Clarinet", +"Piccolo", +"Flute", +"Recorder", +"Pan Flute", +"Bottle Blow", +"Shakuhachi", +"Whistle", +"Ocarina", +"Lead 1 squareea", +"Lead 2 sawtooth", +"Lead 3 calliope", +"Lead 4 chiff", +"Lead 5 charang", +"Lead 6 voice", +"Lead 7 fifths", +"Lead 8 brass", +"Pad 1 new age", +"Pad 2 warm", +"Pad 3 polysynth", +"Pad 4 choir", +"Pad 5 bowedpad", +"Pad 6 metallic", +"Pad 7 halo", +"Pad 8 sweep", +"FX 1 rain", +"FX 2 soundtrack", +"FX 3 crystal", +"FX 4 atmosphere", +"FX 5 brightness", +"FX 6 goblins", +"FX 7 echoes", +"FX 8 sci-fi", +"Sitar", +"Banjo", +"Shamisen", +"Koto", +"Kalimba", +"Bagpipe", +"Fiddle", +"Shanai", +"Tinkle Bell", +"Agogo Bells", +"Steel Drums", +"Woodblock", +"Taiko Drum", +"Melodic Tom", +"Synth Drum", +"Reverse Cymbal", +"Guitar FretNoise", +"Breath Noise", +"Seashore", +"Bird Tweet", +"Telephone", +"Helicopter", +"Applause/Noise", +"Gunshot", +// 27..34: High Q; Slap; Scratch Push; Scratch Pull; Sticks; +// Square Click; Metronome Click; Metronome Bell +"Ac Bass Drum", +"Bass Drum 1", +"Side Stick", +"Acoustic Snare", +"Hand Clap", +"Electric Snare", +"Low Floor Tom", +"Closed High Hat", +"High Floor Tom", +"Pedal High Hat", +"Low Tom", +"Open High Hat", +"Low-Mid Tom", +"High-Mid Tom", +"Crash Cymbal 1", +"High Tom", +"Ride Cymbal 1", +"Chinese Cymbal", +"Ride Bell", +"Tambourine", +"Splash Cymbal", +"Cow Bell", +"Crash Cymbal 2", +"Vibraslap", +"Ride Cymbal 2", +"High Bongo", +"Low Bongo", +"Mute High Conga", +"Open High Conga", +"Low Conga", +"High Timbale", +"Low Timbale", +"High Agogo", +"Low Agogo", +"Cabasa", +"Maracas", +"Short Whistle", +"Long Whistle", +"Short Guiro", +"Long Guiro", +"Claves", +"High Wood Block", +"Low Wood Block", +"Mute Cuica", +"Open Cuica", +"Mute Triangle", +"Open Triangle", +"Shaker","Jingle Bell","Bell Tree","Castanets","Mute Surdu","Open Surdu",""}; + +#endif //MIDI_INS_LIST diff --git a/utils/gen_adldata/progs_cache.cpp b/utils/gen_adldata/progs_cache.cpp new file mode 100644 index 0000000..4aec9be --- /dev/null +++ b/utils/gen_adldata/progs_cache.cpp @@ -0,0 +1,106 @@ +#include "progs_cache.h" + +InstrumentDataTab insdatatab; + +InstrumentsData instab; +InstProgsData progs; + +std::vector banknames; + +//unsigned maxvalues[30] = { 0 }; + +void SetBank(unsigned bank, unsigned patch, size_t insno) +{ + progs[bank][patch] = insno + 1; +} + +size_t InsertIns( + const insdata &id, + const insdata &id2, + ins &in, + const std::string &name, + const std::string &name2) +{ + if(true) + { + InstrumentDataTab::iterator i = insdatatab.lower_bound(id); + + size_t insno = size_t(~0); + if(i == insdatatab.end() || i->first != id) + { + std::pair > > res; + res.first = id; + res.second.first = insdatatab.size(); + if(!name.empty()) res.second.second.insert(name); + if(!name2.empty()) res.second.second.insert(name2); + insdatatab.insert(i, res); + insno = res.second.first; + } + else + { + if(!name.empty()) i->second.second.insert(name); + if(!name2.empty()) i->second.second.insert(name2); + insno = i->second.first; + } + + in.insno1 = insno; + } + if(id != id2) + { + InstrumentDataTab::iterator i = insdatatab.lower_bound(id2); + + size_t insno2 = size_t(~0); + if(i == insdatatab.end() || i->first != id2) + { + std::pair > > res; + res.first = id2; + res.second.first = insdatatab.size(); + if(!name.empty()) res.second.second.insert(name); + if(!name2.empty()) res.second.second.insert(name2); + insdatatab.insert(i, res); + insno2 = res.second.first; + } + else + { + if(!name.empty()) i->second.second.insert(name); + if(!name2.empty()) i->second.second.insert(name2); + insno2 = i->second.first; + } + in.insno2 = insno2; + } + else + in.insno2 = in.insno1; + + + { + InstrumentsData::iterator i = instab.lower_bound(in); + + size_t resno = size_t(~0); + if(i == instab.end() || i->first != in) + { + std::pair > > res; + res.first = in; + res.second.first = instab.size(); + if(!name.empty()) res.second.second.insert(name); + if(!name2.empty()) res.second.second.insert(name2); + instab.insert(i, res); + resno = res.second.first; + } + else + { + if(!name.empty()) i->second.second.insert(name); + if(!name2.empty()) i->second.second.insert(name2); + resno = i->second.first; + } + return resno; + } +} + +// Create silent 'nosound' instrument +size_t InsertNoSoundIns() +{ + // { 0x0F70700,0x0F70710, 0xFF,0xFF, 0x0,+0 }, + insdata tmp1 = { {0x00, 0x10, 0x07, 0x07, 0xF7, 0xF7, 0x00, 0x00, 0xFF, 0xFF, 0x00}, 0, 0 }; + struct ins tmp2 = { 0, 0, 0, false, 0.0 }; + return InsertIns(tmp1, tmp1, tmp2, "nosound"); +} diff --git a/utils/gen_adldata/progs_cache.h b/utils/gen_adldata/progs_cache.h new file mode 100644 index 0000000..007c3b4 --- /dev/null +++ b/utils/gen_adldata/progs_cache.h @@ -0,0 +1,85 @@ +#ifndef PROGS_H +#define PROGS_H + +#include +#include +#include +#include +#include +#include +#include + +struct insdata +{ + uint8_t data[11]; + int8_t finetune; + bool diff; + bool operator==(const insdata &b) const + { + return std::memcmp(data, b.data, 11) == 0 && finetune == b.finetune && diff == b.diff; + } + bool operator< (const insdata &b) const + { + int c = std::memcmp(data, b.data, 11); + if(c != 0) return c < 0; + if(finetune != b.finetune) return finetune < b.finetune; + if(diff != b.diff) return (!diff) == (b.diff); + return 0; + } + bool operator!=(const insdata &b) const + { + return !operator==(b); + } +}; + +struct ins +{ + size_t insno1, insno2; + unsigned char notenum; + bool pseudo4op; + double voice2_fine_tune; + + bool operator==(const ins &b) const + { + return notenum == b.notenum + && insno1 == b.insno1 + && insno2 == b.insno2 + && pseudo4op == b.pseudo4op + && voice2_fine_tune == b.voice2_fine_tune; + } + bool operator< (const ins &b) const + { + if(insno1 != b.insno1) return insno1 < b.insno1; + if(insno2 != b.insno2) return insno2 < b.insno2; + if(notenum != b.notenum) return notenum < b.notenum; + if(pseudo4op != b.pseudo4op) return pseudo4op < b.pseudo4op; + if(voice2_fine_tune != b.voice2_fine_tune) return voice2_fine_tune < b.voice2_fine_tune; + return 0; + } + bool operator!=(const ins &b) const + { + return !operator==(b); + } +}; + +typedef std::map > > InstrumentDataTab; +extern InstrumentDataTab insdatatab; + +typedef std::map > > InstrumentsData; +extern InstrumentsData instab; + +typedef std::map > InstProgsData; +extern InstProgsData progs; + +extern std::vector banknames; + +//static std::map > Correlate; +//extern unsigned maxvalues[30]; + +void SetBank(unsigned bank, unsigned patch, size_t insno); + +size_t InsertIns(const insdata &id, const insdata &id2, ins &in, + const std::string &name, const std::string &name2 = ""); +size_t InsertNoSoundIns(); + +#endif // PROGS_H diff --git a/utils/gen_adldata/scrapped.txt b/utils/gen_adldata/scrapped.txt new file mode 100644 index 0000000..10c15cd --- /dev/null +++ b/utils/gen_adldata/scrapped.txt @@ -0,0 +1,263 @@ + +#ifdef HARD_BANKS +static const char *const banknames[] = +{ + // 0 + "AIL (Star Control 3, Albion, Empire 2, Sensible Soccer, Settlers 2, many others)", + "Bisqwit (selection of 4op and 2op)", + "HMI (Descent, Asterix)", //melodic,drum + "HMI (Descent:: Int)", //intmelo,intdrum + "HMI (Descent:: Ham)", //hammelo,hamdrum + "HMI (Descent:: Rick)", //rickmelo,rickdrum + "HMI (Descent 2)", //d2melo,d2drum + "HMI (Normality)", //normmelo,normdrum + "HMI (Shattered Steel)", //ssmelo,ssdrum + "HMI (Theme Park)", // file131, file132 + // 10 + "HMI (3d Table Sports, Battle Arena Toshinden)", //file133, file134 + "HMI (Aces of the Deep)", //file142, file143 + "HMI (Earthsiege)", //file144, file145 + "HMI (Anvil of Dawn)", //file167,file168 + "DMX (Doom :: partially pseudo 4op)", + "DMX (Hexen, Heretic :: partially pseudo 4op)", + "DMX (MUS Play :: partially pseudo 4op)", + "AIL (Discworld, Grandest Fleet, Pocahontas, Slob Zone 3d, Ultima 4, Zorro)", // file17 + "AIL (Warcraft 2)", + "AIL (Syndicate)", // file19 + // 20 + "AIL (Guilty, Orion Conspiracy, Terra Nova Strike Force Centauri :: 4op)", // file20 + "AIL (Magic Carpet 2)", // file21 + "AIL (Nemesis)", + "AIL (Jagged Alliance)", //file23 + "AIL (When Two Worlds War :: 4op, MISSING INSTRUMENTS)", //file24 + "AIL (Bards Tale Construction :: MISSING INSTRUMENTS)", //file25 + "AIL (Return to Zork)", //file26 + "AIL (Theme Hospital)", //file27 + "AIL (National Hockey League PA)", + "AIL (Inherit The Earth)", //file29 + // 30 + "AIL (Inherit The Earth, file two)", //file30 + "AIL (Little Big Adventure :: 4op)", //file31 + "AIL (Wreckin Crew)", //file32 + "AIL (Death Gate)", // file13 + "AIL (FIFA International Soccer)", //file34 + "AIL (Starship Invasion)", //file35 + "AIL (Super Street Fighter 2 :: 4op)", //file36 + "AIL (Lords of the Realm :: MISSING INSTRUMENTS)", //file37 + "AIL (SimFarm, SimHealth :: 4op)", + "AIL (SimFarm, Settlers, Serf City)", + // 40 + "AIL (Caesar 2 :: partially 4op, MISSING INSTRUMENTS)", // file12 + "AIL (Syndicate Wars)", //file41 + "AIL (Bubble Bobble Feat. Rainbow Islands, Z)", //file42 + "AIL (Warcraft)", //file47 + "AIL (Terra Nova Strike Force Centuri :: partially 4op)", //file48 + "AIL (System Shock :: partially 4op)", //file49 + "AIL (Advanced Civilization)", //file50 + "AIL (Battle Chess 4000 :: partially 4op, melodic only)", //file53 + "AIL (Ultimate Soccer Manager :: partially 4op)", //file54 + "AIL (Air Bucks, Blue And The Gray, America Invades, Terminator 2029)", // sample.ad + // 50 + "AIL (Ultima Underworld 2)", // sample.opl + "AIL (Kasparov's Gambit)", // file15 + "AIL (High Seas Trader :: MISSING INSTRUMENTS)", // file16 + "AIL (Master of Magic, Master of Orion 2 :: 4op, std percussion)", //file159 + "AIL (Master of Magic, Master of Orion 2 :: 4op, orchestral percussion)", //file159 + "SB (Action Soccer)", + "SB (3d Cyberpuck :: melodic only)", + "SB (Simon the Sorcerer :: melodic only)", + "OP3 (The Fat Man 2op set)", + "OP3 (The Fat Man 4op set)", + // 60 + "OP3 (JungleVision 2op set :: melodic only)", + "OP3 (Wallace 2op set, Nitemare 3D :: melodic only)", + "TMB (Duke Nukem 3D)", + "TMB (Shadow Warrior)", + "DMX (Raptor)", + "OP3 (Modded GMOPL by Wohlstand)", + "SB (Jammey O'Connel's bank)", + "TMB (Default bank of Build Engine)", + "OP3 (4op bank by James Alan Nguyen)", + "TMB (Blood)", + // 70 + "TMB (Lee)", + "TMB (Nam)", + "DMX (Bank by Sneakernets)" +}; + +const char *prev = ""; +const char *prev_prefix = ""; +size_t prev_index = 0; + +enum IniType +{ + INI_Both, + INI_Melodic, + INI_Drums +}; + +void writeIni(const char * format, const char * filepath, const char * prefix, size_t index, int type, const char*filter_mel = 0, const char *filter_perc = 0) +{ + if(type == INI_Both) + { + FILE *ini = fopen("banks.ini", "a"); + fprintf(ini, "[bank-%lu]\n", index); + fprintf(ini, "name = \"%s\"\n", banknames[index]); + fprintf(ini, "format = %s\n", format); + fprintf(ini, "file = \"%s\"\n", filepath); + fprintf(ini, "prefix = \"%s\"\n", prefix); + if(filter_mel) fprintf(ini, "filter-m = \"%s\"\n", filter_mel); + if(filter_perc) fprintf(ini, "filter-p = \"%s\"\n", filter_perc); + fprintf(ini, "\n"); + fclose(ini); + } + + if(type == INI_Drums) + { + FILE *ini = fopen("banks.ini", "a"); + fprintf(ini, "[bank-%lu]\n", index); + fprintf(ini, "name = \"%s\"\n", banknames[index]); + fprintf(ini, "format = %s\n", format); + fprintf(ini, "file = \"%s\"\n", prev); + fprintf(ini, "file-p = \"%s\"\n", filepath); + fprintf(ini, "prefix = \"%s\"\n", prev_prefix); + fprintf(ini, "prefix-p = \"%s\"\n", prefix); + fprintf(ini, "\n"); + fclose(ini); + } + + prev = filepath; + prev_prefix = prefix; + prev_index = index; +} +#endif + + + +#ifdef HARD_BANKS +LoadMiles("fm_banks/opl_files/sc3.opl", 0, "G"); // Our "standard" bank! Same as file22.opl + +LoadBisqwit("fm_banks/op3_files/bisqwit.adlraw", 1, "Bisq"); + +LoadBNK("fm_banks/bnk_files/melodic.bnk", 2, "HMIGM", false, false); // same as file156.bnk +LoadBNK("fm_banks/bnk_files/drum.bnk", 2, "HMIGP", false, true); + +LoadBNK("fm_banks/bnk_files/intmelo.bnk", 3, "intM", false, false); +LoadBNK("fm_banks/bnk_files/intdrum.bnk", 3, "intP", false, true); + +LoadBNK("fm_banks/bnk_files/hammelo.bnk", 4, "hamM", false, false); +LoadBNK("fm_banks/bnk_files/hamdrum.bnk", 4, "hamP", false, true); + +LoadBNK("fm_banks/bnk_files/rickmelo.bnk", 5, "rickM", false, false); +LoadBNK("fm_banks/bnk_files/rickdrum.bnk", 5, "rickP", false, true); + +LoadBNK("fm_banks/bnk_files/d2melo.bnk", 6, "b6M", false, false); +LoadBNK("fm_banks/bnk_files/d2drum.bnk", 6, "b6P", false, true); + +LoadBNK("fm_banks/bnk_files/normmelo.bnk", 7, "b7M", false, false); +LoadBNK("fm_banks/bnk_files/normdrum.bnk", 7, "b7P", false, true); // same as file122.bnk + +LoadBNK("fm_banks/bnk_files/ssmelo.bnk", 8, "b8M", false, false); +LoadBNK("fm_banks/bnk_files/ssdrum.bnk", 8, "b8P", false, true); + +LoadTMB("fm_banks/bnk_files/themepark.tmb", 9, "b9MP"); +//LoadBNK("fm_banks/bnk_files/file131.bnk", 9, "b9M", false, false); +//LoadBNK("fm_banks/bnk_files/file132.bnk", 9, "b9P", false, true); + +LoadBNK("fm_banks/bnk_files/file133.bnk", 10, "b10P", false, true); +LoadBNK("fm_banks/bnk_files/file134.bnk", 10, "b10M", false, false); + +LoadBNK("fm_banks/bnk_files/file142.bnk", 11, "b11P", false, true); +LoadBNK("fm_banks/bnk_files/file143.bnk", 11, "b11M", false, false); + +LoadBNK("fm_banks/bnk_files/file145.bnk", 12, "b12M", false, false);//file145 is MELODIC +LoadBNK("fm_banks/bnk_files/file144.bnk", 12, "b12P", false, true);//file144 is DRUMS + +LoadBNK("fm_banks/bnk_files/file167.bnk", 13, "b13P", false, true); +LoadBNK("fm_banks/bnk_files/file168.bnk", 13, "b13M", false, false); + +LoadDoom("fm_banks/doom2/genmidi.op2", 14, "dM"); +LoadDoom("fm_banks/doom2/genmidi.htc", 15, "hxM"); // same as genmidi.hxn +LoadDoom("fm_banks/doom2/default.op2", 16, "mus"); + +LoadMiles("fm_banks/opl_files/file17.opl", 17, "f17G"); +LoadMiles("fm_banks/opl_files/warcraft.ad", 18, "sG"); // same as file44, warcraft.opl +LoadMiles("fm_banks/opl_files/file19.opl", 19, "f19G"); +LoadMiles("fm_banks/opl_files/file20.opl", 20, "f20G"); +LoadMiles("fm_banks/opl_files/file21.opl", 21, "f21G"); +LoadMiles("fm_banks/opl_files/nemesis.opl", 22, "nem"); +LoadMiles("fm_banks/opl_files/file23.opl", 23, "f23G"); +LoadMiles("fm_banks/opl_files/file24.opl", 24, "f24G"); +LoadMiles("fm_banks/opl_files/file25.opl", 25, "f25G"); +LoadMiles("fm_banks/opl_files/file26.opl", 26, "f26G"); +LoadMiles("fm_banks/opl_files/file27.opl", 27, "f27G"); +LoadMiles("fm_banks/opl_files/nhlpa.opl", 28, "nhl"); +LoadMiles("fm_banks/opl_files/file29.opl", 29, "f29G"); +LoadMiles("fm_banks/opl_files/file30.opl", 30, "f30G"); +LoadMiles("fm_banks/opl_files/file31.opl", 31, "f31G"); +LoadMiles("fm_banks/opl_files/file32.opl", 32, "f32G"); +LoadMiles("fm_banks/opl_files/file13.opl", 33, "f13G"); +LoadMiles("fm_banks/opl_files/file34.opl", 34, "f34G"); +LoadMiles("fm_banks/opl_files/file35.opl", 35, "f35G"); +LoadMiles("fm_banks/opl_files/file36.opl", 36, "f36G"); +LoadMiles("fm_banks/opl_files/file37.opl", 37, "f37G"); +LoadMiles("fm_banks/opl_files/simfarm.opl", 38, "qG"); +LoadMiles("fm_banks/opl_files/simfarm.ad", 39, "mG"); // same as file18.opl +LoadMiles("fm_banks/opl_files/file12.opl", 40, "f12G"); +LoadMiles("fm_banks/opl_files/file41.opl", 41, "f41G"); +LoadMiles("fm_banks/opl_files/file42.opl", 42, "f42G"); +LoadMiles("fm_banks/opl_files/file47.opl", 43, "f47G"); +LoadMiles("fm_banks/opl_files/file48.opl", 44, "f48G"); +LoadMiles("fm_banks/opl_files/file49.opl", 45, "f49G"); +LoadMiles("fm_banks/opl_files/file50.opl", 46, "f50G"); +LoadMiles("fm_banks/opl_files/file53.opl", 47, "f53G"); +LoadBNK("fm_banks/bnk_files/file144.bnk", 47, "f53GD", false, true);//Attempt to append missing drums +LoadMiles("fm_banks/opl_files/file54.opl", 48, "f54G"); + +LoadMiles("fm_banks/opl_files/sample.ad", 49, "MG"); // same as file51.opl +LoadMiles("fm_banks/opl_files/sample.opl", 50, "oG"); // same as file40.opl +LoadMiles("fm_banks/opl_files/file15.opl", 51, "f15G"); +LoadMiles("fm_banks/opl_files/file16.opl", 52, "f16G"); + +LoadBNK2("fm_banks/bnk_files/file159.bnk", 53, "b50", "gm", "gps"); // fat-opl3 +LoadBNK2("fm_banks/bnk_files/file159.bnk", 54, "b51", "gm", "gpo"); + +LoadIBK("fm_banks/ibk_files/soccer-genmidi.ibk", 55, "b55M", false); +LoadIBK("fm_banks/ibk_files/soccer-percs.ibk", 55, "b55P", true); +LoadIBK("fm_banks/ibk_files/game.ibk", 56, "b56", false); +LoadIBK("fm_banks/ibk_files/mt_fm.ibk", 57, "b57", false); + +LoadJunglevision("fm_banks/op3_files/fat2.op3", 58, "fat2"); +LoadJunglevision("fm_banks/op3_files/fat4.op3", 59, "fat4"); +LoadJunglevision("fm_banks/op3_files/jv_2op.op3", 60, "b60"); +LoadJunglevision("fm_banks/op3_files/wallace.op3", 61, "b61"); + +LoadTMB("fm_banks/tmb_files/d3dtimbr.tmb", 62, "duke"); +LoadTMB("fm_banks/tmb_files/swtimbr.tmb", 63, "sw"); + +LoadDoom("fm_banks/raptor/genmidi.op2", 64, "rapt"); + +//LoadJunglevision("fm_banks/op3_files/fat2_modded.op3", 65, "b65M"); +LoadTMB("fm_banks/op3_files/gmopl_wohl_mod.tmb", 65, "b65"); + +//LoadIBK("fm_banks/ibk_files/JOconnel.IBK", 66, "b66M", false); +//LoadIBK("fm_banks/ibk_files/my-gmopldrums.IBK", 66, "b66P", true); +LoadTMB("fm_banks/op3_files/gmoconel.tmb", 66, "b66"); + +LoadTMB("fm_banks/tmb_files/default.tmb", 67, "3drm67"); +//LoadDoom("fm_banks/doom2/wolfinstein.op2", 67, "wolf"); //Small experiment! + +//LoadJunglevision("fm_banks/op3_files/2x2.op3", 68, "2x2byJAN"); +LoadMiles("fm_banks/op3_files/2x2.opl", 68, "2x2byJAN"); + +LoadTMB("fm_banks/tmb_files/bloodtmb.tmb", 69, "apgblood"); +LoadTMB("fm_banks/tmb_files/lee.tmb", 70, "apglee"); +LoadTMB("fm_banks/tmb_files/nam.tmb", 71, "apgnam"); + +LoadDoom("fm_banks/doom2/DMXOPL-by-sneakernets.op2", 72, "skeakernets"); + +//LoadBNK("bnk_files/grassman1.bnk", 63, "b63", false); +//LoadBNK("bnk_files/grassman2.bnk", 64, "b64", false); + +//LoadIBK("ibk_files/nitemare_3d.ibk", 65, "b65G", false); // Seems to be identical to wallace.op3 despite different format! +#endif diff --git a/utils/midiplay/Makefile b/utils/midiplay/Makefile new file mode 100644 index 0000000..f2512b4 --- /dev/null +++ b/utils/midiplay/Makefile @@ -0,0 +1,12 @@ +all: midiplay + +midiplay: adlmidiplay.o wave_writer.o + g++ $^ -Wl,-rpath='$$ORIGIN' -L../../bin -ladlmidi -lSDL2 -o ../../bin/adlmidiplay + rm *.o + +adlmidiplay.o: adlmidiplay.cpp + g++ -c $^ -I.. -o adlmidiplay.o + +wave_writer.o: wave_writer.c + gcc -c $^ -I.. -o wave_writer.o + diff --git a/utils/midiplay/Makefile.win32 b/utils/midiplay/Makefile.win32 new file mode 100644 index 0000000..05e192f --- /dev/null +++ b/utils/midiplay/Makefile.win32 @@ -0,0 +1,12 @@ +all: midiplay + +midiplay: adlmidiplay.o wave_writer.o + g++ $^ -L../../bin -ladlmidi -lSDL2 -o ../../bin/adlmidiplay + rm *.o + +adlmidiplay.o: adlmidiplay.cpp + g++ -c $^ -I.. -o adlmidiplay.o + +wave_writer.o: wave_writer.c + gcc -c $^ -I.. -o wave_writer.o + diff --git a/utils/midiplay/adlmidiplay.cpp b/utils/midiplay/adlmidiplay.cpp new file mode 100644 index 0000000..7c8766d --- /dev/null +++ b/utils/midiplay/adlmidiplay.cpp @@ -0,0 +1,338 @@ + +#include +#include +#include +#include +#include +#include +#include +#define SDL_MAIN_HANDLED +#include + +#include + +#include "wave_writer.h" + +class MutexType +{ + SDL_mutex *mut; +public: + MutexType() : mut(SDL_CreateMutex()) { } + ~MutexType() + { + SDL_DestroyMutex(mut); + } + void Lock() + { + SDL_mutexP(mut); + } + void Unlock() + { + SDL_mutexV(mut); + } +}; + + +static std::deque AudioBuffer; +static MutexType AudioBuffer_lock; + +static void SDL_AudioCallbackX(void *, Uint8 *stream, int len) +{ + SDL_LockAudio(); + short *target = (short *) stream; + AudioBuffer_lock.Lock(); + /*if(len != AudioBuffer.size()) + fprintf(stderr, "len=%d stereo samples, AudioBuffer has %u stereo samples", + len/4, (unsigned) AudioBuffer.size()/2);*/ + unsigned ate = (unsigned)len / 2; // number of shorts + if(ate > AudioBuffer.size()) + ate = (unsigned)AudioBuffer.size(); + for(unsigned a = 0; a < ate; ++a) + { + target[a] = AudioBuffer[a]; + } + AudioBuffer.erase(AudioBuffer.begin(), AudioBuffer.begin() + ate); + AudioBuffer_lock.Unlock(); + SDL_UnlockAudio(); +} + +static bool is_number(const std::string &s) +{ + std::string::const_iterator it = s.begin(); + while(it != s.end() && std::isdigit(*it)) ++it; + return !s.empty() && it == s.end(); +} + +static void printError(const char *err) +{ + std::fprintf(stderr, "\nERROR: %s\n\n", err); + std::fflush(stderr); +} + +static int stop = 0; +static void sighandler(int dum) +{ + if((dum == SIGINT) + || (dum == SIGTERM) + #ifndef _WIN32 + || (dum == SIGHUP) + #endif + ) + stop = 1; +} + +int main(int argc, char **argv) +{ + if(argc < 2 || std::string(argv[1]) == "--help" || std::string(argv[1]) == "-h") + { + std::printf( + "Usage: adlmidi [ ] [ [ [ ] ] ]\n" + " -p Enables adlib percussion instrument mode\n" + " -t Enables tremolo amplification mode\n" + " -v Enables vibrato amplification mode\n" + " -s Enables scaling of modulator volumes\n" + " -nl Quit without looping\n" + " -w Write WAV file rather than playing\n" + "\n" + "Where - number of embeeded bank or filepath to custom WOPL bank file\n" + "\n" + "Note: To create WOPL bank files use OPL Bank Editor you can get here: \n" + "https://github.com/Wohlstand/OPL3BankEditor\n" + "\n" + ); + + int banksCount = adl_getBanksCount(); + const char *const *banknames = adl_getBankNames(); + + if(banksCount > 0) + { + std::printf(" Available embedded banks by number:\n\n"); + + for(int a = 0; a < banksCount; ++a) + std::printf("%10s%2u = %s\n", a ? "" : "Banks:", a, banknames[a]); + + std::printf( + "\n" + " Use banks 2-5 to play Descent \"q\" soundtracks.\n" + " Look up the relevant bank number from descent.sng.\n" + "\n" + " The fourth parameter can be used to specify the number\n" + " of four-op channels to use. Each four-op channel eats\n" + " the room of two regular channels. Use as many as required.\n" + " The Doom & Hexen sets require one or two, while\n" + " Miles four-op set requires the maximum of numcards*6.\n" + "\n" + ); + } + else + { + std::printf(" This build of libADLMIDI has no embedded banks!\n\n"); + } + + return 0; + } + + //const unsigned MaxSamplesAtTime = 512; // 512=dbopl limitation + // How long is SDL buffer, in seconds? + // The smaller the value, the more often SDL_AudioCallBack() + // is called. + const double AudioBufferLength = 0.08; + // How much do WE buffer, in seconds? The smaller the value, + // the more prone to sound chopping we are. + const double OurHeadRoomLength = 0.1; + // The lag between visual content and audio content equals + // the sum of these two buffers. + SDL_AudioSpec spec; + SDL_AudioSpec obtained; + + spec.freq = 44100; + spec.format = AUDIO_S16SYS; + spec.channels = 2; + spec.samples = Uint16((double)spec.freq * AudioBufferLength); + spec.callback = SDL_AudioCallbackX; + + ADL_MIDIPlayer *myDevice; + myDevice = adl_init(44100); + if(myDevice == NULL) + { + printError("Failed to init MIDI device!\n"); + return 1; + } + + bool recordWave = false; + + adl_setLoopEnabled(myDevice, 1); + + while(argc > 2) + { + bool had_option = false; + + if(!std::strcmp("-p", argv[2])) + adl_setPercMode(myDevice, 1); + else if(!std::strcmp("-v", argv[2])) + adl_setHVibrato(myDevice, 1); + else if(!std::strcmp("-w", argv[2])) + { + recordWave = true; + adl_setLoopEnabled(myDevice, 0);//Disable loop while record WAV + } + else if(!std::strcmp("-t", argv[2])) + adl_setHTremolo(myDevice, 1); + else if(!std::strcmp("-nl", argv[2])) + adl_setLoopEnabled(myDevice, 0); + else if(!std::strcmp("-s", argv[2])) + adl_setScaleModulators(myDevice, 1); + else break; + + std::copy(argv + (had_option ? 4 : 3), argv + argc, + argv + 2); + argc -= (had_option ? 2 : 1); + } + + if(!recordWave) + { + // Set up SDL + if(SDL_OpenAudio(&spec, &obtained) < 0) + { + std::fprintf(stderr, "\nERROR: Couldn't open audio: %s\n\n", SDL_GetError()); + std::fflush(stderr); + //return 1; + } + if(spec.samples != obtained.samples) + { + std::fprintf(stderr, "Wanted (samples=%u,rate=%u,channels=%u); obtained (samples=%u,rate=%u,channels=%u)\n", + spec.samples, spec.freq, spec.channels, + obtained.samples, obtained.freq, obtained.channels); + std::fflush(stderr); + } + } + + if(argc >= 3) + { + if(is_number(argv[2])) + { + int bankno = std::atoi(argv[2]); + if(adl_setBank(myDevice, bankno) != 0) + { + printError(adl_errorString()); + return 1; + } + } + else + { + std::fprintf(stdout, "Loading custom bank file %s...", argv[2]); + std::fflush(stdout); + if(adl_openBankFile(myDevice, argv[2]) != 0) + { + std::fprintf(stdout, "FAILED!\n"); + std::fflush(stdout); + printError(adl_errorString()); + return 1; + } + std::fprintf(stdout, "OK!\n"); + std::fflush(stdout); + } + } + + if(argc >= 4) + { + if(adl_setNumCards(myDevice, std::atoi(argv[3])) != 0) + { + printError(adl_errorString()); + return 1; + } + std::fprintf(stdout, "Number of cards %s\n", argv[3]); + } + else + { + // 4 chips by default + if(adl_setNumCards(myDevice, 4) != 0) + { + printError(adl_errorString()); + return 1; + } + } + + if(argc >= 5) + { + if(adl_setNumFourOpsChn(myDevice, std::atoi(argv[4])) != 0) + { + printError(adl_errorString()); + return 1; + } + std::fprintf(stdout, "Number of four-ops %s\n", argv[4]); + } + + if(adl_openFile(myDevice, argv[1]) != 0) + { + printError(adl_errorString()); + return 2; + } + + signal(SIGINT, sighandler); + signal(SIGTERM, sighandler); + #ifndef _WIN32 + signal(SIGHUP, sighandler); + #endif + + if(!recordWave) + { + SDL_PauseAudio(0); + + while(!stop) + { + short buff[4096]; + size_t got = (size_t)adl_play(myDevice, 4096, buff); + if(got <= 0) + break; + + AudioBuffer_lock.Lock(); + size_t pos = AudioBuffer.size(); + AudioBuffer.resize(pos + got); + for(size_t p = 0; p < got; ++p) + AudioBuffer[pos + p] = buff[p]; + AudioBuffer_lock.Unlock(); + + const SDL_AudioSpec &spec = obtained; + while(AudioBuffer.size() > spec.samples + (spec.freq * 2) * OurHeadRoomLength) + { + SDL_Delay(1); + } + } + + SDL_CloseAudio(); + } + else + { + std::string wave_out = std::string(argv[1]) + ".wav"; + std::fprintf(stdout, "Recording WAV file %s...\n", wave_out.c_str()); + std::fflush(stdout); + + if(wave_open(spec.freq, wave_out.c_str()) == 0) + { + wave_enable_stereo(); + while(!stop) + { + short buff[4096]; + size_t got = (size_t)adl_play(myDevice, 4096, buff); + if(got <= 0) + break; + wave_write(buff, (long)got); + } + wave_close(); + + std::fprintf(stdout, "Completed!\n"); + std::fflush(stdout); + } + else + { + adl_close(myDevice); + return 1; + } + } + + adl_close(myDevice); + + return 0; +} + diff --git a/utils/midiplay/wave_writer.c b/utils/midiplay/wave_writer.c new file mode 100755 index 0000000..0bfaf68 --- /dev/null +++ b/utils/midiplay/wave_writer.c @@ -0,0 +1,170 @@ +/* snes_spc 0.9.0. http://www.slack.net/~ant/ */ + +#include "wave_writer.h" + +#include +#include +#include + +#ifdef _WIN32 +#include +#endif + +/* Copyright (C) 2003-2007 Shay Green. This module 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 +module 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 module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +enum { buf_size = 32768 * 2 }; +enum { header_size = 0x2C }; + +typedef short sample_t; + +static unsigned char* buf; +static FILE* file; +static long sample_count_; +static long sample_rate_; +static long buf_pos; +static int chan_count; + +static void exit_with_error( const char* str ) +{ + fprintf(stderr, "WAVE Writer Error: %s\n", str ); + fflush(stderr); +} + +int wave_open( long sample_rate, const char* filename ) +{ + sample_count_ = 0; + sample_rate_ = sample_rate; + buf_pos = header_size; + chan_count = 1; + + buf = (unsigned char*) malloc( buf_size * sizeof *buf ); + if ( !buf ) + { + exit_with_error( "Out of memory" ); + return -1; + } + +#ifndef _WIN32 + file = fopen( filename, "wb" ); +#else + wchar_t widePath[MAX_PATH]; + int size = MultiByteToWideChar(CP_UTF8, 0, filename, strlen(filename), widePath, MAX_PATH); + widePath[size] = '\0'; + file = _wfopen( widePath, L"wb" ); +#endif + if (!file) + { + exit_with_error( "Couldn't open WAVE file for writing" ); + return -1; + } + + setvbuf( file, 0, _IOFBF, 32 * 1024L ); + return 0; +} + +void wave_enable_stereo( void ) +{ + chan_count = 2; +} + +static void flush_() +{ + if ( buf_pos && !fwrite( buf, (size_t)buf_pos, 1, file ) ) + exit_with_error( "Couldn't write WAVE data" ); + buf_pos = 0; +} + +void wave_write( short const* in, long remain ) +{ + sample_count_ += remain; + while ( remain ) + { + if ( buf_pos >= buf_size ) + flush_(); + + { + unsigned char* p = &buf [buf_pos]; + long n = (buf_size - (unsigned long)buf_pos) / sizeof (sample_t); + if ( n > remain ) + n = remain; + remain -= n; + + /* convert to LSB first format */ + while ( n-- ) + { + int s = *in++; + *p++ = (unsigned char) s & (0x00FF); + *p++ = (unsigned char) (s >> 8) & (0x00FF); + } + + buf_pos = p - buf; + assert( buf_pos <= buf_size ); + } + } +} + +long wave_sample_count( void ) +{ + return sample_count_; +} + +static void set_le32( void* p, unsigned long n ) +{ + ((unsigned char*) p) [0] = (unsigned char) n & (0xFF); + ((unsigned char*) p) [1] = (unsigned char) (n >> 8) & (0xFF); + ((unsigned char*) p) [2] = (unsigned char) (n >> 16) & (0xFF); + ((unsigned char*) p) [3] = (unsigned char) (n >> 24) & (0xFF); +} + +void wave_close( void ) +{ + if ( file ) + { + /* generate header */ + unsigned char h [header_size] = + { + 'R','I','F','F', + 0,0,0,0, /* length of rest of file */ + 'W','A','V','E', + 'f','m','t',' ', + 0x10,0,0,0, /* size of fmt chunk */ + 1,0, /* uncompressed format */ + 0,0, /* channel count */ + 0,0,0,0, /* sample rate */ + 0,0,0,0, /* bytes per second */ + 0,0, /* bytes per sample frame */ + 16,0, /* bits per sample */ + 'd','a','t','a', + 0,0,0,0, /* size of sample data */ + /* ... */ /* sample data */ + }; + long ds = sample_count_ * (long)sizeof (sample_t); + int frame_size = chan_count * (long)sizeof (sample_t); + + set_le32( h + 0x04, header_size - 8 + ds ); + h [0x16] = (unsigned char)chan_count; + set_le32( h + 0x18, (unsigned long)sample_rate_ ); + set_le32( h + 0x1C, (unsigned long)sample_rate_ * (unsigned long)frame_size ); + h [0x20] = (unsigned char)frame_size; + set_le32( h + 0x28, (unsigned long)ds ); + + flush_(); + + /* write header */ + fseek( file, 0, SEEK_SET ); + fwrite( h, header_size, 1, file ); + fclose( file ); + file = 0; + free( buf ); + buf = 0; + } +} diff --git a/utils/midiplay/wave_writer.h b/utils/midiplay/wave_writer.h new file mode 100755 index 0000000..6d49718 --- /dev/null +++ b/utils/midiplay/wave_writer.h @@ -0,0 +1,21 @@ +/* WAVE sound file writer for recording 16-bit output during program development */ + +#pragma once +#ifndef WAVE_WRITER_H +#define WAVE_WRITER_H + +#ifdef __cplusplus + extern "C" { +#endif + +int wave_open( long sample_rate, const char* filename ); +void wave_enable_stereo( void ); +void wave_write( short const* in, long count ); +long wave_sample_count( void ); +void wave_close( void ); + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/utils/test/adldatatest.cc b/utils/test/adldatatest.cc new file mode 100644 index 0000000..9f992c0 --- /dev/null +++ b/utils/test/adldatatest.cc @@ -0,0 +1,2 @@ +static const int adldata[2184] = { +1,1,1,129,1,1,1,1,12,7,23,152,24,21,69,3,113,114,112,35,97,36,97,33,2,3,35,3,3,35,35,9,33,49,49,49,1,33,49,49,49,49,113,33,241,2,2,16,33,161,161,33,49,161,113,144,33,33,33,49,33,97,161,33,49,49,49,49,33,49,49,50,225,225,161,49,225,98,98,98,34,33,34,33,33,162,32,33,119,97,97,113,33,161,33,161,58,33,6,34,65,97,97,164,2,17,17,147,4,33,49,32,5,7,5,24,16,17,1,14,6,14,14,213,53,14,38,0,16,16,2,0,0,0,0,12,0,12,0,12,0,0,14,0,14,14,14,2,78,17,14,128,14,6,1,1,1,1,1,0,3,3,14,14,215,215,128,128,6,6,6,1,65,10,10,14,14,5,2,1,0,0,1,1,1,65,1,1,22,1,129,17,1,129,1,1,129,129,49,48,177,177,177,177,33,161,65,17,33,33,33,33,33,132,162,49,49,50,33,33,49,49,33,33,49,35,225,1,1,17,162,33,97,97,114,97,114,65,33,33,97,33,33,34,33,33,97,97,97,97,33,33,50,33,225,225,33,33,161,161,161,161,33,33,33,161,34,97,96,33,161,177,97,114,162,33,97,33,81,33,1,97,66,163,161,97,7,19,17,145,1,34,33,33,3,2,1,18,0,16,16,192,3,208,192,218,20,208,228,0,17,17,17,0,1,0,0,18,0,18,0,18,0,0,208,0,7,208,7,5,158,16,208,16,7,2,2,1,2,2,0,0,12,12,0,3,199,199,17,17,21,18,18,2,66,30,30,0,7,4,21,2,0,0,143,75,73,18,87,147,128,146,92,151,33,98,35,145,89,73,146,20,68,147,19,72,19,19,156,84,95,135,71,74,74,161,30,18,141,91,139,139,139,18,21,22,73,77,64,26,29,65,155,152,147,24,91,144,87,0,146,148,148,67,155,138,134,77,143,142,145,142,75,144,129,144,31,70,156,139,76,203,153,147,89,14,70,69,139,158,26,143,165,31,23,93,151,28,137,21,206,21,91,146,77,148,140,76,133,12,6,145,79,73,133,4,106,21,157,150,134,65,142,0,128,0,0,149,92,0,0,0,68,68,7,0,2,0,0,0,0,0,0,0,0,0,0,0,8,0,10,3,0,69,0,0,8,11,0,81,84,89,0,128,128,133,64,64,220,220,0,0,63,63,63,88,69,64,124,64,10,5,63,79,0,0,6,0,0,0,0,0,14,0,0,128,0,0,0,0,128,128,0,0,0,0,128,0,0,137,128,0,0,128,0,5,0,128,0,0,0,0,64,8,0,0,0,0,0,128,0,128,128,0,1,0,0,0,131,0,0,0,1,5,0,0,0,6,131,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,64,0,128,0,128,0,0,0,0,3,0,0,0,0,131,0,128,128,0,3,128,0,0,0,0,0,129,128,0,0,0,3,3,0,0,136,5,0,64,8,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,74,10,93,10,0,8,0,13,74,0,0,0,0,0,0,0,8,0,8,0,0,0,0,9,0,0,0,0,8,78,82,8,64,64,0,0,0,0,242,242,242,242,241,241,161,194,246,243,84,243,246,246,211,117,246,199,170,151,151,152,145,113,243,243,241,246,249,145,149,32,148,241,241,81,161,162,244,241,221,221,209,113,241,245,245,245,177,127,193,193,244,116,84,84,133,117,118,158,97,117,114,84,147,147,147,147,170,126,117,155,133,136,117,132,102,118,87,119,255,255,134,102,146,223,239,241,83,168,145,84,33,161,17,17,248,33,116,177,241,17,17,243,210,163,246,212,250,124,221,218,241,236,103,250,168,248,241,31,248,248,246,55,178,246,255,243,248,248,249,252,255,252,246,246,246,246,246,246,246,246,246,246,248,245,228,180,246,248,246,255,248,245,250,250,250,250,249,249,248,248,118,200,173,168,246,245,0,0,0,103,248,224,224,122,228,249,0,250,246,0,242,242,242,242,242,242,242,194,243,242,244,242,231,246,163,181,241,199,138,85,85,70,97,97,243,241,242,243,246,132,148,209,195,241,241,113,242,161,241,241,86,102,97,114,111,133,243,242,114,63,79,79,138,113,122,165,143,143,130,98,127,116,113,166,114,114,130,114,143,139,97,114,101,101,117,101,101,85,86,118,255,255,100,150,145,111,143,244,160,37,85,106,66,49,66,207,134,65,165,242,242,17,29,129,242,162,242,235,194,111,86,143,195,248,223,248,250,243,243,31,86,52,31,86,244,79,18,246,243,243,248,250,255,250,246,251,246,123,246,203,246,246,159,246,244,159,245,151,159,243,159,255,244,245,200,250,248,248,250,246,246,246,119,155,141,136,103,70,247,247,247,117,117,255,255,123,85,214,247,248,246,0,244,244,244,247,247,247,242,248,244,242,244,246,246,246,243,245,20,88,24,35,4,42,6,6,148,154,58,34,84,65,25,79,6,40,232,40,154,22,232,40,19,19,28,18,33,117,117,5,37,3,18,34,21,57,5,99,23,23,21,23,106,31,85,60,2,3,3,15,22,23,25,33,95,95,31,88,86,70,7,7,3,15,85,18,42,5,1,41,148,17,52,1,67,119,51,71,246,35,149,129,81,81,49,115,83,17,65,50,86,32,51,5,229,38,53,40,7,71,6,0,36,0,0,163,97,0,1,240,119,119,255,5,7,5,12,8,12,8,12,2,12,12,0,12,66,48,228,4,0,55,0,3,66,12,191,135,141,136,10,137,136,136,79,73,5,4,6,5,244,244,244,231,72,240,240,74,228,50,243,141,12,0,247,247,246,247,247,247,245,248,245,241,244,246,247,246,243,245,7,8,8,20,4,26,7,7,200,231,248,248,58,25,25,248,166,24,120,72,223,223,120,24,38,6,12,6,22,53,244,195,8,7,5,5,5,103,5,69,9,9,55,44,10,15,24,28,11,9,9,15,10,12,25,23,26,26,10,26,38,54,7,7,15,15,24,10,42,7,6,9,5,3,22,3,53,71,37,7,2,19,114,38,245,19,3,35,246,229,230,17,5,12,22,11,229,22,5,229,3,3,2,255,132,4,2,55,21,245,22,201,6,6,255,23,8,23,6,71,6,71,6,67,6,6,2,6,228,2,229,247,2,5,2,20,228,8,151,183,184,182,6,108,182,182,24,105,5,4,23,22,245,245,245,7,5,5,2,27,57,165,245,181,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,1,1,1,0,1,1,0,1,0,1,1,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,0,0,1,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,2,1,0,0,1,0,0,0,0,0,0,0,0,1,0,1,0,1,0,0,1,1,0,1,0,1,1,0,0,0,1,2,0,0,0,0,0,2,2,0,0,0,0,0,2,0,0,0,2,2,0,2,0,2,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,2,0,3,0,0,0,0,0,0,3,3,3,3,0,0,3,3,3,2,0,3,0,0,0,3,3,0,3,3,3,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,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,2,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,2,1,0,1,0,0,0,0,0,0,0,0,0,3,2,3,3,0,0,3,1,2,0,0,0,0,0,0,0,2,0,2,0,2,0,0,3,0,3,0,1,0,3,0,3,0,3,0,0,0,0,0,0,0,0,0,2,2,0,0,3,3,0,0,0,0,0,0,0,2,1,0,0,0,0,0,8,8,8,6,0,0,8,10,0,2,2,0,0,4,12,4,2,2,4,4,0,12,10,6,12,12,0,6,0,8,8,8,2,10,10,12,8,8,10,10,8,8,8,2,2,0,0,2,14,0,10,12,0,0,12,8,12,12,12,2,2,8,0,8,8,8,10,10,8,6,0,4,0,0,2,0,0,0,11,11,0,0,0,0,0,2,0,10,2,10,12,0,8,0,10,0,2,0,0,12,0,6,6,4,0,0,4,8,12,6,10,6,6,10,8,10,6,4,14,14,14,14,14,0,10,14,14,14,8,8,8,14,0,14,4,10,4,10,4,10,4,4,14,4,14,14,6,14,14,8,14,12,14,6,7,6,6,6,14,14,15,15,14,14,14,14,14,14,1,0,1,0,0,8,8,14,6,14,8,7,4,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,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,0,0,0,35,35,52,48,58,60,47,43,49,43,51,43,54,57,72,60,76,84,36,65,84,83,84,24,77,60,65,59,51,45,71,60,58,53,64,71,61,61,44,40,69,68,63,74,60,80,64,72,73,70,68,48,53,0}; diff --git a/utils/test/test.cc b/utils/test/test.cc new file mode 100644 index 0000000..ff8515b --- /dev/null +++ b/utils/test/test.cc @@ -0,0 +1,202 @@ +#include +static const unsigned char adl[182][12] = +{ +// The data bytes are: +// [0,1] AM/VIB/EG/KSR/Multiple bits for carrier and modulator respectively +// [2,3] KSL/Attenuation settings for carrier and modulator respectively +// [4,5] Attack and decay rates for carrier and modulator respectively +// [6,7] Sustain and release rates for carrier and modulator respectively +// [8,9] Wave select settings for carrier and modulator respectively +// [10] Feedback/connection bits for the channel (also stereo/pan bits) +// [11] For percussive instruments (GP35..GP87), the tone to play + { 1, 1,143, 6,242,242,244,247,0,0, 56, 0}, // GM1:AcouGrandPiano + { 1, 1, 75, 0,242,242,244,247,0,0, 56, 0}, // GM2:BrightAcouGrand + { 1, 1, 73, 0,242,242,244,246,0,0, 56, 0}, // GM3:ElecGrandPiano + { 129, 65, 18, 0,242,242,247,247,0,0, 54, 0}, // GM4:Honky-tonkPiano + { 1, 1, 87, 0,241,242,247,247,0,0, 48, 0}, // GM5:Rhodes Piano + { 1, 1,147, 0,241,242,247,247,0,0, 48, 0}, // GM6:Chorused Piano + { 1, 22,128, 14,161,242,242,245,0,0, 56, 0}, // GM7:Harpsichord + { 1, 1,146, 0,194,194,248,248,0,0, 58, 0}, // GM8:Clavinet + { 12,129, 92, 0,246,243,244,245,0,0, 48, 0}, // GM9:Celesta + { 7, 17,151,128,243,242,242,241,0,0, 50, 0}, // GM10:Glockenspiel + { 23, 1, 33, 0, 84,244,244,244,0,0, 50, 0}, // GM11:Music box + { 152,129, 98, 0,243,242,246,246,0,0, 48, 0}, // GM12:Vibraphone + { 24, 1, 35, 0,246,231,246,247,0,0, 48, 0}, // GM13:Marimba + { 21, 1,145, 0,246,246,246,246,0,0, 52, 0}, // GM14:Xylophone + { 69,129, 89,128,211,163,243,243,0,0, 60, 0}, // GM15:Tubular Bells + { 3,129, 73,128,117,181,245,245,1,0, 52, 0}, // GM16:Dulcimer + { 113, 49,146, 0,246,241, 20, 7,0,0, 50, 0}, // GM17:Hammond Organ + { 114, 48, 20, 0,199,199, 88, 8,0,0, 50, 0}, // GM18:Percussive Organ + { 112,177, 68, 0,170,138, 24, 8,0,0, 52, 0}, // GM19:Rock Organ + { 35,177,147, 0,151, 85, 35, 20,1,0, 52, 0}, // GM20:Church Organ + { 97,177, 19,128,151, 85, 4, 4,1,0, 48, 0}, // GM21:Reed Organ + { 36,177, 72, 0,152, 70, 42, 26,1,0, 60, 0}, // GM22:Accordion + { 97, 33, 19, 0,145, 97, 6, 7,1,0, 58, 0}, // GM23:Harmonica + { 33,161, 19,137,113, 97, 6, 7,0,0, 54, 0}, // GM24:Tango Accordion + { 2, 65,156,128,243,243,148,200,1,0, 60, 0}, // GM25:Acoustic Guitar1 + { 3, 17, 84, 0,243,241,154,231,1,0, 60, 0}, // GM26:Acoustic Guitar2 + { 35, 33, 95, 0,241,242, 58,248,0,0, 48, 0}, // GM27:Electric Guitar1 + { 3, 33,135,128,246,243, 34,248,1,0, 54, 0}, // GM28:Electric Guitar2 + { 3, 33, 71, 0,249,246, 84, 58,0,0, 48, 0}, // GM29:Electric Guitar3 + { 35, 33, 74, 5,145,132, 65, 25,1,0, 56, 0}, // GM30:Overdrive Guitar + { 35, 33, 74, 0,149,148, 25, 25,1,0, 56, 0}, // GM31:Distorton Guitar + { 9,132,161,128, 32,209, 79,248,0,0, 56, 0}, // GM32:Guitar Harmonics + { 33,162, 30, 0,148,195, 6,166,0,0, 50, 0}, // GM33:Acoustic Bass + { 49, 49, 18, 0,241,241, 40, 24,0,0, 58, 0}, // GM34:Electric Bass 1 + { 49, 49,141, 0,241,241,232,120,0,0, 58, 0}, // GM35:Electric Bass 2 + { 49, 50, 91, 0, 81,113, 40, 72,0,0, 60, 0}, // GM36:Fretless Bass + { 1, 33,139, 64,161,242,154,223,0,0, 56, 0}, // GM37:Slap Bass 1 + { 33, 33,139, 8,162,161, 22,223,0,0, 56, 0}, // GM38:Slap Bass 2 + { 49, 49,139, 0,244,241,232,120,0,0, 58, 0}, // GM39:Synth Bass 1 + { 49, 49, 18, 0,241,241, 40, 24,0,0, 58, 0}, // GM40:Synth Bass 2 + { 49, 33, 21, 0,221, 86, 19, 38,1,0, 56, 0}, // GM41:Violin + { 49, 33, 22, 0,221,102, 19, 6,1,0, 56, 0}, // GM42:Viola + { 113, 49, 73, 0,209, 97, 28, 12,1,0, 56, 0}, // GM43:Cello + { 33, 35, 77,128,113,114, 18, 6,1,0, 50, 0}, // GM44:Contrabass + { 241,225, 64, 0,241,111, 33, 22,1,0, 50, 0}, // GM45:Tremulo Strings + { 2, 1, 26,128,245,133,117, 53,1,0, 48, 0}, // GM46:Pizzicato String + { 2, 1, 29,128,245,243,117,244,1,0, 48, 0}, // GM47:Orchestral Harp + { 16, 17, 65, 0,245,242, 5,195,1,0, 50, 0}, // GM48:Timpany + { 33,162,155, 1,177,114, 37, 8,1,0, 62, 0}, // GM49:String Ensemble1 + { 161, 33,152, 0,127, 63, 3, 7,1,1, 48, 0}, // GM50:String Ensemble2 + { 161, 97,147, 0,193, 79, 18, 5,0,0, 58, 0}, // GM51:Synth Strings 1 + { 33, 97, 24, 0,193, 79, 34, 5,0,0, 60, 0}, // GM52:SynthStrings 2 + { 49,114, 91,131,244,138, 21, 5,0,0, 48, 0}, // GM53:Choir Aahs + { 161, 97,144, 0,116,113, 57,103,0,0, 48, 0}, // GM54:Voice Oohs + { 113,114, 87, 0, 84,122, 5, 5,0,0, 60, 0}, // GM55:Synth Voice + { 144, 65, 0, 0, 84,165, 99, 69,0,0, 56, 0}, // GM56:Orchestra Hit + { 33, 33,146, 1,133,143, 23, 9,0,0, 60, 0}, // GM57:Trumpet + { 33, 33,148, 5,117,143, 23, 9,0,0, 60, 0}, // GM58:Trombone + { 33, 97,148, 0,118,130, 21, 55,0,0, 60, 0}, // GM59:Tuba + { 49, 33, 67, 0,158, 98, 23, 44,1,1, 50, 0}, // GM60:Muted Trumpet + { 33, 33,155, 0, 97,127,106, 10,0,0, 50, 0}, // GM61:French Horn + { 97, 34,138, 6,117,116, 31, 15,0,0, 56, 0}, // GM62:Brass Section + { 161, 33,134,131,114,113, 85, 24,1,0, 48, 0}, // GM63:Synth Brass 1 + { 33, 33, 77, 0, 84,166, 60, 28,0,0, 56, 0}, // GM64:Synth Brass 2 + { 49, 97,143, 0,147,114, 2, 11,1,0, 56, 0}, // GM65:Soprano Sax + { 49, 97,142, 0,147,114, 3, 9,1,0, 56, 0}, // GM66:Alto Sax + { 49, 97,145, 0,147,130, 3, 9,1,0, 58, 0}, // GM67:Tenor Sax + { 49, 97,142, 0,147,114, 15, 15,1,0, 58, 0}, // GM68:Baritone Sax + { 33, 33, 75, 0,170,143, 22, 10,1,0, 56, 0}, // GM69:Oboe + { 49, 33,144, 0,126,139, 23, 12,1,1, 54, 0}, // GM70:English Horn + { 49, 50,129, 0,117, 97, 25, 25,1,0, 48, 0}, // GM71:Bassoon + { 50, 33,144, 0,155,114, 33, 23,0,0, 52, 0}, // GM72:Clarinet + { 225,225, 31, 0,133,101, 95, 26,0,0, 48, 0}, // GM73:Piccolo + { 225,225, 70, 0,136,101, 95, 26,0,0, 48, 0}, // GM74:Flute + { 161, 33,156, 0,117,117, 31, 10,0,0, 50, 0}, // GM75:Recorder + { 49, 33,139, 0,132,101, 88, 26,0,0, 48, 0}, // GM76:Pan Flute + { 225,161, 76, 0,102,101, 86, 38,0,0, 48, 0}, // GM77:Bottle Blow + { 98,161,203, 0,118, 85, 70, 54,0,0, 48, 0}, // GM78:Shakuhachi + { 98,161,153, 0, 87, 86, 7, 7,0,0, 59, 0}, // GM79:Whistle + { 98,161,147, 0,119,118, 7, 7,0,0, 59, 0}, // GM80:Ocarina + { 34, 33, 89, 0,255,255, 3, 15,2,0, 48, 0}, // GM81:Lead 1 squareea + { 33, 33, 14, 0,255,255, 15, 15,1,1, 48, 0}, // GM82:Lead 2 sawtooth + { 34, 33, 70,128,134,100, 85, 24,0,0, 48, 0}, // GM83:Lead 3 calliope + { 33,161, 69, 0,102,150, 18, 10,0,0, 48, 0}, // GM84:Lead 4 chiff + { 33, 34,139, 0,146,145, 42, 42,1,0, 48, 0}, // GM85:Lead 5 charang + { 162, 97,158, 64,223,111, 5, 7,0,0, 50, 0}, // GM86:Lead 6 voice + { 32, 96, 26, 0,239,143, 1, 6,0,2, 48, 0}, // GM87:Lead 7 fifths + { 33, 33,143,128,241,244, 41, 9,0,0, 58, 0}, // GM88:Lead 8 brass + { 119,161,165, 0, 83,160,148, 5,0,0, 50, 0}, // GM89:Pad 1 new age + { 97,177, 31,128,168, 37, 17, 3,0,0, 58, 0}, // GM90:Pad 2 warm + { 97, 97, 23, 0,145, 85, 52, 22,0,0, 60, 0}, // GM91:Pad 3 polysynth + { 113,114, 93, 0, 84,106, 1, 3,0,0, 48, 0}, // GM92:Pad 4 choir + { 33,162,151, 0, 33, 66, 67, 53,0,0, 56, 0}, // GM93:Pad 5 bowedpad + { 161, 33, 28, 0,161, 49,119, 71,1,1, 48, 0}, // GM94:Pad 6 metallic + { 33, 97,137, 3, 17, 66, 51, 37,0,0, 58, 0}, // GM95:Pad 7 halo + { 161, 33, 21, 0, 17,207, 71, 7,1,0, 48, 0}, // GM96:Pad 8 sweep + { 58, 81,206, 0,248,134,246, 2,0,0, 50, 0}, // GM97:FX 1 rain + { 33, 33, 21, 0, 33, 65, 35, 19,1,0, 48, 0}, // GM98:FX 2 soundtrack + { 6, 1, 91, 0,116,165,149,114,0,0, 48, 0}, // GM99:FX 3 crystal + { 34, 97,146,131,177,242,129, 38,0,0, 60, 0}, // GM100:FX 4 atmosphere + { 65, 66, 77, 0,241,242, 81,245,1,0, 48, 0}, // GM101:FX 5 brightness + { 97,163,148,128, 17, 17, 81, 19,1,0, 54, 0}, // GM102:FX 6 goblins + { 97,161,140,128, 17, 29, 49, 3,0,0, 54, 0}, // GM103:FX 7 echoes + { 164, 97, 76, 0,243,129,115, 35,1,0, 52, 0}, // GM104:FX 8 sci-fi + { 2, 7,133, 3,210,242, 83,246,0,1, 48, 0}, // GM105:Sitar + { 17, 19, 12,128,163,162, 17,229,1,0, 48, 0}, // GM106:Banjo + { 17, 17, 6, 0,246,242, 65,230,1,2, 52, 0}, // GM107:Shamisen + { 147,145,145, 0,212,235, 50, 17,0,1, 56, 0}, // GM108:Koto + { 4, 1, 79, 0,250,194, 86, 5,0,0, 60, 0}, // GM109:Kalimba + { 33, 34, 73, 0,124,111, 32, 12,0,1, 54, 0}, // GM110:Bagpipe + { 49, 33,133, 0,221, 86, 51, 22,1,0, 58, 0}, // GM111:Fiddle + { 32, 33, 4,129,218,143, 5, 11,2,0, 54, 0}, // GM112:Shanai + { 5, 3,106,128,241,195,229,229,0,0, 54, 0}, // GM113:Tinkle Bell + { 7, 2, 21, 0,236,248, 38, 22,0,0, 58, 0}, // GM114:Agogo Bells + { 5, 1,157, 0,103,223, 53, 5,0,0, 56, 0}, // GM115:Steel Drums + { 24, 18,150, 0,250,248, 40,229,0,0, 58, 0}, // GM116:Woodblock + { 16, 0,134, 3,168,250, 7, 3,0,0, 54, 0}, // GM117:Taiko Drum + { 17, 16, 65, 3,248,243, 71, 3,2,0, 52, 0}, // GM118:Melodic Tom + { 1, 16,142, 0,241,243, 6, 2,2,0, 62, 0}, // GM119:Synth Drum + { 14,192, 0, 0, 31, 31, 0,255,0,3, 62, 0}, // GM120:Reverse Cymbal + { 6, 3,128,136,248, 86, 36,132,0,2, 62, 0}, // GM121:Guitar FretNoise + { 14,208, 0, 5,248, 52, 0, 4,0,3, 62, 0}, // GM122:Breath Noise + { 14,192, 0, 0,246, 31, 0, 2,0,3, 62, 0}, // GM123:Seashore + { 213,218,149, 64, 55, 86,163, 55,0,0, 48, 0}, // GM124:Bird Tweet + { 53, 20, 92, 8,178,244, 97, 21,2,0, 58, 0}, // GM125:Telephone + { 14,208, 0, 0,246, 79, 0,245,0,3, 62, 0}, // GM126:Helicopter + { 38,228, 0, 0,255, 18, 1, 22,0,1, 62, 0}, // GM127:Applause/Noise + { 0, 0, 0, 0,243,246,240,201,0,2, 62, 0}, // GM128:Gunshot + { 16, 17, 68, 0,248,243,119, 6,2,0, 56, 35}, // GP35:Ac Bass Drum + { 16, 17, 68, 0,248,243,119, 6,2,0, 56, 35}, // GP36:Bass Drum 1 + { 2, 17, 7, 0,249,248,255,255,0,0, 56, 52}, // GP37:Side Stick + { 0, 0, 0, 0,252,250, 5, 23,2,0, 62, 48}, // GP38:Acoustic Snare + { 0, 1, 2, 0,255,255, 7, 8,0,0, 48, 58}, // GP39:Hand Clap + { 0, 0, 0, 0,252,250, 5, 23,2,0, 62, 60}, // GP40:Electric Snare + { 0, 0, 0, 0,246,246, 12, 6,0,0, 52, 47}, // GP41:Low Floor Tom + { 12, 18, 0, 0,246,251, 8, 71,0,2, 58, 43}, // GP42:Closed High Hat + { 0, 0, 0, 0,246,246, 12, 6,0,0, 52, 49}, // GP43:High Floor Tom + { 12, 18, 0, 5,246,123, 8, 71,0,2, 58, 43}, // GP44:Pedal High Hat + { 0, 0, 0, 0,246,246, 12, 6,0,0, 52, 51}, // GP45:Low Tom + { 12, 18, 0, 0,246,203, 2, 67,0,2, 58, 43}, // GP46:Open High Hat + { 0, 0, 0, 0,246,246, 12, 6,0,0, 52, 54}, // GP47:Low-Mid Tom + { 0, 0, 0, 0,246,246, 12, 6,0,0, 52, 57}, // GP48:High-Mid Tom + { 14,208, 0, 0,246,159, 0, 2,0,3, 62, 72}, // GP49:Crash Cymbal 1 + { 0, 0, 0, 0,246,246, 12, 6,0,0, 52, 60}, // GP50:High Tom + { 14, 7, 8, 74,248,244, 66,228,0,3, 62, 76}, // GP51:Ride Cymbal 1 + { 14,208, 0, 10,245,159, 48, 2,0,0, 62, 84}, // GP52:Chinese Cymbal + { 14, 7, 10, 93,228,245,228,229,3,1, 54, 36}, // GP53:Ride Bell + { 2, 5, 3, 10,180,151, 4,247,0,0, 62, 65}, // GP54:Tambourine + { 78,158, 0, 0,246,159, 0, 2,0,3, 62, 84}, // GP55:Splash Cymbal + { 17, 16, 69, 8,248,243, 55, 5,2,0, 56, 83}, // GP56:Cow Bell + { 14,208, 0, 0,246,159, 0, 2,0,3, 62, 84}, // GP57:Crash Cymbal 2 + { 128, 16, 0, 13,255,255, 3, 20,3,0, 60, 24}, // GP58:Vibraslap + { 14, 7, 8, 74,248,244, 66,228,0,3, 62, 77}, // GP59:Ride Cymbal 2 + { 6, 2, 11, 0,245,245, 12, 8,0,0, 54, 60}, // GP60:High Bongo + { 1, 2, 0, 0,250,200,191,151,0,0, 55, 65}, // GP61:Low Bongo + { 1, 1, 81, 0,250,250,135,183,0,0, 54, 59}, // GP62:Mute High Conga + { 1, 2, 84, 0,250,248,141,184,0,0, 54, 51}, // GP63:Open High Conga + { 1, 2, 89, 0,250,248,136,182,0,0, 54, 45}, // GP64:Low Conga + { 1, 0, 0, 0,249,250, 10, 6,3,0, 62, 71}, // GP65:High Timbale + { 0, 0,128, 0,249,246,137,108,3,0, 62, 60}, // GP66:Low Timbale + { 3, 12,128, 8,248,246,136,182,3,0, 63, 58}, // GP67:High Agogo + { 3, 12,133, 0,248,246,136,182,3,0, 63, 53}, // GP68:Low Agogo + { 14, 0, 64, 8,118,119, 79, 24,0,2, 62, 64}, // GP69:Cabasa + { 14, 3, 64, 0,200,155, 73,105,0,2, 62, 71}, // GP70:Maracas + { 215,199,220, 0,173,141, 5, 5,3,0, 62, 61}, // GP71:Short Whistle + { 215,199,220, 0,168,136, 4, 4,3,0, 62, 61}, // GP72:Long Whistle + { 128, 17, 0, 0,246,103, 6, 23,3,3, 62, 44}, // GP73:Short Guiro + { 128, 17, 0, 9,245, 70, 5, 22,2,3, 62, 40}, // GP74:Long Guiro + { 6, 21, 63, 0, 0,247,244,245,0,0, 49, 69}, // GP75:Claves + { 6, 18, 63, 0, 0,247,244,245,3,0, 48, 68}, // GP76:High Wood Block + { 6, 18, 63, 0, 0,247,244,245,0,0, 49, 63}, // GP77:Low Wood Block + { 1, 2, 88, 0,103,117,231, 7,0,0, 48, 74}, // GP78:Mute Cuica + { 65, 66, 69, 8,248,117, 72, 5,0,0, 48, 60}, // GP79:Open Cuica + { 10, 30, 64, 78,224,255,240, 5,3,0, 56, 80}, // GP80:Mute Triangle + { 10, 30,124, 82,224,255,240, 2,3,0, 56, 64}, // GP81:Open Triangle + { 14, 0, 64, 8,122,123, 74, 27,0,2, 62, 72}, // GP82 + { 14, 7, 10, 64,228, 85,228, 57,3,1, 54, 73}, // GP83 + { 5, 4, 5, 64,249,214, 50,165,3,0, 62, 70}, // GP84 + { 2, 21, 63, 0, 0,247,243,245,3,0, 56, 68}, // GP85 + { 1, 2, 79, 0,250,248,141,181,0,0, 55, 48}, // GP86 + { 0, 0, 0, 0,246,246, 12, 6,0,0, 52, 53} // GP87 (low-low-mid tom?) +}; +int main() +{ + printf("static const int adldata[2184] = {\n"); + for(unsigned x=0; x<12; ++x) + for(unsigned i=0; i<182; ++i) + printf(",%d", + (x==10 ? adl[i][x]&~0x30 : adl[i][x])); + printf("};\n"); +} -- cgit v1.2.3