From dccd30f73cf8a68bf6765cad533f7d6887dc2171 Mon Sep 17 00:00:00 2001 From: cam900 Date: Sat, 9 Apr 2022 00:42:27 +0900 Subject: [PATCH 01/76] Fix loop area view in sample editor --- src/gui/sampleEdit.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gui/sampleEdit.cpp b/src/gui/sampleEdit.cpp index b976ab92..18a91e29 100644 --- a/src/gui/sampleEdit.cpp +++ b/src/gui/sampleEdit.cpp @@ -605,7 +605,7 @@ void FurnaceGUI::drawSampleEdit() { ImU32 centerLineColor=ImAlphaBlendColors(bgColor,ImGui::GetColorU32(ImGuiCol_PlotLines,0.25)); for (int i=0; iloopStart>=0 && sample->loopStart<(int)sample->samples && j-samplePos>sample->loopStart) { + if (sample->loopStart>=0 && sample->loopStart<(int)sample->samples && ((j+samplePos)*sampleZoom)>sample->loopStart) { data[i*availX+j]=bgColorLoop; } else { data[i*availX+j]=bgColor; @@ -870,4 +870,4 @@ void FurnaceGUI::doRedoSample() { updateSampleTex=true; } }); -} \ No newline at end of file +} From 48e8e49ba8f3d64a6d68c827d924b333a31e4c47 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 8 Apr 2022 12:21:42 -0500 Subject: [PATCH 02/76] whoops! --- src/engine/waveSynth.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/engine/waveSynth.h b/src/engine/waveSynth.h index 70fb2738..ccd8b23d 100644 --- a/src/engine/waveSynth.h +++ b/src/engine/waveSynth.h @@ -75,8 +75,8 @@ class DivWaveSynth { height(31), first(false), activeChangedB(false) { - memset(wave1,0,sizeof(int)*256); - memset(wave2,0,sizeof(int)*256); + memset(wave1,0,256); + memset(wave2,0,256); memset(output,0,sizeof(int)*256); } }; From 5b95cf9db949c68ed717a49e2e9e1eddbb2564b5 Mon Sep 17 00:00:00 2001 From: OPNA2608 Date: Mon, 28 Mar 2022 15:38:35 +0200 Subject: [PATCH 03/76] Add new CI job to prepare for artifact uploads --- .github/workflows/build.yml | 198 +++++++++++++++++- .../SDL-Fix-MSVC-static-runtime-linking.patch | 35 ++++ 2 files changed, 231 insertions(+), 2 deletions(-) create mode 100644 extern/SDL-Fix-MSVC-static-runtime-linking.patch diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4dce0467..e53d720c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -14,6 +14,7 @@ env: BUILD_TYPE: Release jobs: + # Do a plain build, like we would expect a user to do it on their end. build: strategy: matrix: @@ -24,7 +25,7 @@ jobs: - { name: 'Ubuntu', os: ubuntu-18.04, shell: bash } fail-fast: false - name: ${{ matrix.config.name }} + name: "Build: ${{ matrix.config.name }}" runs-on: ${{ matrix.config.os }} defaults: run: @@ -81,7 +82,7 @@ jobs: if [ '${{ matrix.config.compiler }}' == 'mingw' ]; then CMAKE_EXTRA_ARGS+=('-G' 'MSYS Makefiles') elif [ '${{ matrix.config.compiler }}' == 'msvc' ]; then - # We don't want all the MSVC warnings to cause errors yet + # FIXME We don't want all the MSVC warnings to cause errors yet export USE_WAE=OFF fi fi @@ -106,3 +107,196 @@ jobs: cmake \ --install ${PWD}/build \ --config ${{ env.BUILD_TYPE }} + + # Now do a build that we can package. (static runtime linking on MSVC, zipping on Windows, CPack on Darwin, appimage stuff on Ubuntu) + # We rebuild here because the build dependencies may be slightly different and might trigger a full rebuild anyway. + package: + needs: build + strategy: + matrix: + config: + - { name: 'Windows MSVC', os: windows-latest, compiler: msvc, shell: bash } + - { name: 'Windows MinGW', os: windows-latest, compiler: mingw, shell: 'msys2 {0}' } + - { name: 'macOS', os: macos-latest, shell: bash } + - { name: 'Ubuntu', os: ubuntu-18.04, shell: bash } + fail-fast: false + + name: "Package: ${{ matrix.config.name }}" + runs-on: ${{ matrix.config.os }} + defaults: + run: + shell: ${{ matrix.config.shell }} + + steps: + - name: Checkout + uses: actions/checkout@v2 + with: + submodules: recursive + + - name: Setup Toolchain [Windows MSVC] + if: ${{ runner.os == 'Windows' && matrix.config.compiler == 'msvc' }} + uses: seanmiddleditch/gha-setup-vsdevenv@v3 + + - name: Setup Toolchain [Windows MinGW] + if: ${{ runner.os == 'Windows' && matrix.config.compiler == 'mingw' }} + uses: msys2/setup-msys2@v2 + with: + msystem: MINGW64 + update: true + install: | + mingw-w64-x86_64-toolchain + mingw-w64-x86_64-cmake + make + p7zip + + - name: Install Dependencies [macOS] + if: ${{ runner.os == 'macOS' }} + run: | + export HOMEBREW_NO_INSTALL_CLEANUP=1 + brew update + brew install \ + pkg-config \ + sdl2 \ + libsndfile \ + zlib \ + jack + + - name: Install Dependencies [Ubuntu] + if: ${{ runner.os == 'Linux' }} + run: | + sudo apt update + sudo apt install \ + libsdl2-dev \ + libsndfile1-dev \ + zlib1g-dev \ + libjack-jackd2-dev \ + appstream + wget "https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage" + chmod +x appimagetool-x86_64.AppImage + + - name: Set package identity + id: package-identity + run: | + package_name="furnace-${GITHUB_SHA}" + package_ext="" + if [ '${{ runner.os }}' == 'Windows' ]; then + package_name="${package_name}-Windows" + if [ '${{ matrix.config.compiler }}' == 'mingw' ]; then + package_name="${package_name}-MinGW" + else + package_name="${package_name}-MSVC" + fi + package_ext=".zip" + elif [ '${{ runner.os }}' == 'macOS' ]; then + package_name="${package_name}-macOS" + package_ext=".dmg" + else + package_name="${package_name}-Linux" + package_ext=".AppImage" + fi + + echo "Package identity: ${package_name}" + echo "Package file: ${package_name}${package_ext}" + + echo "::set-output name=id::${package_name}" + echo "::set-output name=filename::${package_name}${package_ext}" + + - name: Configure + run: | + export USE_WAE=ON + export CMAKE_EXTRA_ARGS=() + if [ '${{ runner.os }}' == 'Windows' ]; then + if [ '${{ matrix.config.compiler }}' == 'mingw' ]; then + CMAKE_EXTRA_ARGS+=('-G' 'MSYS Makefiles') + elif [ '${{ matrix.config.compiler }}' == 'msvc' ]; then + # FIXME We don't want all the MSVC warnings to cause errors yet + export USE_WAE=OFF + + # Force static linking + # 1. Make MSVC runtime configurable + CMAKE_EXTRA_ARGS+=('-DCMAKE_POLICY_DEFAULT_CMP0091=NEW') + # 2. Use static (debug) runtime + if [ '${{ env.BUILD_TYPE }}' == 'Debug' ]; then + CMAKE_EXTRA_ARGS+=('-DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreadedDebug') + else + CMAKE_EXTRA_ARGS+=('-DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded') + fi + + # Fix SDL static linking (see linked issues in patch file) + pushd extern/SDL + env EMAIL=root@localhost git am ../SDL-Fix-MSVC-static-runtime-linking.patch + popd + fi + elif [ '${{ runner.os }}' == 'macOS' ]; then + CMAKE_EXTRA_ARGS+=('-DCMAKE_OSX_DEPLOYMENT_TARGET="10.9"') + fi + + cmake \ + -B ${PWD}/build \ + -DCMAKE_INSTALL_PREFIX=/usr \ + -DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} \ + -DWARNINGS_ARE_ERRORS=${USE_WAE} \ + "${CMAKE_EXTRA_ARGS[@]}" + + - name: Build + run: | + export VERBOSE=1 + cmake \ + --build ${PWD}/build \ + --config ${{ env.BUILD_TYPE }} \ + --parallel 2 + + - name: Package [Windows] + if: ${{ runner.os == 'Windows' }} + run: | + binPath=build + if [ '${{ matrix.config.compiler }}' == 'msvc' ]; then + binPath="${binPath}/${{ env.BUILD_TYPE }}" + fi + if [ '${{ matrix.config.compiler }}' == 'mingw' ]; then + strip -s "${binPath}/furnace.exe" + fi + + mkdir target + pushd target + + cp -v ../LICENSE LICENSE.txt + cp -v ../README.md README.txt + cp -vr ../{papers,demos} ../${binPath}/furnace.exe ./ + + 7z a -tzip ../${{ steps.package-identity.outputs.filename }} * + popd + + - name: Package [macOS] + if: ${{ runner.os == 'macOS' }} + run: | + pushd build + cpack + mv Furnace-*-Darwin.dmg ../${{ steps.package-identity.outputs.filename }} + popd + + - name: Package [Ubuntu] + if: ${{ runner.os == 'Linux' }} + run: | + strip -s build/furnace + + mkdir -p target/furnace.AppDir + make -C ${PWD}/build DESTDIR=${PWD}/target/furnace.AppDir install + pushd target + + pushd furnace.AppDir + cp -v usr/share/{icons/hicolor/1024x1024/apps/furnace.png,applications/furnace.desktop} ./ + ln -s furnace.png .DirIcon + mv -v usr/share/metainfo/{furnace.appdata,org.tildearrow.furnace.metainfo}.xml + cp -v ../../res/AppRun ./ + popd + + ../appimagetool-x86_64.AppImage furnace.AppDir + mv Furnace-*.AppImage ../${{ steps.package-identity.outputs.filename }} + popd + + - name: Upload artifact + uses: actions/upload-artifact@v3 + with: + name: ${{ steps.package-identity.outputs.id }} + path: ${{ steps.package-identity.outputs.filename }} diff --git a/extern/SDL-Fix-MSVC-static-runtime-linking.patch b/extern/SDL-Fix-MSVC-static-runtime-linking.patch new file mode 100644 index 00000000..31b9ea61 --- /dev/null +++ b/extern/SDL-Fix-MSVC-static-runtime-linking.patch @@ -0,0 +1,35 @@ +From 34d3dcd98697af081625ccea7a41a3c47806c4ff Mon Sep 17 00:00:00 2001 +From: OPNA2608 +Date: Mon, 28 Mar 2022 16:43:16 +0200 +Subject: [PATCH] SDL: Fix MSVC static runtime linking + +See https://github.com/libsdl-org/SDL/issues/3662, https://github.com/libsdl-org/SDL/issues/4258. +--- + src/stdlib/SDL_stdlib.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/stdlib/SDL_stdlib.c b/src/stdlib/SDL_stdlib.c +index 9d785aad5..dfac4d7c3 100644 +--- a/src/stdlib/SDL_stdlib.c ++++ b/src/stdlib/SDL_stdlib.c +@@ -550,7 +550,7 @@ __declspec(selectany) int _fltused = 1; + #endif + + /* The optimizer on Visual Studio 2005 and later generates memcpy() and memset() calls */ +-#if _MSC_VER >= 1400 ++#if (_MSC_VER >= 1400) && !defined(_MT) + extern void *memcpy(void* dst, const void* src, size_t len); + #pragma intrinsic(memcpy) + +@@ -570,7 +570,7 @@ memset(void *dst, int c, size_t len) + { + return SDL_memset(dst, c, len); + } +-#endif /* _MSC_VER >= 1400 */ ++#endif /* (_MSC_VER >= 1400) && !defined(_MT) */ + + #ifdef _M_IX86 + +-- +2.33.1 + From 8a6dfa8d199cdb66af6d88d257d5b75f0b0b3d63 Mon Sep 17 00:00:00 2001 From: OPNA2608 Date: Thu, 31 Mar 2022 15:57:52 +0200 Subject: [PATCH 04/76] pfd: Fixes for MinGW 10 --- extern/pfd-fixed/portable-file-dialogs.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extern/pfd-fixed/portable-file-dialogs.h b/extern/pfd-fixed/portable-file-dialogs.h index 41e588ac..008fe0a9 100644 --- a/extern/pfd-fixed/portable-file-dialogs.h +++ b/extern/pfd-fixed/portable-file-dialogs.h @@ -57,7 +57,7 @@ #ifndef PFD_HAS_IFILEDIALOG # define PFD_HAS_IFILEDIALOG 1 # if (defined __MINGW64__ || defined __MINGW32__) && defined __GXX_ABI_VERSION -# if __GXX_ABI_VERSION <= 1013 +# if __GXX_ABI_VERSION <= 1014 # undef PFD_HAS_IFILEDIALOG # define PFD_HAS_IFILEDIALOG 0 # endif @@ -1383,7 +1383,7 @@ inline notify::notify(std::string const &title, /* case icon::info: */ default: nid->dwInfoFlags = NIIF_INFO; break; } - ENUMRESNAMEPROC icon_enum_callback = [](HMODULE, LPCTSTR, LPTSTR lpName, LONG_PTR lParam) -> BOOL + ENUMRESNAMEPROC icon_enum_callback = [](HMODULE, LPCTSTR, LPTSTR lpName, LONG_PTR lParam) -> BOOL WINAPI { ((NOTIFYICONDATAW *)lParam)->hIcon = ::LoadIcon(GetModuleHandle(nullptr), lpName); return false; From 0351388996d3ea1ac4741f00272b75b51bc4d74c Mon Sep 17 00:00:00 2001 From: OPNA2608 Date: Thu, 31 Mar 2022 16:20:51 +0200 Subject: [PATCH 05/76] Add MinGW cross-compiler toolchains --- scripts/Cross-MinGW-x86.cmake | 4 ++++ scripts/Cross-MinGW-x86_64.cmake | 4 ++++ scripts/Cross-MinGW.cmake | 14 ++++++++++++++ 3 files changed, 22 insertions(+) create mode 100644 scripts/Cross-MinGW-x86.cmake create mode 100644 scripts/Cross-MinGW-x86_64.cmake create mode 100644 scripts/Cross-MinGW.cmake diff --git a/scripts/Cross-MinGW-x86.cmake b/scripts/Cross-MinGW-x86.cmake new file mode 100644 index 00000000..4049ffdd --- /dev/null +++ b/scripts/Cross-MinGW-x86.cmake @@ -0,0 +1,4 @@ +set(CMAKE_SYSTEM_NAME Windows) +set(CMAKE_SYSTEM_PROCESSOR i686) + +include(${CMAKE_CURRENT_LIST_DIR}/Cross-MinGW.cmake) diff --git a/scripts/Cross-MinGW-x86_64.cmake b/scripts/Cross-MinGW-x86_64.cmake new file mode 100644 index 00000000..5b088cb3 --- /dev/null +++ b/scripts/Cross-MinGW-x86_64.cmake @@ -0,0 +1,4 @@ +set(CMAKE_SYSTEM_NAME Windows) +set(CMAKE_SYSTEM_PROCESSOR x86_64) + +include(${CMAKE_CURRENT_LIST_DIR}/Cross-MinGW.cmake) diff --git a/scripts/Cross-MinGW.cmake b/scripts/Cross-MinGW.cmake new file mode 100644 index 00000000..09871d6b --- /dev/null +++ b/scripts/Cross-MinGW.cmake @@ -0,0 +1,14 @@ +set(TARGET_PREFIX ${CMAKE_SYSTEM_PROCESSOR}-w64-mingw32) + +set(CMAKE_C_COMPILER ${TARGET_PREFIX}-gcc-posix) +set(CMAKE_CXX_COMPILER ${TARGET_PREFIX}-g++-posix) +set(PKG_CONFIG_EXECUTABLE ${TARGET_PREFIX}-pkg-config) + +set(CMAKE_FIND_ROOT_PATH /usr/${TARGET_PREFIX}) + +# Search host system for programs +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +# Search target system for libraries, headers & CMake packages +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) From 6c9f1c6d540e982c0e6f6ee72e3613f8a6933943 Mon Sep 17 00:00:00 2001 From: OPNA2608 Date: Fri, 1 Apr 2022 02:55:20 +0200 Subject: [PATCH 06/76] Cross-compile MinGW builds on CI --- .github/workflows/build.yml | 125 ++++++++++++++++-------------------- 1 file changed, 55 insertions(+), 70 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e53d720c..7d3dd84f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -19,17 +19,14 @@ jobs: strategy: matrix: config: - - { name: 'Windows MSVC', os: windows-latest, compiler: msvc, shell: bash } - - { name: 'Windows MinGW', os: windows-latest, compiler: mingw, shell: 'msys2 {0}' } - - { name: 'macOS', os: macos-latest, shell: bash } - - { name: 'Ubuntu', os: ubuntu-18.04, shell: bash } + - { name: 'Windows MSVC', os: windows-latest, compiler: msvc } + - { name: 'Windows MinGW', os: ubuntu-20.04, compiler: mingw } + - { name: 'macOS', os: macos-latest } + - { name: 'Ubuntu', os: ubuntu-18.04 } fail-fast: false name: "Build: ${{ matrix.config.name }}" runs-on: ${{ matrix.config.os }} - defaults: - run: - shell: ${{ matrix.config.shell }} steps: - name: Checkout @@ -38,19 +35,16 @@ jobs: submodules: recursive - name: Setup Toolchain [Windows MSVC] - if: ${{ runner.os == 'Windows' && matrix.config.compiler == 'msvc' }} + if: ${{ matrix.config.compiler == 'msvc' }} uses: seanmiddleditch/gha-setup-vsdevenv@v3 - name: Setup Toolchain [Windows MinGW] - if: ${{ runner.os == 'Windows' && matrix.config.compiler == 'mingw' }} - uses: msys2/setup-msys2@v2 - with: - msystem: MINGW64 - update: true - install: | - mingw-w64-x86_64-toolchain - mingw-w64-x86_64-cmake - make + if: ${{ matrix.config.compiler == 'mingw' }} + run: | + sudo apt update + sudo apt install \ + mingw-w64 \ + mingw-w64-tools - name: Install Dependencies [macOS] if: ${{ runner.os == 'macOS' }} @@ -65,7 +59,7 @@ jobs: jack - name: Install Dependencies [Ubuntu] - if: ${{ runner.os == 'Linux' }} + if: ${{ runner.os == 'Linux' && matrix.config.compiler != 'mingw' }} run: | sudo apt update sudo apt install \ @@ -78,13 +72,11 @@ jobs: run: | export USE_WAE=ON export CMAKE_EXTRA_ARGS=() - if [ '${{ runner.os }}' == 'Windows' ]; then - if [ '${{ matrix.config.compiler }}' == 'mingw' ]; then - CMAKE_EXTRA_ARGS+=('-G' 'MSYS Makefiles') - elif [ '${{ matrix.config.compiler }}' == 'msvc' ]; then - # FIXME We don't want all the MSVC warnings to cause errors yet - export USE_WAE=OFF - fi + if [ '${{ matrix.config.compiler }}' == 'msvc' ]; then + # FIXME We don't want all the MSVC warnings to cause errors yet + export USE_WAE=OFF + elif [ '${{ matrix.config.compiler }}' == 'mingw' ]; then + CMAKE_EXTRA_ARGS+=('-DCMAKE_TOOLCHAIN_FILE=scripts/Cross-MinGW-x86.cmake') fi cmake \ @@ -115,17 +107,14 @@ jobs: strategy: matrix: config: - - { name: 'Windows MSVC', os: windows-latest, compiler: msvc, shell: bash } - - { name: 'Windows MinGW', os: windows-latest, compiler: mingw, shell: 'msys2 {0}' } - - { name: 'macOS', os: macos-latest, shell: bash } - - { name: 'Ubuntu', os: ubuntu-18.04, shell: bash } + - { name: 'Windows MSVC', os: windows-latest, compiler: msvc } + - { name: 'Windows MinGW', os: ubuntu-20.04, compiler: mingw } + - { name: 'macOS', os: macos-latest } + - { name: 'Ubuntu', os: ubuntu-18.04 } fail-fast: false name: "Package: ${{ matrix.config.name }}" runs-on: ${{ matrix.config.os }} - defaults: - run: - shell: ${{ matrix.config.shell }} steps: - name: Checkout @@ -134,20 +123,16 @@ jobs: submodules: recursive - name: Setup Toolchain [Windows MSVC] - if: ${{ runner.os == 'Windows' && matrix.config.compiler == 'msvc' }} + if: ${{ matrix.config.compiler == 'msvc' }} uses: seanmiddleditch/gha-setup-vsdevenv@v3 - name: Setup Toolchain [Windows MinGW] - if: ${{ runner.os == 'Windows' && matrix.config.compiler == 'mingw' }} - uses: msys2/setup-msys2@v2 - with: - msystem: MINGW64 - update: true - install: | - mingw-w64-x86_64-toolchain - mingw-w64-x86_64-cmake - make - p7zip + if: ${{ matrix.config.compiler == 'mingw' }} + run: | + sudo apt update + sudo apt install \ + mingw-w64 \ + mingw-w64-tools - name: Install Dependencies [macOS] if: ${{ runner.os == 'macOS' }} @@ -162,7 +147,7 @@ jobs: jack - name: Install Dependencies [Ubuntu] - if: ${{ runner.os == 'Linux' }} + if: ${{ runner.os == 'Linux' && matrix.config.compiler != 'mingw' }} run: | sudo apt update sudo apt install \ @@ -179,7 +164,7 @@ jobs: run: | package_name="furnace-${GITHUB_SHA}" package_ext="" - if [ '${{ runner.os }}' == 'Windows' ]; then + if [ '${{ runner.os }}' == 'Windows' ] || [ '${{ matrix.config.compiler }}' == 'mingw' ]; then package_name="${package_name}-Windows" if [ '${{ matrix.config.compiler }}' == 'mingw' ]; then package_name="${package_name}-MinGW" @@ -205,28 +190,26 @@ jobs: run: | export USE_WAE=ON export CMAKE_EXTRA_ARGS=() - if [ '${{ runner.os }}' == 'Windows' ]; then - if [ '${{ matrix.config.compiler }}' == 'mingw' ]; then - CMAKE_EXTRA_ARGS+=('-G' 'MSYS Makefiles') - elif [ '${{ matrix.config.compiler }}' == 'msvc' ]; then - # FIXME We don't want all the MSVC warnings to cause errors yet - export USE_WAE=OFF + if [ '${{ matrix.config.compiler }}' == 'msvc' ]; then + # FIXME We don't want all the MSVC warnings to cause errors yet + export USE_WAE=OFF - # Force static linking - # 1. Make MSVC runtime configurable - CMAKE_EXTRA_ARGS+=('-DCMAKE_POLICY_DEFAULT_CMP0091=NEW') - # 2. Use static (debug) runtime - if [ '${{ env.BUILD_TYPE }}' == 'Debug' ]; then - CMAKE_EXTRA_ARGS+=('-DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreadedDebug') - else - CMAKE_EXTRA_ARGS+=('-DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded') - fi - - # Fix SDL static linking (see linked issues in patch file) - pushd extern/SDL - env EMAIL=root@localhost git am ../SDL-Fix-MSVC-static-runtime-linking.patch - popd + # Force static linking + # 1. Make MSVC runtime configurable + CMAKE_EXTRA_ARGS+=('-DCMAKE_POLICY_DEFAULT_CMP0091=NEW') + # 2. Use static (debug) runtime + if [ '${{ env.BUILD_TYPE }}' == 'Debug' ]; then + CMAKE_EXTRA_ARGS+=('-DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreadedDebug') + else + CMAKE_EXTRA_ARGS+=('-DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded') fi + + # Fix SDL static linking (see linked issues in patch file) + pushd extern/SDL + env EMAIL=root@localhost git am ../SDL-Fix-MSVC-static-runtime-linking.patch + popd + elif [ '${{ matrix.config.compiler }}' == 'mingw' ]; then + CMAKE_EXTRA_ARGS+=('-DCMAKE_TOOLCHAIN_FILE=scripts/Cross-MinGW-x86.cmake') elif [ '${{ runner.os }}' == 'macOS' ]; then CMAKE_EXTRA_ARGS+=('-DCMAKE_OSX_DEPLOYMENT_TARGET="10.9"') fi @@ -247,14 +230,14 @@ jobs: --parallel 2 - name: Package [Windows] - if: ${{ runner.os == 'Windows' }} + if: ${{ runner.os == 'Windows' || matrix.config.compiler == 'mingw' }} run: | binPath=build if [ '${{ matrix.config.compiler }}' == 'msvc' ]; then binPath="${binPath}/${{ env.BUILD_TYPE }}" fi - if [ '${{ matrix.config.compiler }}' == 'mingw' ]; then - strip -s "${binPath}/furnace.exe" + if [ '${{ matrix.config.compiler }}' == 'mingw' ] && [ '${{ env.BUILD_TYPE }}' == 'Release' ]; then + i686-w64-mingw32-strip -s "${binPath}/furnace.exe" fi mkdir target @@ -276,9 +259,11 @@ jobs: popd - name: Package [Ubuntu] - if: ${{ runner.os == 'Linux' }} + if: ${{ runner.os == 'Linux' && matrix.config.compiler != 'mingw' }} run: | - strip -s build/furnace + if [ '${{ env.BUILD_TYPE }}' == 'Release' ]; then + strip -s build/furnace + fi mkdir -p target/furnace.AppDir make -C ${PWD}/build DESTDIR=${PWD}/target/furnace.AppDir install From 8483f853973349614282355d99f7dbd314a76b43 Mon Sep 17 00:00:00 2001 From: OPNA2608 Date: Sat, 2 Apr 2022 16:48:05 +0200 Subject: [PATCH 07/76] Modularise Windows arch on CI --- .github/workflows/build.yml | 81 ++++++++++++++++++++++++++++++++----- 1 file changed, 71 insertions(+), 10 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7d3dd84f..db59071a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -12,6 +12,7 @@ defaults: env: BUILD_TYPE: Release + WINDOWS_ARCH: x86 jobs: # Do a plain build, like we would expect a user to do it on their end. @@ -34,9 +35,37 @@ jobs: with: submodules: recursive + - name: Set Windows arch identifiers + id: windows-identify + if: ${{ matrix.config.compiler == 'msvc' || matrix.config.compiler == 'mingw' }} + run: | + vswhere_target="${{ env.WINDOWS_ARCH }}" + msvc_target="${{ env.WINDOWS_ARCH }}" + mingw_target="${{ env.WINDOWS_ARCH }}" + + if [ '${{ env.WINDOWS_ARCH }}' == 'x86' ]; then + msvc_target="Win32" + elif [ '${{ env.WINDOWS_ARCH }}' == 'x86_64' ]; then + vswhere_target="amd64" + msvc_target="x64" + fi + + if [ '${{ matrix.config.compiler }}' == 'msvc' ]; then + echo "vswhere target: ${vswhere_target}" + echo "MSVC target: ${msvc_target}" + else + echo "MinGW cross target: ${mingw_target}" + fi + + echo "::set-output name=vswhere-target::${vswhere_target}" + echo "::set-output name=msvc-target::${msvc_target}" + echo "::set-output name=mingw-target::${mingw_target}" + - name: Setup Toolchain [Windows MSVC] if: ${{ matrix.config.compiler == 'msvc' }} uses: seanmiddleditch/gha-setup-vsdevenv@v3 + with: + arch: ${{ steps.windows-identify.outputs.vswhere-target }} - name: Setup Toolchain [Windows MinGW] if: ${{ matrix.config.compiler == 'mingw' }} @@ -73,10 +102,12 @@ jobs: export USE_WAE=ON export CMAKE_EXTRA_ARGS=() if [ '${{ matrix.config.compiler }}' == 'msvc' ]; then + CMAKE_EXTRA_ARGS+=('-DCMAKE_GENERATOR_PLATFORM=${{ steps.windows-identify.outputs.msvc-target }}') + # FIXME We don't want all the MSVC warnings to cause errors yet export USE_WAE=OFF elif [ '${{ matrix.config.compiler }}' == 'mingw' ]; then - CMAKE_EXTRA_ARGS+=('-DCMAKE_TOOLCHAIN_FILE=scripts/Cross-MinGW-x86.cmake') + CMAKE_EXTRA_ARGS+=('-DCMAKE_TOOLCHAIN_FILE=scripts/Cross-MinGW-${{ steps.windows-identify.outputs.mingw-target }}.cmake') fi cmake \ @@ -122,9 +153,37 @@ jobs: with: submodules: recursive + - name: Set Windows arch identifiers + id: windows-identify + if: ${{ matrix.config.compiler == 'msvc' || matrix.config.compiler == 'mingw' }} + run: | + vswhere_target="${{ env.WINDOWS_ARCH }}" + msvc_target="${{ env.WINDOWS_ARCH }}" + mingw_target="${{ env.WINDOWS_ARCH }}" + + if [ '${{ env.WINDOWS_ARCH }}' == 'x86' ]; then + msvc_target="Win32" + elif [ '${{ env.WINDOWS_ARCH }}' == 'x86_64' ]; then + vswhere_target="amd64" + msvc_target="x64" + fi + + if [ '${{ matrix.config.compiler }}' == 'msvc' ]; then + echo "vswhere target: ${vswhere_target}" + echo "MSVC target: ${msvc_target}" + else + echo "MinGW cross target: ${mingw_target}" + fi + + echo "::set-output name=vswhere-target::${vswhere_target}" + echo "::set-output name=msvc-target::${msvc_target}" + echo "::set-output name=mingw-target::${mingw_target}" + - name: Setup Toolchain [Windows MSVC] if: ${{ matrix.config.compiler == 'msvc' }} uses: seanmiddleditch/gha-setup-vsdevenv@v3 + with: + arch: ${{ steps.windows-identify.outputs.vswhere-target }} - name: Setup Toolchain [Windows MinGW] if: ${{ matrix.config.compiler == 'mingw' }} @@ -159,8 +218,8 @@ jobs: wget "https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage" chmod +x appimagetool-x86_64.AppImage - - name: Set package identity - id: package-identity + - name: Set package identifier + id: package-identify run: | package_name="furnace-${GITHUB_SHA}" package_ext="" @@ -180,7 +239,7 @@ jobs: package_ext=".AppImage" fi - echo "Package identity: ${package_name}" + echo "Package identifier: ${package_name}" echo "Package file: ${package_name}${package_ext}" echo "::set-output name=id::${package_name}" @@ -191,6 +250,8 @@ jobs: export USE_WAE=ON export CMAKE_EXTRA_ARGS=() if [ '${{ matrix.config.compiler }}' == 'msvc' ]; then + CMAKE_EXTRA_ARGS+=('-DCMAKE_GENERATOR_PLATFORM=${{ steps.windows-identify.outputs.msvc-target }}') + # FIXME We don't want all the MSVC warnings to cause errors yet export USE_WAE=OFF @@ -209,7 +270,7 @@ jobs: env EMAIL=root@localhost git am ../SDL-Fix-MSVC-static-runtime-linking.patch popd elif [ '${{ matrix.config.compiler }}' == 'mingw' ]; then - CMAKE_EXTRA_ARGS+=('-DCMAKE_TOOLCHAIN_FILE=scripts/Cross-MinGW-x86.cmake') + CMAKE_EXTRA_ARGS+=('-DCMAKE_TOOLCHAIN_FILE=scripts/Cross-MinGW-${{ steps.windows-identify.outputs.mingw-target }}.cmake') elif [ '${{ runner.os }}' == 'macOS' ]; then CMAKE_EXTRA_ARGS+=('-DCMAKE_OSX_DEPLOYMENT_TARGET="10.9"') fi @@ -247,7 +308,7 @@ jobs: cp -v ../README.md README.txt cp -vr ../{papers,demos} ../${binPath}/furnace.exe ./ - 7z a -tzip ../${{ steps.package-identity.outputs.filename }} * + 7z a -tzip ../${{ steps.package-identify.outputs.filename }} * popd - name: Package [macOS] @@ -255,7 +316,7 @@ jobs: run: | pushd build cpack - mv Furnace-*-Darwin.dmg ../${{ steps.package-identity.outputs.filename }} + mv Furnace-*-Darwin.dmg ../${{ steps.package-identify.outputs.filename }} popd - name: Package [Ubuntu] @@ -277,11 +338,11 @@ jobs: popd ../appimagetool-x86_64.AppImage furnace.AppDir - mv Furnace-*.AppImage ../${{ steps.package-identity.outputs.filename }} + mv Furnace-*.AppImage ../${{ steps.package-identify.outputs.filename }} popd - name: Upload artifact uses: actions/upload-artifact@v3 with: - name: ${{ steps.package-identity.outputs.id }} - path: ${{ steps.package-identity.outputs.filename }} + name: ${{ steps.package-identify.outputs.id }} + path: ${{ steps.package-identify.outputs.filename }} From 54a36c495055720eb5320b42eb77872b6c5706cb Mon Sep 17 00:00:00 2001 From: OPNA2608 Date: Sat, 2 Apr 2022 17:36:04 +0200 Subject: [PATCH 08/76] Fix SDL static linking --- .github/workflows/build.yml | 5 --- CMakeLists.txt | 9 +++-- .../SDL-Fix-MSVC-static-runtime-linking.patch | 35 ------------------- 3 files changed, 7 insertions(+), 42 deletions(-) delete mode 100644 extern/SDL-Fix-MSVC-static-runtime-linking.patch diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index db59071a..3fd8509f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -264,11 +264,6 @@ jobs: else CMAKE_EXTRA_ARGS+=('-DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded') fi - - # Fix SDL static linking (see linked issues in patch file) - pushd extern/SDL - env EMAIL=root@localhost git am ../SDL-Fix-MSVC-static-runtime-linking.patch - popd elif [ '${{ matrix.config.compiler }}' == 'mingw' ]; then CMAKE_EXTRA_ARGS+=('-DCMAKE_TOOLCHAIN_FILE=scripts/Cross-MinGW-${{ steps.windows-identify.outputs.mingw-target }}.cmake') elif [ '${{ runner.os }}' == 'macOS' ]; then diff --git a/CMakeLists.txt b/CMakeLists.txt index c5fc06e7..769842f3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -167,8 +167,13 @@ if (SYSTEM_SDL2) endif() message(STATUS "Using system-installed SDL2") else() - set(SDL_SHARED OFF) - set(SDL_STATIC ON) + set(SDL_SHARED OFF CACHE BOOL "Force no dynamically-linked SDL" FORCE) + set(SDL_STATIC ON CACHE BOOL "Force statically-linked SDL" FORCE) + # https://github.com/libsdl-org/SDL/issues/1481 + # On 2014-06-22 17:15:50 +0000, Sam Lantinga wrote: + # If you link SDL statically, you also need to define HAVE_LIBC so it builds with the C runtime that your application uses. + # This should probably go in a FAQ. + set(SDL_LIBC ON CACHE BOOL "Tell SDL that we want it to use our C runtime (required for proper static linking)" FORCE) add_subdirectory(extern/SDL EXCLUDE_FROM_ALL) list(APPEND DEPENDENCIES_INCLUDE_DIRS extern/SDL/include) list(APPEND DEPENDENCIES_LIBRARIES SDL2-static) diff --git a/extern/SDL-Fix-MSVC-static-runtime-linking.patch b/extern/SDL-Fix-MSVC-static-runtime-linking.patch deleted file mode 100644 index 31b9ea61..00000000 --- a/extern/SDL-Fix-MSVC-static-runtime-linking.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 34d3dcd98697af081625ccea7a41a3c47806c4ff Mon Sep 17 00:00:00 2001 -From: OPNA2608 -Date: Mon, 28 Mar 2022 16:43:16 +0200 -Subject: [PATCH] SDL: Fix MSVC static runtime linking - -See https://github.com/libsdl-org/SDL/issues/3662, https://github.com/libsdl-org/SDL/issues/4258. ---- - src/stdlib/SDL_stdlib.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/src/stdlib/SDL_stdlib.c b/src/stdlib/SDL_stdlib.c -index 9d785aad5..dfac4d7c3 100644 ---- a/src/stdlib/SDL_stdlib.c -+++ b/src/stdlib/SDL_stdlib.c -@@ -550,7 +550,7 @@ __declspec(selectany) int _fltused = 1; - #endif - - /* The optimizer on Visual Studio 2005 and later generates memcpy() and memset() calls */ --#if _MSC_VER >= 1400 -+#if (_MSC_VER >= 1400) && !defined(_MT) - extern void *memcpy(void* dst, const void* src, size_t len); - #pragma intrinsic(memcpy) - -@@ -570,7 +570,7 @@ memset(void *dst, int c, size_t len) - { - return SDL_memset(dst, c, len); - } --#endif /* _MSC_VER >= 1400 */ -+#endif /* (_MSC_VER >= 1400) && !defined(_MT) */ - - #ifdef _M_IX86 - --- -2.33.1 - From fa1e3ea3e1029918e08fdb2bd8c1ce4f2c8c7765 Mon Sep 17 00:00:00 2001 From: OPNA2608 Date: Sat, 2 Apr 2022 18:29:37 +0200 Subject: [PATCH 09/76] Fix zip-in-zip artifact upload for Windows --- .github/workflows/build.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3fd8509f..bbf80788 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -230,7 +230,7 @@ jobs: else package_name="${package_name}-MSVC" fi - package_ext=".zip" + package_ext="" # Directory, uploading will automatically zip it elif [ '${{ runner.os }}' == 'macOS' ]; then package_name="${package_name}-macOS" package_ext=".dmg" @@ -293,17 +293,17 @@ jobs: binPath="${binPath}/${{ env.BUILD_TYPE }}" fi if [ '${{ matrix.config.compiler }}' == 'mingw' ] && [ '${{ env.BUILD_TYPE }}' == 'Release' ]; then + # FIXME arch-specific strip prefix i686-w64-mingw32-strip -s "${binPath}/furnace.exe" fi - mkdir target - pushd target + mkdir ${{ steps.package-identify.outputs.filename }} + pushd ${{ steps.package-identify.outputs.filename }} cp -v ../LICENSE LICENSE.txt cp -v ../README.md README.txt cp -vr ../{papers,demos} ../${binPath}/furnace.exe ./ - 7z a -tzip ../${{ steps.package-identify.outputs.filename }} * popd - name: Package [macOS] From 28682b79d139d9514556430ee367ca77ca4a5d36 Mon Sep 17 00:00:00 2001 From: OPNA2608 Date: Sun, 3 Apr 2022 20:57:17 +0200 Subject: [PATCH 10/76] Build with system libs in first run --- .github/workflows/build.yml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index bbf80788..6e20265d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -83,6 +83,8 @@ jobs: brew install \ pkg-config \ sdl2 \ + fmt \ + rtmidi \ libsndfile \ zlib \ jack @@ -93,6 +95,8 @@ jobs: sudo apt update sudo apt install \ libsdl2-dev \ + libfmt-dev \ + librtmidi-dev \ libsndfile1-dev \ zlib1g-dev \ libjack-jackd2-dev @@ -108,6 +112,19 @@ jobs: export USE_WAE=OFF elif [ '${{ matrix.config.compiler }}' == 'mingw' ]; then CMAKE_EXTRA_ARGS+=('-DCMAKE_TOOLCHAIN_FILE=scripts/Cross-MinGW-${{ steps.windows-identify.outputs.mingw-target }}.cmake') + else + # Test with system libs + CMAKE_EXTRA_ARGS+=( + '-DSYSTEM_FMT=ON' + '-DSYSTEM_LIBSNDFILE=ON' + '-DSYSTEM_RTMIDI=ON' + '-DSYSTEM_ZLIB=ON' + '-DWITH_JACK=ON' + ) + # Too old on Ubuntu + if [ '${{ runner.os }}' == 'macOS' ]; then + CMAKE_EXTRA_ARGS+=('-DSYSTEM_SDL2=ON') + fi fi cmake \ @@ -201,6 +218,8 @@ jobs: brew install \ pkg-config \ sdl2 \ + fmt \ + rtmidi \ libsndfile \ zlib \ jack @@ -211,6 +230,8 @@ jobs: sudo apt update sudo apt install \ libsdl2-dev \ + libfmt-dev \ + librtmidi-dev \ libsndfile1-dev \ zlib1g-dev \ libjack-jackd2-dev \ From 759b5ab7d111a2deabfc1650981ad053f1b28a26 Mon Sep 17 00:00:00 2001 From: OPNA2608 Date: Thu, 7 Apr 2022 19:25:27 +0200 Subject: [PATCH 11/76] Don't install brew dependencies in package CI run --- .github/workflows/build.yml | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6e20265d..3ab546e7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -210,20 +210,6 @@ jobs: mingw-w64 \ mingw-w64-tools - - name: Install Dependencies [macOS] - if: ${{ runner.os == 'macOS' }} - run: | - export HOMEBREW_NO_INSTALL_CLEANUP=1 - brew update - brew install \ - pkg-config \ - sdl2 \ - fmt \ - rtmidi \ - libsndfile \ - zlib \ - jack - - name: Install Dependencies [Ubuntu] if: ${{ runner.os == 'Linux' && matrix.config.compiler != 'mingw' }} run: | From 3fbcc6be578059c394f8ff2eeb89cedb36c076b3 Mon Sep 17 00:00:00 2001 From: OPNA2608 Date: Fri, 8 Apr 2022 20:37:08 +0200 Subject: [PATCH 12/76] Build x86 & x86_64 on Windows CI --- .github/workflows/build.yml | 45 +++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3ab546e7..a16439aa 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -12,7 +12,6 @@ defaults: env: BUILD_TYPE: Release - WINDOWS_ARCH: x86 jobs: # Do a plain build, like we would expect a user to do it on their end. @@ -20,8 +19,10 @@ jobs: strategy: matrix: config: - - { name: 'Windows MSVC', os: windows-latest, compiler: msvc } - - { name: 'Windows MinGW', os: ubuntu-20.04, compiler: mingw } + - { name: 'Windows MSVC x86', os: windows-latest, compiler: msvc, arch: x86 } + - { name: 'Windows MSVC x86_64', os: windows-latest, compiler: msvc, arch: x86_64 } + - { name: 'Windows MinGW x86', os: ubuntu-20.04, compiler: mingw, arch: x86 } + - { name: 'Windows MinGW x86_64', os: ubuntu-20.04, compiler: mingw, arch: x86_64 } - { name: 'macOS', os: macos-latest } - { name: 'Ubuntu', os: ubuntu-18.04 } fail-fast: false @@ -39,13 +40,13 @@ jobs: id: windows-identify if: ${{ matrix.config.compiler == 'msvc' || matrix.config.compiler == 'mingw' }} run: | - vswhere_target="${{ env.WINDOWS_ARCH }}" - msvc_target="${{ env.WINDOWS_ARCH }}" - mingw_target="${{ env.WINDOWS_ARCH }}" + vswhere_target="${{ matrix.config.arch }}" + msvc_target="${{ matrix.config.arch }}" + mingw_target="${{ matrix.config.arch }}" - if [ '${{ env.WINDOWS_ARCH }}' == 'x86' ]; then + if [ '${{ matrix.config.arch }}' == 'x86' ]; then msvc_target="Win32" - elif [ '${{ env.WINDOWS_ARCH }}' == 'x86_64' ]; then + elif [ '${{ matrix.config.arch }}' == 'x86_64' ]; then vswhere_target="amd64" msvc_target="x64" fi @@ -155,8 +156,10 @@ jobs: strategy: matrix: config: - - { name: 'Windows MSVC', os: windows-latest, compiler: msvc } - - { name: 'Windows MinGW', os: ubuntu-20.04, compiler: mingw } + - { name: 'Windows MSVC x86', os: windows-latest, compiler: msvc, arch: x86 } + - { name: 'Windows MSVC x86_64', os: windows-latest, compiler: msvc, arch: x86_64 } + - { name: 'Windows MinGW x86', os: ubuntu-20.04, compiler: mingw, arch: x86 } + - { name: 'Windows MinGW x86_64', os: ubuntu-20.04, compiler: mingw, arch: x86_64 } - { name: 'macOS', os: macos-latest } - { name: 'Ubuntu', os: ubuntu-18.04 } fail-fast: false @@ -174,13 +177,13 @@ jobs: id: windows-identify if: ${{ matrix.config.compiler == 'msvc' || matrix.config.compiler == 'mingw' }} run: | - vswhere_target="${{ env.WINDOWS_ARCH }}" - msvc_target="${{ env.WINDOWS_ARCH }}" - mingw_target="${{ env.WINDOWS_ARCH }}" + vswhere_target="${{ matrix.config.arch }}" + msvc_target="${{ matrix.config.arch }}" + mingw_target="${{ matrix.config.arch }}" - if [ '${{ env.WINDOWS_ARCH }}' == 'x86' ]; then + if [ '${{ matrix.config.arch }}' == 'x86' ]; then msvc_target="Win32" - elif [ '${{ env.WINDOWS_ARCH }}' == 'x86_64' ]; then + elif [ '${{ matrix.config.arch }}' == 'x86_64' ]; then vswhere_target="amd64" msvc_target="x64" fi @@ -237,6 +240,7 @@ jobs: else package_name="${package_name}-MSVC" fi + package_name="${package_name}-${{ matrix.config.arch }}" package_ext="" # Directory, uploading will automatically zip it elif [ '${{ runner.os }}' == 'macOS' ]; then package_name="${package_name}-macOS" @@ -300,8 +304,15 @@ jobs: binPath="${binPath}/${{ env.BUILD_TYPE }}" fi if [ '${{ matrix.config.compiler }}' == 'mingw' ] && [ '${{ env.BUILD_TYPE }}' == 'Release' ]; then - # FIXME arch-specific strip prefix - i686-w64-mingw32-strip -s "${binPath}/furnace.exe" + # arch-specific strip prefix + # TODO maybe extract from cross toolchain files? + toolPrefix="-w64-mingw32-" + if [ '${{ matrix.config.arch }}' == 'x86_64' ]; then + toolPrefix="x86_64${toolPrefix}" + else + toolPrefix="i686${toolPrefix}" + fi + ${toolPrefix}strip -s "${binPath}/furnace.exe" fi mkdir ${{ steps.package-identify.outputs.filename }} From 5474f6899fa9291bd2f6221b5dd9b139cfae6af1 Mon Sep 17 00:00:00 2001 From: OPNA2608 Date: Fri, 8 Apr 2022 21:13:15 +0200 Subject: [PATCH 13/76] Merge CI phases --- .github/workflows/build.yml | 153 ++++++++++-------------------------- 1 file changed, 40 insertions(+), 113 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a16439aa..94de2b50 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -14,7 +14,6 @@ env: BUILD_TYPE: Release jobs: - # Do a plain build, like we would expect a user to do it on their end. build: strategy: matrix: @@ -27,7 +26,7 @@ jobs: - { name: 'Ubuntu', os: ubuntu-18.04 } fail-fast: false - name: "Build: ${{ matrix.config.name }}" + name: "Test: ${{ matrix.config.name }}" runs-on: ${{ matrix.config.os }} steps: @@ -62,6 +61,34 @@ jobs: echo "::set-output name=msvc-target::${msvc_target}" echo "::set-output name=mingw-target::${mingw_target}" + - name: Set package identifier + id: package-identify + run: | + package_name="furnace-${GITHUB_SHA}" + package_ext="" + if [ '${{ runner.os }}' == 'Windows' ] || [ '${{ matrix.config.compiler }}' == 'mingw' ]; then + package_name="${package_name}-Windows" + if [ '${{ matrix.config.compiler }}' == 'mingw' ]; then + package_name="${package_name}-MinGW" + else + package_name="${package_name}-MSVC" + fi + package_name="${package_name}-${{ matrix.config.arch }}" + package_ext="" # Directory, uploading will automatically zip it + elif [ '${{ runner.os }}' == 'macOS' ]; then + package_name="${package_name}-macOS" + package_ext=".dmg" + else + package_name="${package_name}-Linux" + package_ext=".AppImage" + fi + + echo "Package identifier: ${package_name}" + echo "Package file: ${package_name}${package_ext}" + + echo "::set-output name=id::${package_name}" + echo "::set-output name=filename::${package_name}${package_ext}" + - name: Setup Toolchain [Windows MSVC] if: ${{ matrix.config.compiler == 'msvc' }} uses: seanmiddleditch/gha-setup-vsdevenv@v3 @@ -100,9 +127,12 @@ jobs: librtmidi-dev \ libsndfile1-dev \ zlib1g-dev \ - libjack-jackd2-dev + libjack-jackd2-dev \ + appstream + wget "https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage" + chmod +x appimagetool-x86_64.AppImage - - name: Configure + - name: Configure (Normal) run: | export USE_WAE=ON export CMAKE_EXTRA_ARGS=() @@ -135,7 +165,7 @@ jobs: -DWARNINGS_ARE_ERRORS=${USE_WAE} \ "${CMAKE_EXTRA_ARGS[@]}" - - name: Build + - name: Build (Normal) run: | export VERBOSE=1 cmake \ @@ -143,120 +173,17 @@ jobs: --config ${{ env.BUILD_TYPE }} \ --parallel 2 - - name: Install + - name: Install (Normal) run: | cmake \ --install ${PWD}/build \ --config ${{ env.BUILD_TYPE }} - # Now do a build that we can package. (static runtime linking on MSVC, zipping on Windows, CPack on Darwin, appimage stuff on Ubuntu) - # We rebuild here because the build dependencies may be slightly different and might trigger a full rebuild anyway. - package: - needs: build - strategy: - matrix: - config: - - { name: 'Windows MSVC x86', os: windows-latest, compiler: msvc, arch: x86 } - - { name: 'Windows MSVC x86_64', os: windows-latest, compiler: msvc, arch: x86_64 } - - { name: 'Windows MinGW x86', os: ubuntu-20.04, compiler: mingw, arch: x86 } - - { name: 'Windows MinGW x86_64', os: ubuntu-20.04, compiler: mingw, arch: x86_64 } - - { name: 'macOS', os: macos-latest } - - { name: 'Ubuntu', os: ubuntu-18.04 } - fail-fast: false - - name: "Package: ${{ matrix.config.name }}" - runs-on: ${{ matrix.config.os }} - - steps: - - name: Checkout - uses: actions/checkout@v2 - with: - submodules: recursive - - - name: Set Windows arch identifiers - id: windows-identify - if: ${{ matrix.config.compiler == 'msvc' || matrix.config.compiler == 'mingw' }} + - name: Cleanup (Normal) run: | - vswhere_target="${{ matrix.config.arch }}" - msvc_target="${{ matrix.config.arch }}" - mingw_target="${{ matrix.config.arch }}" + rm -rf build/ target/ - if [ '${{ matrix.config.arch }}' == 'x86' ]; then - msvc_target="Win32" - elif [ '${{ matrix.config.arch }}' == 'x86_64' ]; then - vswhere_target="amd64" - msvc_target="x64" - fi - - if [ '${{ matrix.config.compiler }}' == 'msvc' ]; then - echo "vswhere target: ${vswhere_target}" - echo "MSVC target: ${msvc_target}" - else - echo "MinGW cross target: ${mingw_target}" - fi - - echo "::set-output name=vswhere-target::${vswhere_target}" - echo "::set-output name=msvc-target::${msvc_target}" - echo "::set-output name=mingw-target::${mingw_target}" - - - name: Setup Toolchain [Windows MSVC] - if: ${{ matrix.config.compiler == 'msvc' }} - uses: seanmiddleditch/gha-setup-vsdevenv@v3 - with: - arch: ${{ steps.windows-identify.outputs.vswhere-target }} - - - name: Setup Toolchain [Windows MinGW] - if: ${{ matrix.config.compiler == 'mingw' }} - run: | - sudo apt update - sudo apt install \ - mingw-w64 \ - mingw-w64-tools - - - name: Install Dependencies [Ubuntu] - if: ${{ runner.os == 'Linux' && matrix.config.compiler != 'mingw' }} - run: | - sudo apt update - sudo apt install \ - libsdl2-dev \ - libfmt-dev \ - librtmidi-dev \ - libsndfile1-dev \ - zlib1g-dev \ - libjack-jackd2-dev \ - appstream - wget "https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage" - chmod +x appimagetool-x86_64.AppImage - - - name: Set package identifier - id: package-identify - run: | - package_name="furnace-${GITHUB_SHA}" - package_ext="" - if [ '${{ runner.os }}' == 'Windows' ] || [ '${{ matrix.config.compiler }}' == 'mingw' ]; then - package_name="${package_name}-Windows" - if [ '${{ matrix.config.compiler }}' == 'mingw' ]; then - package_name="${package_name}-MinGW" - else - package_name="${package_name}-MSVC" - fi - package_name="${package_name}-${{ matrix.config.arch }}" - package_ext="" # Directory, uploading will automatically zip it - elif [ '${{ runner.os }}' == 'macOS' ]; then - package_name="${package_name}-macOS" - package_ext=".dmg" - else - package_name="${package_name}-Linux" - package_ext=".AppImage" - fi - - echo "Package identifier: ${package_name}" - echo "Package file: ${package_name}${package_ext}" - - echo "::set-output name=id::${package_name}" - echo "::set-output name=filename::${package_name}${package_ext}" - - - name: Configure + - name: Configure (Package) run: | export USE_WAE=ON export CMAKE_EXTRA_ARGS=() @@ -288,7 +215,7 @@ jobs: -DWARNINGS_ARE_ERRORS=${USE_WAE} \ "${CMAKE_EXTRA_ARGS[@]}" - - name: Build + - name: Build (Package) run: | export VERBOSE=1 cmake \ From 89455959fc7caffa589c595a69d2101333926613 Mon Sep 17 00:00:00 2001 From: freq-mod <32672779+freq-mod@users.noreply.github.com> Date: Fri, 8 Apr 2022 22:34:13 +0200 Subject: [PATCH 14/76] slightly improve fds docs --- papers/doc/7-systems/fds.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/papers/doc/7-systems/fds.md b/papers/doc/7-systems/fds.md index ee288198..1174b3f3 100644 --- a/papers/doc/7-systems/fds.md +++ b/papers/doc/7-systems/fds.md @@ -3,7 +3,7 @@ the Famicom Disk System is an expansion device for the Famicom (known as NES outside Japan), a popular console from the '80's. as it name implies, it allowed people to play games on specialized floppy disks that could be rewritten on vending machines, therefore reducing the cost of ownership and manufacturing. -it also offers an additional wavetable sound channel with (somewhat limited) FM capabilities, which is what Furnace supports. +it also offers an additional 6-bit, 64-byte wavetable sound channel with (somewhat limited) FM capabilities, which is what Furnace supports. # effects From e10a410cf1a13a3600b66ef1a73e9c2131d2830c Mon Sep 17 00:00:00 2001 From: freq-mod <32672779+freq-mod@users.noreply.github.com> Date: Fri, 8 Apr 2022 22:59:51 +0200 Subject: [PATCH 15/76] some docs improvemets --- papers/doc/7-systems/opll.md | 5 +++ papers/doc/7-systems/saa1099.md | 5 ++- papers/doc/7-systems/vrc6.md | 4 +- papers/doc/effects.md | 66 +++++++++++++++++++++++++++++++++ 4 files changed, 78 insertions(+), 2 deletions(-) create mode 100644 papers/doc/effects.md diff --git a/papers/doc/7-systems/opll.md b/papers/doc/7-systems/opll.md index 06f542f1..2e92171b 100644 --- a/papers/doc/7-systems/opll.md +++ b/papers/doc/7-systems/opll.md @@ -2,6 +2,11 @@ the YM2413, otherwise known as OPLL, is a cost-reduced FM synthesis sound chip, based on the Yamaha YM3812 (OPL2). thought OPL was downgraded enough? :p +OPLL spawned also a few derivative chips, the best known of these is: +- the myth. the legend. THE VRC7. 6 channels, *rather interesting* instruments sound bank, no drums mode +- Yamaha YM2423, same chip as YM2413, just a different patch set +- Yamaha YMF281, ditto + # technical specifications the YM2413 is equipped with the following features: diff --git a/papers/doc/7-systems/saa1099.md b/papers/doc/7-systems/saa1099.md index 093eb603..0cb19fbd 100644 --- a/papers/doc/7-systems/saa1099.md +++ b/papers/doc/7-systems/saa1099.md @@ -1,6 +1,9 @@ # Philips SAA1099 -this was used by the Game Blaster and SAM Coupé. it's pretty similar to the AY-3-8910, but has stereo sound, twice the channels and two envelopes, both of which are highly flexible. +this was used by the Game Blaster and SAM Coupé. it's pretty similar to the AY-3-8910, stereo sound, twice the channels and two envelopes, both of which are highly flexible. The envelopes work like this: + +an instrument with envelope settings is placed on channel 2 or channel 5 +an instrument that is used as an "envelope output", is placed on channel 3 or channel 6. You may want to disable wave output on the output channel. # effects diff --git a/papers/doc/7-systems/vrc6.md b/papers/doc/7-systems/vrc6.md index 63bda1ab..c89678b4 100644 --- a/papers/doc/7-systems/vrc6.md +++ b/papers/doc/7-systems/vrc6.md @@ -5,6 +5,8 @@ the most popular expansion chip to the NES' sound system. the chip has 2 pulse wave channels and one sawtooth channel. volume register is 4 bit for pulse wave and 6 bit for sawtooth, but sawtooth output is corrupted when volume register value is too high. because this register is actually an 8 bit accumulator, its output may wrap around. +For that reason, the sawtooth channel has it's own instrument type. Setting volume macro and pattern editor volume setting too high (above 42/2A) will distort the waveform. + pulse wave duty cycle is 8-level. it can be ignored and it has potential for DAC at this case: volume register in this mode is DAC output and it can be PCM playback through this mode. Furnace supports this routine for PCM playback, but it consumes a lot of CPU time in real hardware (even if conjunction with VRC6's integrated IRQ timer). @@ -13,4 +15,4 @@ Furnace supports this routine for PCM playback, but it consumes a lot of CPU tim these effects only are effective in the pulse channels. - `12xx`: set duty cycle (0 to 7). -- `17xx`: toggle PCM mode. \ No newline at end of file +- `17xx`: toggle PCM mode. diff --git a/papers/doc/effects.md b/papers/doc/effects.md new file mode 100644 index 00000000..773d3037 --- /dev/null +++ b/papers/doc/effects.md @@ -0,0 +1,66 @@ +# effect list + +most of the effect numbers are from ProTracker/FastTracker 2. +however, effects are continuous, which means you only need to type it once and then stop it with an effect value of `00`. + +- `00xy`: arpeggio. after using this effect the channel will rapidly switch between `note`, `note+x` and `note+y`. +- `01xx`: slide up. +- `02xx`: slide down. +- `03xx`: note portamento. + - a note must be present for this effect to work. +- `04xy`: vibrato. `x` is the speed, while `y` is the depth. + - maximum vibrato depth is ±1 semitone. +- `07xy`: tremolo. `x` is the speed, while `y` is the depth. + - maximum tremolo depth is -60 volume steps. +- `08xy`: set panning. `x` is the left channel and `y` is the right one. + - not all systems support this effect. +- `09xx`: set speed 1. +- `0Axy`: volume slide. + - if `x` is 0 then this is a slide down. + - if `y` is 0 then this is a slide up. +- `0Bxx`: jump to pattern. +- `0Cxx`: retrigger note every `xx` ticks. + - this effect is not continuous. +- `0Dxx`: jump to next pattern. +- `0Fxx`: set speed 2. + +- `9xxx`: set sample position to `xxx`\*0x100. + - not all systems support this effect. + +- `Cxxx`: change song Hz. + - `xxx` may be from `000` to `3ff`. + +- `E0xx`: set arpeggio tick. + - this sets the number of ticks between arpeggio values. +- `E1xy`: note slide up. `x` is the speed, while `y` is how many semitones to slide up. +- `E2xy`: note slide down. `x` is the speed, while `y` is how many semitones to slide down. +- `E3xx`: set vibrato direction. `xx` may be one of the following: + - `00`: up and down. + - `01`: up only. + - `02`: down only. +- `E4xx`: set vibrato range in 1/16th of a semitone. +- `E5xx`: set pitch. `80` is 0 cents. + - range is ±1 semitone. +- `EAxx`: toggle legato. +- `EBxx`: set sample bank. + - does not apply on Amiga. +- `ECxx`: note off after `xx` ticks. +- `EDxx`: delay note by `xx` ticks. +- `EExx`: send external command. + - this effect is currently incomplete. +- `EFxx`: add or subtract global pitch. + - this effect is rather weird. use with caution. + - `80` is center. +- `F0xx`: change song Hz by BPM value. +- `F1xx`: single tick slide up. +- `F2xx`: single tick slide down. +- `F3xx`: fine volume slide up (64x slower than `0Axy`). +- `F4xx`: fine volume slide down (64x slower than `0Axy`). +- `F8xx`: single tick volume slide up. +- `F9xx`: single tick volume slide down. +- `FAxy`: fast volume slide (4x faster than `0Axy`). + - if `x` is 0 then this is a slide down. + - if `y` is 0 then this is a slide up. +- `FFxx`: end of song/stop playback. + +additionally each system has its own effects. [click here for more details](../7-systems/README.md). From c381b60143c8ce4e8bf84e848fdeb64904aee290 Mon Sep 17 00:00:00 2001 From: freq-mod <32672779+freq-mod@users.noreply.github.com> Date: Fri, 8 Apr 2022 23:03:02 +0200 Subject: [PATCH 16/76] Update saa1099.md --- papers/doc/7-systems/saa1099.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/papers/doc/7-systems/saa1099.md b/papers/doc/7-systems/saa1099.md index 0cb19fbd..9cf7b643 100644 --- a/papers/doc/7-systems/saa1099.md +++ b/papers/doc/7-systems/saa1099.md @@ -1,6 +1,6 @@ # Philips SAA1099 -this was used by the Game Blaster and SAM Coupé. it's pretty similar to the AY-3-8910, stereo sound, twice the channels and two envelopes, both of which are highly flexible. The envelopes work like this: +this was used by the Game Blaster and SAM Coupé. it's pretty similar to the AY-3-8910, but has stereo sound, twice the channels and two envelopes, both of which are highly flexible. The envelopes work like this: an instrument with envelope settings is placed on channel 2 or channel 5 an instrument that is used as an "envelope output", is placed on channel 3 or channel 6. You may want to disable wave output on the output channel. From 0fcc73b6c6cf8710088e28b241beff248b9b305e Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 8 Apr 2022 16:03:54 -0500 Subject: [PATCH 17/76] WaveSynth: implement more effects --- src/engine/waveSynth.cpp | 50 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/src/engine/waveSynth.cpp b/src/engine/waveSynth.cpp index d658be17..4d776ba4 100644 --- a/src/engine/waveSynth.cpp +++ b/src/engine/waveSynth.cpp @@ -25,6 +25,54 @@ bool DivWaveSynth::tick() { } updated=true; break; + case DIV_WS_ADD: + for (int i=0; i<=state.speed; i++) { + output[pos]+=MIN(height,state.param1); + if (output[pos]>=height) output[pos]-=height; + if (++pos>=width) pos=0; + } + updated=true; + break; + case DIV_WS_SUBTRACT: + for (int i=0; i<=state.speed; i++) { + output[pos]+=MIN(height,state.param1); + if (output[pos]<0) output[pos]+=height; + if (++pos>=width) pos=0; + } + updated=true; + break; + case DIV_WS_AVERAGE: + for (int i=0; i<=state.speed; i++) { + int pos1=(pos+1>=width)?0:(pos+1); + output[pos]=(output[pos]*state.param1+output[pos1]*(256-state.param1))>>8; + if (output[pos]<0) output[pos]=0; + if (output[pos]>height) output[pos]=height; + if (++pos>=width) pos=0; + } + updated=true; + break; + case DIV_WS_PHASE: + for (int i=0; i<=state.speed; i++) { + output[pos]=wave1[(pos+stage)%width]; + if (++pos>=width) { + pos=0; + if (++stage>=width) stage=0; + } + } + updated=true; + break; + case DIV_WS_WIPE: + break; + case DIV_WS_FADE: + break; + case DIV_WS_PING_PONG: + break; + case DIV_WS_OVERLAY: + break; + case DIV_WS_NEGATIVE_OVERLAY: + break; + case DIV_WS_PHASE_DUAL: + break; } divCounter=state.rateDivider; } @@ -96,4 +144,4 @@ void DivWaveSynth::init(DivInstrument* which, int w, int h, bool insChanged) { changeWave1(state.wave1); changeWave2(state.wave2); } -} \ No newline at end of file +} From 7e4890d0ea70a898b2b88c246be2f2be69951563 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 8 Apr 2022 16:10:49 -0500 Subject: [PATCH 18/76] effects back on its orig place for now --- papers/doc/effects.md | 66 ------------------------------------------- 1 file changed, 66 deletions(-) delete mode 100644 papers/doc/effects.md diff --git a/papers/doc/effects.md b/papers/doc/effects.md deleted file mode 100644 index 773d3037..00000000 --- a/papers/doc/effects.md +++ /dev/null @@ -1,66 +0,0 @@ -# effect list - -most of the effect numbers are from ProTracker/FastTracker 2. -however, effects are continuous, which means you only need to type it once and then stop it with an effect value of `00`. - -- `00xy`: arpeggio. after using this effect the channel will rapidly switch between `note`, `note+x` and `note+y`. -- `01xx`: slide up. -- `02xx`: slide down. -- `03xx`: note portamento. - - a note must be present for this effect to work. -- `04xy`: vibrato. `x` is the speed, while `y` is the depth. - - maximum vibrato depth is ±1 semitone. -- `07xy`: tremolo. `x` is the speed, while `y` is the depth. - - maximum tremolo depth is -60 volume steps. -- `08xy`: set panning. `x` is the left channel and `y` is the right one. - - not all systems support this effect. -- `09xx`: set speed 1. -- `0Axy`: volume slide. - - if `x` is 0 then this is a slide down. - - if `y` is 0 then this is a slide up. -- `0Bxx`: jump to pattern. -- `0Cxx`: retrigger note every `xx` ticks. - - this effect is not continuous. -- `0Dxx`: jump to next pattern. -- `0Fxx`: set speed 2. - -- `9xxx`: set sample position to `xxx`\*0x100. - - not all systems support this effect. - -- `Cxxx`: change song Hz. - - `xxx` may be from `000` to `3ff`. - -- `E0xx`: set arpeggio tick. - - this sets the number of ticks between arpeggio values. -- `E1xy`: note slide up. `x` is the speed, while `y` is how many semitones to slide up. -- `E2xy`: note slide down. `x` is the speed, while `y` is how many semitones to slide down. -- `E3xx`: set vibrato direction. `xx` may be one of the following: - - `00`: up and down. - - `01`: up only. - - `02`: down only. -- `E4xx`: set vibrato range in 1/16th of a semitone. -- `E5xx`: set pitch. `80` is 0 cents. - - range is ±1 semitone. -- `EAxx`: toggle legato. -- `EBxx`: set sample bank. - - does not apply on Amiga. -- `ECxx`: note off after `xx` ticks. -- `EDxx`: delay note by `xx` ticks. -- `EExx`: send external command. - - this effect is currently incomplete. -- `EFxx`: add or subtract global pitch. - - this effect is rather weird. use with caution. - - `80` is center. -- `F0xx`: change song Hz by BPM value. -- `F1xx`: single tick slide up. -- `F2xx`: single tick slide down. -- `F3xx`: fine volume slide up (64x slower than `0Axy`). -- `F4xx`: fine volume slide down (64x slower than `0Axy`). -- `F8xx`: single tick volume slide up. -- `F9xx`: single tick volume slide down. -- `FAxy`: fast volume slide (4x faster than `0Axy`). - - if `x` is 0 then this is a slide down. - - if `y` is 0 then this is a slide up. -- `FFxx`: end of song/stop playback. - -additionally each system has its own effects. [click here for more details](../7-systems/README.md). From 0aef54400d637921598c923ebfc1e0331f054bd8 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 8 Apr 2022 16:30:08 -0500 Subject: [PATCH 19/76] exclude Windows/macOS from system lib build in CI --- .github/workflows/build.yml | 32 +++++++++++--------------------- 1 file changed, 11 insertions(+), 21 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 94de2b50..b48c493b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -26,7 +26,7 @@ jobs: - { name: 'Ubuntu', os: ubuntu-18.04 } fail-fast: false - name: "Test: ${{ matrix.config.name }}" + name: ${{ matrix.config.name }} runs-on: ${{ matrix.config.os }} steps: @@ -103,20 +103,6 @@ jobs: mingw-w64 \ mingw-w64-tools - - name: Install Dependencies [macOS] - if: ${{ runner.os == 'macOS' }} - run: | - export HOMEBREW_NO_INSTALL_CLEANUP=1 - brew update - brew install \ - pkg-config \ - sdl2 \ - fmt \ - rtmidi \ - libsndfile \ - zlib \ - jack - - name: Install Dependencies [Ubuntu] if: ${{ runner.os == 'Linux' && matrix.config.compiler != 'mingw' }} run: | @@ -132,7 +118,8 @@ jobs: wget "https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage" chmod +x appimagetool-x86_64.AppImage - - name: Configure (Normal) + - name: Configure (System Libraries) + if: ${{ runner.os == 'Linux' && matrix.config.compiler != 'mingw' }} run: | export USE_WAE=ON export CMAKE_EXTRA_ARGS=() @@ -165,7 +152,8 @@ jobs: -DWARNINGS_ARE_ERRORS=${USE_WAE} \ "${CMAKE_EXTRA_ARGS[@]}" - - name: Build (Normal) + - name: Build (System Libraries) + if: ${{ runner.os == 'Linux' && matrix.config.compiler != 'mingw' }} run: | export VERBOSE=1 cmake \ @@ -173,17 +161,19 @@ jobs: --config ${{ env.BUILD_TYPE }} \ --parallel 2 - - name: Install (Normal) + - name: Install (System Libraries) + if: ${{ runner.os == 'Linux' && matrix.config.compiler != 'mingw' }} run: | cmake \ --install ${PWD}/build \ --config ${{ env.BUILD_TYPE }} - - name: Cleanup (Normal) + - name: Cleanup (System Libraries) + if: ${{ runner.os == 'Linux' && matrix.config.compiler != 'mingw' }} run: | rm -rf build/ target/ - - name: Configure (Package) + - name: Configure run: | export USE_WAE=ON export CMAKE_EXTRA_ARGS=() @@ -215,7 +205,7 @@ jobs: -DWARNINGS_ARE_ERRORS=${USE_WAE} \ "${CMAKE_EXTRA_ARGS[@]}" - - name: Build (Package) + - name: Build run: | export VERBOSE=1 cmake \ From 9e0e8f334599404734fa3f4dfa3ad7275c0d3b61 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 8 Apr 2022 17:21:36 -0500 Subject: [PATCH 20/76] dev80 - increase song limits up to 256 patterns up to 256 orders --- papers/format.md | 7 +++++++ src/engine/engine.cpp | 12 ++++++------ src/engine/engine.h | 4 ++-- src/engine/fileOps.cpp | 33 +++++++++++++++++++++++++++++---- src/engine/orders.h | 4 ++-- src/engine/pattern.cpp | 4 ++-- src/engine/pattern.h | 2 +- src/gui/gui.cpp | 2 +- src/gui/gui.h | 2 +- src/gui/orders.cpp | 4 ++-- src/gui/songInfo.cpp | 2 +- 11 files changed, 54 insertions(+), 22 deletions(-) diff --git a/papers/format.md b/papers/format.md index 9ce20d2d..ce1685c6 100644 --- a/papers/format.md +++ b/papers/format.md @@ -29,6 +29,7 @@ furthermore, an `or reserved` indicates this field is always present, but is res the format versions are: +- 80: Furnace dev80 - 79: Furnace dev79 - 78: Furnace dev78 - 77: Furnace dev77 @@ -119,12 +120,17 @@ size | description | - 60 is NTSC | - 50 is PAL 2 | pattern length + | - the limit is 256. 2 | orders length + | - the limit is 256 (>=80) or 127 (<80). 1 | highlight A 1 | highlight B 2 | instrument count + | - the limit is 256. 2 | wavetable count + | - the limit is 256. 2 | sample count + | - the limit is 256. 4 | pattern count 32 | list of sound chips | - possible soundchips: @@ -230,6 +236,7 @@ size | description | - a table of bytes | - size=channels*ordLen | - read orders then channels + | - the maximum value of a cell is FF (>=80) or 7F (<80). ??? | effect columns | - size=channels 1?? | channel hide status diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index c26058e6..78ae1ce4 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -1281,7 +1281,7 @@ void DivEngine::delInstrument(int index) { song.ins.erase(song.ins.begin()+index); song.insLen=song.ins.size(); for (int i=0; idata[k][2]>index) { @@ -1556,7 +1556,7 @@ void DivEngine::delSample(int index) { void DivEngine::addOrder(bool duplicate, bool where) { unsigned char order[DIV_MAX_CHANS]; - if (song.ordersLen>=0x7e) return; + if (song.ordersLen>=0xff) return; BUSY_BEGIN_SOFT; if (duplicate) { for (int i=0; i=0x7e) return; + if (song.ordersLen>=0xff) return; warnings=""; BUSY_BEGIN_SOFT; for (int i=0; idata[k][2]==one) { diff --git a/src/engine/engine.h b/src/engine/engine.h index 677cdeaa..89005675 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -42,8 +42,8 @@ #define BUSY_BEGIN_SOFT softLocked=true; isBusy.lock(); #define BUSY_END isBusy.unlock(); softLocked=false; -#define DIV_VERSION "dev79" -#define DIV_ENGINE_VERSION 79 +#define DIV_VERSION "dev80" +#define DIV_ENGINE_VERSION 80 // for imports #define DIV_VERSION_MOD 0xff01 diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index 7988992b..37964c68 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -959,7 +959,7 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { delete[] file; return false; } - if (ds.ordersLen>127) { + if (ds.ordersLen>256) { logE("song is too long!\n"); lastError="song is too long!"; delete[] file; @@ -1407,6 +1407,8 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { int index=reader.readS(); reader.readI(); + logD("- %d, %d\n",chan,index); + if (chan<0 || chan>=tchans) { logE("pattern channel out of range!\n",i); lastError="pattern channel out of range!"; @@ -1414,7 +1416,7 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { delete[] file; return false; } - if (index<0 || index>127) { + if (index<0 || index>255) { logE("pattern index out of range!\n",i); lastError="pattern index out of range!"; ds.unload(); @@ -1422,8 +1424,6 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { return false; } - logD("- %d, %d\n",chan,index); - DivPattern* pat=ds.pat[chan].getPattern(index,true); for (int j=0; jdata[j][0]=reader.readS(); @@ -2292,6 +2292,31 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) { lastError="this system is not possible on .dmf"; return NULL; } + // fail if values are out of range + if (song.ordersLen>127) { + logE("maximum .dmf song length is 127!\n"); + lastError="maximum .dmf song length is 127"; + return NULL; + } + if (song.ins.size()>128) { + logE("maximum number of instruments in .dmf is 128!\n"); + lastError="maximum number of instruments in .dmf is 128"; + return NULL; + } + if (song.wave.size()>64) { + logE("maximum number of wavetables in .dmf is 64!\n"); + lastError="maximum number of wavetables in .dmf is 64"; + return NULL; + } + for (int i=0; i0x7f) { + logE("order %d, %d is out of range (0-127)!\n",song.orders.ord[i][j]); + lastError=fmt::sprintf("order %d, %d is out of range (0-127)",song.orders.ord[i][j]); + return NULL; + } + } + } saveLock.lock(); warnings=""; song.version=version; diff --git a/src/engine/orders.h b/src/engine/orders.h index d10dbe4c..c57d1aab 100644 --- a/src/engine/orders.h +++ b/src/engine/orders.h @@ -21,10 +21,10 @@ #define _ORDERS_H struct DivOrders { - unsigned char ord[DIV_MAX_CHANS][128]; + unsigned char ord[DIV_MAX_CHANS][256]; DivOrders() { - memset(ord,0,DIV_MAX_CHANS*128); + memset(ord,0,DIV_MAX_CHANS*256); } }; diff --git a/src/engine/pattern.cpp b/src/engine/pattern.cpp index 91a4ecd4..8241255b 100644 --- a/src/engine/pattern.cpp +++ b/src/engine/pattern.cpp @@ -41,7 +41,7 @@ DivPattern* DivChannelData::getPattern(int index, bool create) { } void DivChannelData::wipePatterns() { - for (int i=0; i<128; i++) { + for (int i=0; i<256; i++) { if (data[i]!=NULL) { delete data[i]; data[i]=NULL; @@ -131,5 +131,5 @@ SafeReader* DivPattern::compile(int len, int fxRows) { DivChannelData::DivChannelData(): effectRows(1) { - memset(data,0,128*sizeof(void*)); + memset(data,0,256*sizeof(void*)); } diff --git a/src/engine/pattern.h b/src/engine/pattern.h index 1af744b6..fd0b0d07 100644 --- a/src/engine/pattern.h +++ b/src/engine/pattern.h @@ -49,7 +49,7 @@ struct DivChannelData { // 3: volume // 4-5+: effect/effect value // do NOT access directly unless you know what you're doing! - DivPattern* data[128]; + DivPattern* data[256]; /** * get a pattern from this channel, or the empty pattern if not initialized. diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index bae782ff..755b825a 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -1131,7 +1131,7 @@ void FurnaceGUI::keyDown(SDL_Event& ev) { if (orderCursor>=0 && orderCursorgetTotalChannelCount()) { int curOrder=e->getOrder(); e->lockSave([this,curOrder,num]() { - e->song.orders.ord[orderCursor][curOrder]=((e->song.orders.ord[orderCursor][curOrder]<<4)|num)&0x7f; + e->song.orders.ord[orderCursor][curOrder]=((e->song.orders.ord[orderCursor][curOrder]<<4)|num); }); if (orderEditMode==2 || orderEditMode==3) { curNibble=!curNibble; diff --git a/src/gui/gui.h b/src/gui/gui.h index 445369f0..a797700f 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -952,7 +952,7 @@ class FurnaceGUI { int oldOrdersLen; DivOrders oldOrders; - DivPattern* oldPat[128]; + DivPattern* oldPat[DIV_MAX_CHANS]; std::deque undoHist; std::deque redoHist; diff --git a/src/gui/orders.cpp b/src/gui/orders.cpp index b233c48b..945f551d 100644 --- a/src/gui/orders.cpp +++ b/src/gui/orders.cpp @@ -102,10 +102,10 @@ void FurnaceGUI::drawOrders() { e->lockSave([this,i,j]() { if (changeAllOrders) { for (int k=0; kgetTotalChannelCount(); k++) { - if (e->song.orders.ord[k][i]<0x7f) e->song.orders.ord[k][i]++; + if (e->song.orders.ord[k][i]<0xff) e->song.orders.ord[k][i]++; } } else { - if (e->song.orders.ord[j][i]<0x7f) e->song.orders.ord[j][i]++; + if (e->song.orders.ord[j][i]<0xff) e->song.orders.ord[j][i]++; } }); e->walkSong(loopOrder,loopRow,loopEnd); diff --git a/src/gui/songInfo.cpp b/src/gui/songInfo.cpp index b5923801..a2f788c3 100644 --- a/src/gui/songInfo.cpp +++ b/src/gui/songInfo.cpp @@ -122,7 +122,7 @@ void FurnaceGUI::drawSongInfo() { int ordLen=e->song.ordersLen; if (ImGui::InputInt("##OrdLength",&ordLen,1,3)) { MARK_MODIFIED if (ordLen<1) ordLen=1; - if (ordLen>127) ordLen=127; + if (ordLen>256) ordLen=256; e->song.ordersLen=ordLen; if (e->getOrder()>=ordLen) { e->setOrder(ordLen-1); From 320250b8311de4910f946226cc57e5f153aa9bc5 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 9 Apr 2022 01:50:44 -0500 Subject: [PATCH 21/76] MIDI out improvements --- src/engine/engine.cpp | 13 +++++++++++++ src/engine/engine.h | 7 +++++-- src/engine/playback.cpp | 22 +++++++++++++++++++--- 3 files changed, 37 insertions(+), 5 deletions(-) diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 78ae1ce4..f11f967d 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -873,6 +873,11 @@ void DivEngine::play() { for (int i=0; imidiOut!=NULL) { + int pos=totalTicksR/6; + output->midiOut->send(TAMidiMessage(TA_MIDI_POSITION,(pos>>7)&0x7f,pos&0x7f)); + output->midiOut->send(TAMidiMessage(TA_MIDI_MACHINE_PLAY,0,0)); + } BUSY_END; } @@ -918,6 +923,14 @@ void DivEngine::stop() { for (int i=0; inotifyPlaybackStop(); } + if (output) if (output->midiOut!=NULL) { + output->midiOut->send(TAMidiMessage(TA_MIDI_MACHINE_STOP,0,0)); + for (int i=0; i=0) { + output->midiOut->send(TAMidiMessage(0x80|(i&15),chan[i].curMidiNote,0)); + } + } + } BUSY_END; } diff --git a/src/engine/engine.h b/src/engine/engine.h index 89005675..6741a00e 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -86,7 +86,8 @@ struct DivChannelState { bool doNote, legato, portaStop, keyOn, keyOff, nowYouCanStop, stopOnOff; bool arpYield, delayLocked, inPorta, scheduledSlideReset, shorthandPorta, noteOnInhibit, resetArp; - int midiNote, curMidiNote; + int midiNote, curMidiNote, midiPitch; + bool midiAftertouch; DivChannelState(): note(-1), @@ -130,7 +131,9 @@ struct DivChannelState { noteOnInhibit(false), resetArp(false), midiNote(-1), - curMidiNote(-1) {} + curMidiNote(-1), + midiPitch(-1), + midiAftertouch(false) {} }; struct DivNoteEvent { diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index 8e1f1d66..1776b046 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -201,16 +201,24 @@ int DivEngine::dispatchCmd(DivCommand c) { chan[c.chan].curMidiNote=-1; break; case DIV_CMD_INSTRUMENT: - output->midiOut->send(TAMidiMessage(0xc0|(c.chan&15),c.value,0)); + if (chan[c.chan].lastIns!=c.value) { + output->midiOut->send(TAMidiMessage(0xc0|(c.chan&15),c.value,0)); + } break; case DIV_CMD_VOLUME: - //output->midiOut->send(TAMidiMessage(0xb0|(c.chan&15),0x07,scaledVol)); + if (chan[c.chan].curMidiNote>=0 && chan[c.chan].midiAftertouch) { + chan[c.chan].midiAftertouch=false; + output->midiOut->send(TAMidiMessage(0xa0|(c.chan&15),chan[c.chan].curMidiNote,scaledVol)); + } break; case DIV_CMD_PITCH: { int pitchBend=8192+(c.value<<5); if (pitchBend<0) pitchBend=0; if (pitchBend>16383) pitchBend=16383; - output->midiOut->send(TAMidiMessage(0xe0|(c.chan&15),pitchBend&0x7f,pitchBend>>7)); + if (pitchBend!=chan[c.chan].midiPitch) { + chan[c.chan].midiPitch=pitchBend; + output->midiOut->send(TAMidiMessage(0xe0|(c.chan&15),pitchBend&0x7f,pitchBend>>7)); + } break; } default: @@ -963,6 +971,9 @@ void DivEngine::processRow(int i, bool afterDelay) { // volume if (pat->data[whatRow][3]!=-1) { if (dispatchCmd(DivCommand(DIV_ALWAYS_SET_VOLUME,i)) || (MIN(chan[i].volMax,chan[i].volume)>>8)!=pat->data[whatRow][3]) { + if (pat->data[whatRow][0]==0 && pat->data[whatRow][1]==0) { + chan[i].midiAftertouch=true; + } chan[i].volume=pat->data[whatRow][3]<<8; dispatchCmd(DivCommand(DIV_CMD_VOLUME,i,chan[i].volume>>8)); } @@ -1436,6 +1447,11 @@ bool DivEngine::nextTick(bool noAccum) { cycles++; } + // MIDI clock + if (output) if (!skipping && output->midiOut!=NULL) { + output->midiOut->send(TAMidiMessage(TA_MIDI_CLOCK,0,0)); + } + while (!pendingNotes.empty()) { DivNoteEvent& note=pendingNotes.front(); if (note.on) { From 7bf2a3ea1a64703d3fec0fa9974fd2aeec2fd115 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 9 Apr 2022 02:42:58 -0500 Subject: [PATCH 22/76] GUI: prepare for oscilloscope improvements --- src/engine/engine.h | 3 +++ src/engine/playback.cpp | 7 ++++-- src/gui/gui.cpp | 7 +++++- src/gui/gui.h | 6 +++++ src/gui/osc.cpp | 51 ++++++++++++++++++++++++++++++++++++----- src/gui/volMeter.cpp | 8 ------- 6 files changed, 65 insertions(+), 17 deletions(-) diff --git a/src/engine/engine.h b/src/engine/engine.h index 6741a00e..68ec0ce5 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -298,6 +298,7 @@ class DivEngine { bool keyHit[DIV_MAX_CHANS]; float* oscBuf[2]; float oscSize; + int oscReadPos, oscWritePos; void runExportThread(); void nextBuf(float** in, float** out, int inChans, int outChans, unsigned int size); @@ -772,6 +773,8 @@ class DivEngine { totalProcessed(0), oscBuf{NULL,NULL}, oscSize(1), + oscReadPos(0), + oscWritePos(0), adpcmAMem(NULL), adpcmAMemLen(0), adpcmBMem(NULL), diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index 1776b046..e6fb4d72 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -1896,8 +1896,11 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi while (metroPos>=1) metroPos--; } - memcpy(oscBuf[0],out[0],size*sizeof(float)); - memcpy(oscBuf[1],out[1],size*sizeof(float)); + for (unsigned int i=0; i=32768) oscWritePos=0; + } oscSize=size; if (forceMono) { diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 755b825a..23110ef8 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -2600,6 +2600,9 @@ bool FurnaceGUI::loop() { drawInsList(); drawInsEdit(); drawMixer(); + + readOsc(); + drawOsc(); drawVolMeter(); drawSettings(); @@ -3428,7 +3431,8 @@ FurnaceGUI::FurnaceGUI(): openSampleResampleOpt(false), openSampleAmplifyOpt(false), openSampleSilenceOpt(false), - openSampleFilterOpt(false) { + openSampleFilterOpt(false), + oscTotal(0) { // value keys valueKeys[SDLK_0]=0; valueKeys[SDLK_1]=1; @@ -3469,4 +3473,5 @@ FurnaceGUI::FurnaceGUI(): memset(patChanX,0,sizeof(float)*(DIV_MAX_CHANS+1)); memset(patChanSlideY,0,sizeof(float)*(DIV_MAX_CHANS+1)); memset(lastIns,-1,sizeof(int)*DIV_MAX_CHANS); + memset(oscValues,0,sizeof(float)*512); } diff --git a/src/gui/gui.h b/src/gui/gui.h index a797700f..6d8f300b 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -976,6 +976,10 @@ class FurnaceGUI { size_t sampleClipboardLen; bool openSampleResizeOpt, openSampleResampleOpt, openSampleAmplifyOpt, openSampleSilenceOpt, openSampleFilterOpt; + // oscilloscope + int oscTotal; + float oscValues[512]; + // visualizer float keyHit[DIV_MAX_CHANS]; int lastIns[DIV_MAX_CHANS]; @@ -996,6 +1000,8 @@ class FurnaceGUI { void updateWindowTitle(); void prepareLayout(); + void readOsc(); + float calcBPM(int s1, int s2, float hz); void patternRow(int i, bool isPlaying, float lineHeight, int chans, int ord, const DivPattern** patCache); diff --git a/src/gui/osc.cpp b/src/gui/osc.cpp index 0bdcdf8a..a4da29c8 100644 --- a/src/gui/osc.cpp +++ b/src/gui/osc.cpp @@ -18,6 +18,50 @@ */ #include "gui.h" +#include + +void FurnaceGUI::readOsc() { + int writePos=e->oscWritePos; + int readPos=e->oscReadPos; + int avail=0; + int total=0; + if (writePos>=readPos) { + avail=writePos-readPos; + } else { + avail=writePos-readPos+32768; + } + if (oscTotal==0) { + oscTotal=ImGui::GetIO().DeltaTime*e->getAudioDescGot().rate; + } else { + oscTotal=(oscTotal+(int)round(ImGui::GetIO().DeltaTime*e->getAudioDescGot().rate))>>1; + } + int bias=avail-oscTotal-e->getAudioDescGot().bufsize; + if (bias<0) bias=0; + total=oscTotal+(bias>>6); + if (total>avail) total=avail; + //printf("total: %d. avail: %d bias: %d\n",total,avail,bias); + for (int i=0; i<512; i++) { + int pos=(readPos+(i*total/512))&0x7fff; + oscValues[i]=(e->oscBuf[0][pos]+e->oscBuf[1][pos])*0.5f; + } + + float peakDecay=0.05f*60.0f*ImGui::GetIO().DeltaTime; + for (int i=0; i<2; i++) { + peak[i]*=1.0-peakDecay; + if (peak[i]<0.0001) peak[i]=0.0; + float newPeak=peak[i]; + for (int j=0; joscBuf[i][pos])>newPeak) { + newPeak=fabs(e->oscBuf[i][pos]); + } + } + peak[i]+=(newPeak-peak[i])*0.9; + } + + readPos=(readPos+total)&0x7fff; + e->oscReadPos=readPos; +} void FurnaceGUI::drawOsc() { if (nextWindow==GUI_WINDOW_OSCILLOSCOPE) { @@ -31,14 +75,9 @@ void FurnaceGUI::drawOsc() { ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing,ImVec2(0,0)); ImGui::PushStyleVar(ImGuiStyleVar_ItemInnerSpacing,ImVec2(0,0)); if (ImGui::Begin("Oscilloscope",&oscOpen)) { - float values[512]; - for (int i=0; i<512; i++) { - int pos=i*e->oscSize/512; - values[i]=(e->oscBuf[0][pos]+e->oscBuf[1][pos])*0.5f; - } //ImGui::SetCursorPos(ImVec2(0,0)); ImGui::BeginDisabled(); - ImGui::PlotLines("##SingleOsc",values,512,0,NULL,-1.0f,1.0f,ImGui::GetContentRegionAvail()); + ImGui::PlotLines("##SingleOsc",oscValues,512,0,NULL,-1.0f,1.0f,ImGui::GetContentRegionAvail()); ImGui::EndDisabled(); } ImGui::PopStyleVar(3); diff --git a/src/gui/volMeter.cpp b/src/gui/volMeter.cpp index 29f62c96..7be3464e 100644 --- a/src/gui/volMeter.cpp +++ b/src/gui/volMeter.cpp @@ -49,17 +49,9 @@ void FurnaceGUI::drawVolMeter() { ImGuiStyle& style=ImGui::GetStyle(); ImGui::ItemSize(ImVec2(4.0f,4.0f),style.FramePadding.y); ImU32 lowColor=ImGui::GetColorU32(uiColors[GUI_COLOR_VOLMETER_LOW]); - float peakDecay=0.05f*60.0f*ImGui::GetIO().DeltaTime; if (ImGui::ItemAdd(rect,ImGui::GetID("volMeter"))) { ImGui::RenderFrame(rect.Min,rect.Max,ImGui::GetColorU32(ImGuiCol_FrameBg),true,style.FrameRounding); for (int i=0; i<2; i++) { - peak[i]*=1.0-peakDecay; - if (peak[i]<0.0001) peak[i]=0.0; - for (int j=0; joscSize; j++) { - if (fabs(e->oscBuf[i][j])>peak[i]) { - peak[i]=fabs(e->oscBuf[i][j]); - } - } float logPeak=(20*log10(peak[i])/36.0); if (logPeak==NAN) logPeak=0.0; if (logPeak<-1.0) logPeak=-1.0; From 785ac8d1a71380ece6d0966eee469c2730be55c8 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 9 Apr 2022 02:45:06 -0500 Subject: [PATCH 23/76] small oscBuf fix --- src/engine/playback.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index e6fb4d72..d6d18465 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -1748,8 +1748,11 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi if (!playing) { if (out!=NULL) { - memcpy(oscBuf[0],out[0],size*sizeof(float)); - memcpy(oscBuf[1],out[1],size*sizeof(float)); + for (unsigned int i=0; i=32768) oscWritePos=0; + } oscSize=size; } isBusy.unlock(); From d4fbebf47896d180bc197c12284b223f1c57e2de Mon Sep 17 00:00:00 2001 From: OPNA2608 Date: Thu, 31 Mar 2022 18:50:09 +0200 Subject: [PATCH 24/76] Lower MSVC warning level to 2 (significant), enable WAE on CI --- .github/workflows/build.yml | 6 ------ CMakeLists.txt | 5 ++--- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b48c493b..19118f6a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -125,9 +125,6 @@ jobs: export CMAKE_EXTRA_ARGS=() if [ '${{ matrix.config.compiler }}' == 'msvc' ]; then CMAKE_EXTRA_ARGS+=('-DCMAKE_GENERATOR_PLATFORM=${{ steps.windows-identify.outputs.msvc-target }}') - - # FIXME We don't want all the MSVC warnings to cause errors yet - export USE_WAE=OFF elif [ '${{ matrix.config.compiler }}' == 'mingw' ]; then CMAKE_EXTRA_ARGS+=('-DCMAKE_TOOLCHAIN_FILE=scripts/Cross-MinGW-${{ steps.windows-identify.outputs.mingw-target }}.cmake') else @@ -180,9 +177,6 @@ jobs: if [ '${{ matrix.config.compiler }}' == 'msvc' ]; then CMAKE_EXTRA_ARGS+=('-DCMAKE_GENERATOR_PLATFORM=${{ steps.windows-identify.outputs.msvc-target }}') - # FIXME We don't want all the MSVC warnings to cause errors yet - export USE_WAE=OFF - # Force static linking # 1. Make MSVC runtime configurable CMAKE_EXTRA_ARGS+=('-DCMAKE_POLICY_DEFAULT_CMP0091=NEW') diff --git a/CMakeLists.txt b/CMakeLists.txt index 769842f3..3f23e102 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -457,9 +457,8 @@ if (NOT MSVC) list(APPEND WARNING_FLAGS -Werror) endif() else() - # /wd4100 == -Wno-unused-parameter - add_compile_options("/source-charset:utf-8") - set(WARNING_FLAGS /W4 /wd4100 /D_CRT_SECURE_NO_WARNINGS) + add_compile_options("/utf-8") + set(WARNING_FLAGS /W2 /D_CRT_SECURE_NO_WARNINGS) if (WARNINGS_ARE_ERRORS) list(APPEND WARNING_FLAGS /WX) endif() From 43b12c1ca549a58c7bec9f6f5aea7b191ec0db7e Mon Sep 17 00:00:00 2001 From: OPNA2608 Date: Sat, 2 Apr 2022 18:35:00 +0200 Subject: [PATCH 25/76] Ignore C4244, C4305 & C4309 --- CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3f23e102..c240e37b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -459,6 +459,11 @@ if (NOT MSVC) else() add_compile_options("/utf-8") set(WARNING_FLAGS /W2 /D_CRT_SECURE_NO_WARNINGS) + list(APPEND WARNING_FLAGS + /wd4244 # implicit type conversions + /wd4305 # truncations + /wd4309 # truncations of constant values + ) if (WARNINGS_ARE_ERRORS) list(APPEND WARNING_FLAGS /WX) endif() From 82d893082cddae36c90bef56ad0949c9f221acad Mon Sep 17 00:00:00 2001 From: OPNA2608 Date: Thu, 31 Mar 2022 20:28:30 +0200 Subject: [PATCH 26/76] Fix for C4005: '_CRT_SECURE_NO_WARNINGS': macro redefinition --- src/engine/platform/sound/ymfm/ymfm.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/platform/sound/ymfm/ymfm.h b/src/engine/platform/sound/ymfm/ymfm.h index 906e3211..7b98f849 100644 --- a/src/engine/platform/sound/ymfm/ymfm.h +++ b/src/engine/platform/sound/ymfm/ymfm.h @@ -33,7 +33,7 @@ #pragma once -#ifdef _MSC_VER +#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) #define _CRT_SECURE_NO_WARNINGS #endif From 4c19a973efc4c57086e6d75e1ea3143d90cee36a Mon Sep 17 00:00:00 2001 From: OPNA2608 Date: Thu, 31 Mar 2022 20:46:27 +0200 Subject: [PATCH 27/76] Fix for C4805: '|': unsafe mix of type 'unsigned char' and type 'bool' in operation --- src/engine/platform/ay8930.cpp | 2 +- src/engine/platform/c64.cpp | 16 ++++++++-------- src/engine/platform/opl.cpp | 2 +- src/engine/platform/opll.cpp | 2 +- src/engine/platform/sound/ay8910.cpp | 2 +- src/gui/sysConf.cpp | 4 ++-- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/engine/platform/ay8930.cpp b/src/engine/platform/ay8930.cpp index 1849d0cd..eda6af04 100644 --- a/src/engine/platform/ay8930.cpp +++ b/src/engine/platform/ay8930.cpp @@ -123,7 +123,7 @@ void DivPlatformAY8930::acquire(short* bufL, short* bufR, size_t start, size_t l } while (!writes.empty()) { QueuedWrite w=writes.front(); - if (bank!=(w.addr>>4)) { + if ((int)bank!=(w.addr>>4)) { bank=w.addr>>4; ay->address_w(0x0d); ay->data_w(0xa0|(bank<<4)|ayEnvMode[0]); diff --git a/src/engine/platform/c64.cpp b/src/engine/platform/c64.cpp index 49be60fb..6ddb2cf4 100644 --- a/src/engine/platform/c64.cpp +++ b/src/engine/platform/c64.cpp @@ -118,7 +118,7 @@ void DivPlatformC64::acquire(short* bufL, short* bufR, size_t start, size_t len) void DivPlatformC64::updateFilter() { rWrite(0x15,filtCut&7); rWrite(0x16,filtCut>>3); - rWrite(0x17,(filtRes<<4)|(chan[2].filter<<2)|(chan[1].filter<<1)|(chan[0].filter)); + rWrite(0x17,(filtRes<<4)|(chan[2].filter<<2)|(chan[1].filter<<1)|(int)(chan[0].filter)); rWrite(0x18,(filtControl<<4)|vol); } @@ -177,7 +177,7 @@ void DivPlatformC64::tick() { } if (chan[i].std.hadWave) { chan[i].wave=chan[i].std.wave; - rWrite(i*7+4,(isMuted[i]?8:(chan[i].wave<<4))|(chan[i].ring<<2)|(chan[i].sync<<1)|chan[i].active); + rWrite(i*7+4,(isMuted[i]?8:(chan[i].wave<<4))|(chan[i].ring<<2)|(chan[i].sync<<1)|(int)(chan[i].active)); } if (chan[i].std.hadEx1) { filtControl=chan[i].std.ex1&15; @@ -232,7 +232,7 @@ int DivPlatformC64::dispatch(DivCommand c) { rWrite(c.chan*7+3,chan[c.chan].duty>>8); } if (chan[c.chan].insChanged) { - chan[c.chan].wave=(ins->c64.noiseOn<<3)|(ins->c64.pulseOn<<2)|(ins->c64.sawOn<<1)|(ins->c64.triOn); + chan[c.chan].wave=(ins->c64.noiseOn<<3)|(ins->c64.pulseOn<<2)|(ins->c64.sawOn<<1)|(int)(ins->c64.triOn); chan[c.chan].attack=ins->c64.a; chan[c.chan].decay=(ins->c64.s==15)?0:ins->c64.d; chan[c.chan].sustain=ins->c64.s; @@ -245,7 +245,7 @@ int DivPlatformC64::dispatch(DivCommand c) { if (ins->c64.initFilter) { filtCut=ins->c64.cut; filtRes=ins->c64.res; - filtControl=ins->c64.lp|(ins->c64.bp<<1)|(ins->c64.hp<<2)|(ins->c64.ch3off<<3); + filtControl=(int)(ins->c64.lp)|(ins->c64.bp<<1)|(ins->c64.hp<<2)|(ins->c64.ch3off<<3); } updateFilter(); } @@ -330,7 +330,7 @@ int DivPlatformC64::dispatch(DivCommand c) { break; case DIV_CMD_WAVE: chan[c.chan].wave=c.value; - rWrite(c.chan*7+4,(isMuted[c.chan]?8:(chan[c.chan].wave<<4))|(chan[c.chan].ring<<2)|(chan[c.chan].sync<<1)|chan[c.chan].active); + rWrite(c.chan*7+4,(isMuted[c.chan]?8:(chan[c.chan].wave<<4))|(chan[c.chan].ring<<2)|(chan[c.chan].sync<<1)|(int)(chan[c.chan].active)); break; case DIV_CMD_LEGATO: chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value+((chan[c.chan].std.willArp && !chan[c.chan].std.arpMode)?(chan[c.chan].std.arp):(0))); @@ -411,11 +411,11 @@ int DivPlatformC64::dispatch(DivCommand c) { break; case 4: chan[c.chan].ring=c.value; - rWrite(c.chan*7+4,(isMuted[c.chan]?8:(chan[c.chan].wave<<4))|(chan[c.chan].ring<<2)|(chan[c.chan].sync<<1)|chan[c.chan].active); + rWrite(c.chan*7+4,(isMuted[c.chan]?8:(chan[c.chan].wave<<4))|(chan[c.chan].ring<<2)|(chan[c.chan].sync<<1)|(int)(chan[c.chan].active)); break; case 5: chan[c.chan].sync=c.value; - rWrite(c.chan*7+4,(isMuted[c.chan]?8:(chan[c.chan].wave<<4))|(chan[c.chan].ring<<2)|(chan[c.chan].sync<<1)|chan[c.chan].active); + rWrite(c.chan*7+4,(isMuted[c.chan]?8:(chan[c.chan].wave<<4))|(chan[c.chan].ring<<2)|(chan[c.chan].sync<<1)|(int)(chan[c.chan].active)); break; case 6: filtControl&=7; @@ -434,7 +434,7 @@ int DivPlatformC64::dispatch(DivCommand c) { void DivPlatformC64::muteChannel(int ch, bool mute) { isMuted[ch]=mute; - rWrite(ch*7+4,(isMuted[ch]?8:(chan[ch].wave<<4))|(chan[ch].ring<<2)|(chan[ch].sync<<1)|chan[ch].active); + rWrite(ch*7+4,(isMuted[ch]?8:(chan[ch].wave<<4))|(chan[ch].ring<<2)|(chan[ch].sync<<1)|(int)(chan[ch].active)); } void DivPlatformC64::forceIns() { diff --git a/src/engine/platform/opl.cpp b/src/engine/platform/opl.cpp index fcba9f80..bd0ae933 100644 --- a/src/engine/platform/opl.cpp +++ b/src/engine/platform/opl.cpp @@ -371,7 +371,7 @@ void DivPlatformOPL::tick() { if (update4OpMask) { update4OpMask=false; if (oplType==3) { - unsigned char opMask=chan[0].fourOp|(chan[2].fourOp<<1)|(chan[4].fourOp<<2)|(chan[6].fourOp<<3)|(chan[8].fourOp<<4)|(chan[10].fourOp<<5); + unsigned char opMask=(int)(chan[0].fourOp)|(chan[2].fourOp<<1)|(chan[4].fourOp<<2)|(chan[6].fourOp<<3)|(chan[8].fourOp<<4)|(chan[10].fourOp<<5); immWrite(0x104,opMask); //printf("updating opMask to %.2x\n",opMask); } diff --git a/src/engine/platform/opll.cpp b/src/engine/platform/opll.cpp index 55a1fa80..14332bce 100644 --- a/src/engine/platform/opll.cpp +++ b/src/engine/platform/opll.cpp @@ -620,7 +620,7 @@ int DivPlatformOPLL::dispatch(DivCommand c) { } case DIV_CMD_FM_EXTCH: if (!properDrumsSys) break; - if (properDrums==c.value) break; + if ((int)properDrums==c.value) break; if (c.value) { properDrums=true; immWrite(0x0e,0x20); diff --git a/src/engine/platform/sound/ay8910.cpp b/src/engine/platform/sound/ay8910.cpp index 2d734f93..8bb38788 100644 --- a/src/engine/platform/sound/ay8910.cpp +++ b/src/engine/platform/sound/ay8910.cpp @@ -1120,7 +1120,7 @@ void ay8910_device::sound_stream_update(short** outputs, int outLen) for (int chan = 0; chan < NUM_CHANNELS; chan++) { tone = &m_tone[chan]; - m_vol_enabled[chan] = (tone->output | tone_enable(chan)) & (noise_output() | noise_enable(chan)); + m_vol_enabled[chan] = (tone->output | (unsigned char)tone_enable(chan)) & (noise_output() | (unsigned char)noise_enable(chan)); } /* update envelope */ diff --git a/src/gui/sysConf.cpp b/src/gui/sysConf.cpp index 1bc60c7c..8ecf7c07 100644 --- a/src/gui/sysConf.cpp +++ b/src/gui/sysConf.cpp @@ -284,7 +284,7 @@ void FurnaceGUI::drawSysConf(int i) { } sysPal=flags&1; if (ImGui::Checkbox("PAL",&sysPal)) { - e->setSysFlags(i,(flags&(~1))|sysPal,restart); + e->setSysFlags(i,(flags&(~1))|(unsigned int)sysPal,restart); updateWindowTitle(); } bool bypassLimits=flags&4; @@ -395,4 +395,4 @@ void FurnaceGUI::drawSysConf(int i) { } break; } -} \ No newline at end of file +} From 16ad29ae7a775d5a92ff684ad5576f069ac18276 Mon Sep 17 00:00:00 2001 From: OPNA2608 Date: Thu, 31 Mar 2022 23:01:22 +0200 Subject: [PATCH 28/76] Fix C4293: '<<': shift count negative or too big, undefined behavior MSVC seems kinda braindead: https://reviews.llvm.org/D41030#952363 --- src/gui/insEdit.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 14ca65b4..7412c15d 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -1044,7 +1044,7 @@ void FurnaceGUI::drawFMEnv(unsigned char tl, unsigned char ar, unsigned char dr, } \ ImGui::SetNextItemWidth(availableWidth); \ if (ImGui::InputText("##IMacroMML_" macroName,&mmlStr)) { \ - decodeMMLStr(mmlStr,macro,macroLen,macroLoop,macroAMin,(bitfield)?((1< Date: Sat, 9 Apr 2022 11:23:19 +0200 Subject: [PATCH 29/76] Fix C4229 Move calling convention modifier for icon callback lambda in pfd, MSVC wasn't quite happy with this. --- extern/pfd-fixed/portable-file-dialogs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extern/pfd-fixed/portable-file-dialogs.h b/extern/pfd-fixed/portable-file-dialogs.h index 008fe0a9..3d90a854 100644 --- a/extern/pfd-fixed/portable-file-dialogs.h +++ b/extern/pfd-fixed/portable-file-dialogs.h @@ -1383,7 +1383,7 @@ inline notify::notify(std::string const &title, /* case icon::info: */ default: nid->dwInfoFlags = NIIF_INFO; break; } - ENUMRESNAMEPROC icon_enum_callback = [](HMODULE, LPCTSTR, LPTSTR lpName, LONG_PTR lParam) -> BOOL WINAPI + ENUMRESNAMEPROC icon_enum_callback = [](HMODULE, LPCTSTR, LPTSTR lpName, LONG_PTR lParam) WINAPI -> BOOL { ((NOTIFYICONDATAW *)lParam)->hIcon = ::LoadIcon(GetModuleHandle(nullptr), lpName); return false; From 11cdc3924d9f4e612dadde1bff7390d65429efb0 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 9 Apr 2022 05:02:24 -0500 Subject: [PATCH 30/76] GUI: improve oscilloscope it's not finished yet --- src/gui/gui.cpp | 4 +- src/gui/gui.h | 12 ++++++ src/gui/guiConst.cpp | 10 +++++ src/gui/osc.cpp | 90 ++++++++++++++++++++++++++++++++++++++++---- src/gui/settings.cpp | 12 ++++++ 5 files changed, 119 insertions(+), 9 deletions(-) diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 23110ef8..66930051 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -3432,7 +3432,9 @@ FurnaceGUI::FurnaceGUI(): openSampleAmplifyOpt(false), openSampleSilenceOpt(false), openSampleFilterOpt(false), - oscTotal(0) { + oscTotal(0), + oscZoom(0.5f), + oscZoomSlider(false) { // value keys valueKeys[SDLK_0]=0; valueKeys[SDLK_1]=1; diff --git a/src/gui/gui.h b/src/gui/gui.h index 6d8f300b..641cf7c0 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -71,6 +71,16 @@ enum FurnaceGUIColors { GUI_COLOR_FILE_FONT, GUI_COLOR_FILE_OTHER, + GUI_COLOR_OSC_BG1, + GUI_COLOR_OSC_BG2, + GUI_COLOR_OSC_BG3, + GUI_COLOR_OSC_BG4, + GUI_COLOR_OSC_BORDER, + GUI_COLOR_OSC_WAVE, + GUI_COLOR_OSC_WAVE_PEAK, + GUI_COLOR_OSC_REF, + GUI_COLOR_OSC_GUIDE, + GUI_COLOR_VOLMETER_LOW, GUI_COLOR_VOLMETER_HIGH, GUI_COLOR_VOLMETER_PEAK, @@ -979,6 +989,8 @@ class FurnaceGUI { // oscilloscope int oscTotal; float oscValues[512]; + float oscZoom; + bool oscZoomSlider; // visualizer float keyHit[DIV_MAX_CHANS]; diff --git a/src/gui/guiConst.cpp b/src/gui/guiConst.cpp index 08582933..c3a7c72b 100644 --- a/src/gui/guiConst.cpp +++ b/src/gui/guiConst.cpp @@ -377,6 +377,16 @@ const FurnaceGUIColorDef guiColors[GUI_COLOR_MAX]={ D(GUI_COLOR_FILE_FONT,"",ImVec4(0.3f,1.0f,0.6f,1.0f)), D(GUI_COLOR_FILE_OTHER,"",ImVec4(0.7f,0.7f,0.7f,1.0f)), + D(GUI_COLOR_OSC_BG1,"",ImVec4(0.1f,0.18f,0.3f,1.0f)), + D(GUI_COLOR_OSC_BG2,"",ImVec4(0.1f,0.18f,0.3f,1.0f)), + D(GUI_COLOR_OSC_BG3,"",ImVec4(0.05f,0.15f,0.25f,1.0f)), + D(GUI_COLOR_OSC_BG4,"",ImVec4(0.05f,0.15f,0.25f,1.0f)), + D(GUI_COLOR_OSC_BORDER,"",ImVec4(0.4f,0.6f,0.95f,1.0f)), + D(GUI_COLOR_OSC_WAVE,"",ImVec4(0.95f,0.95f,1.0f,1.0f)), + D(GUI_COLOR_OSC_WAVE_PEAK,"",ImVec4(0.95f,0.95f,1.0f,1.0f)), + D(GUI_COLOR_OSC_REF,"",ImVec4(0.3f,0.3f,0.3f,1.0f)), + D(GUI_COLOR_OSC_GUIDE,"",ImVec4(0.3,0.3f,0.3f,1.0f)), + D(GUI_COLOR_VOLMETER_LOW,"",ImVec4(0.2f,0.6f,0.2f,1.0f)), D(GUI_COLOR_VOLMETER_HIGH,"",ImVec4(1.0f,0.9f,0.2f,1.0f)), D(GUI_COLOR_VOLMETER_PEAK,"",ImVec4(1.0f,0.1f,0.1f,1.0f)), diff --git a/src/gui/osc.cpp b/src/gui/osc.cpp index a4da29c8..eb9a7b8c 100644 --- a/src/gui/osc.cpp +++ b/src/gui/osc.cpp @@ -18,6 +18,8 @@ */ #include "gui.h" +#include "imgui_internal.h" +#include #include void FurnaceGUI::readOsc() { @@ -71,16 +73,88 @@ void FurnaceGUI::drawOsc() { } if (!oscOpen) return; ImGui::SetNextWindowSizeConstraints(ImVec2(64.0f*dpiScale,32.0f*dpiScale),ImVec2(scrW*dpiScale,scrH*dpiScale)); - ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding,ImVec2(0,0)); + /*ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding,ImVec2(0,0)); ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing,ImVec2(0,0)); - ImGui::PushStyleVar(ImGuiStyleVar_ItemInnerSpacing,ImVec2(0,0)); + ImGui::PushStyleVar(ImGuiStyleVar_ItemInnerSpacing,ImVec2(0,0));*/ if (ImGui::Begin("Oscilloscope",&oscOpen)) { - //ImGui::SetCursorPos(ImVec2(0,0)); - ImGui::BeginDisabled(); - ImGui::PlotLines("##SingleOsc",oscValues,512,0,NULL,-1.0f,1.0f,ImGui::GetContentRegionAvail()); - ImGui::EndDisabled(); + if (oscZoomSlider) { + if (ImGui::VSliderFloat("##OscZoom",ImVec2(20.0f*dpiScale,ImGui::GetContentRegionAvail().y),&oscZoom,0.5,2.0)) { + if (oscZoom<0.5) oscZoom=0.5; + if (oscZoom>2.0) oscZoom=2.0; + } + ImGui::SameLine(); + } + + ImDrawList* dl=ImGui::GetWindowDrawList(); + ImGuiWindow* window=ImGui::GetCurrentWindow(); + + ImVec2 waveform[512]; + ImVec2 size=ImGui::GetContentRegionAvail(); + + ImVec2 minArea=window->DC.CursorPos; + ImVec2 maxArea=ImVec2( + minArea.x+size.x, + minArea.y+size.y + ); + ImRect rect=ImRect(minArea,maxArea); + ImGuiStyle& style=ImGui::GetStyle(); + ImU32 color=ImGui::GetColorU32(isClipping?uiColors[GUI_COLOR_OSC_WAVE_PEAK]:uiColors[GUI_COLOR_OSC_WAVE]); + ImU32 borderColor=ImGui::GetColorU32(uiColors[GUI_COLOR_OSC_BORDER]); + ImGui::ItemSize(size,style.FramePadding.y); + if (ImGui::ItemAdd(rect,ImGui::GetID("wsDisplay"))) { + // https://github.com/ocornut/imgui/issues/3710 + // TODO: improve + const int v0 = dl->VtxBuffer.Size; + dl->AddRectFilled(rect.Min,rect.Max,0xffffffff,8.0f*dpiScale); + const int v1 = dl->VtxBuffer.Size; + + for (int i=v0; iVtxBuffer.Data[i]; + ImVec4 col0=uiColors[GUI_COLOR_OSC_BG1]; + ImVec4 col1=uiColors[GUI_COLOR_OSC_BG3]; + ImVec4 col2=uiColors[GUI_COLOR_OSC_BG2]; + ImVec4 col3=uiColors[GUI_COLOR_OSC_BG4]; + + float shadeX=(v->pos.x-rect.Min.x)/(rect.Max.x-rect.Min.x); + float shadeY=(v->pos.y-rect.Min.y)/(rect.Max.y-rect.Min.y); + if (shadeX<0.0f) shadeX=0.0f; + if (shadeX>1.0f) shadeX=1.0f; + if (shadeY<0.0f) shadeY=0.0f; + if (shadeY>1.0f) shadeY=1.0f; + + col0.x+=(col2.x-col0.x)*shadeX; + col0.y+=(col2.y-col0.y)*shadeX; + col0.z+=(col2.z-col0.z)*shadeX; + col0.w+=(col2.w-col0.w)*shadeX; + + col1.x+=(col3.x-col1.x)*shadeX; + col1.y+=(col3.y-col1.y)*shadeX; + col1.z+=(col3.z-col1.z)*shadeX; + col1.w+=(col3.w-col1.w)*shadeX; + + col0.x+=(col1.x-col0.x)*shadeY; + col0.y+=(col1.y-col0.y)*shadeY; + col0.z+=(col1.z-col0.z)*shadeY; + col0.w+=(col1.w-col0.w)*shadeY; + + v->col=ImGui::ColorConvertFloat4ToU32(col0); + } + + for (size_t i=0; i<512; i++) { + float x=(float)i/512.0f; + float y=oscValues[i]*oscZoom; + if (y<-0.5f) y=-0.5f; + if (y>0.5f) y=0.5f; + waveform[i]=ImLerp(rect.Min,rect.Max,ImVec2(x,0.5f-y)); + } + dl->AddPolyline(waveform,512,color,ImDrawFlags_None,dpiScale); + dl->AddRect(rect.Min,rect.Max,borderColor,8.0f*dpiScale,0,dpiScale); + } + if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) { + oscZoomSlider=!oscZoomSlider; + } } - ImGui::PopStyleVar(3); + //ImGui::PopStyleVar(3); if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_OSCILLOSCOPE; ImGui::End(); -} \ No newline at end of file +} diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index 1cbd6a06..316e3ef5 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -942,6 +942,18 @@ void FurnaceGUI::drawSettings() { UI_COLOR_CONFIG(GUI_COLOR_FILE_OTHER,"Other"); ImGui::TreePop(); } + if (ImGui::TreeNode("Oscilloscope")) { + UI_COLOR_CONFIG(GUI_COLOR_OSC_BORDER,"Border"); + UI_COLOR_CONFIG(GUI_COLOR_OSC_BG1,"Background (top-left)"); + UI_COLOR_CONFIG(GUI_COLOR_OSC_BG2,"Background (top-right)"); + UI_COLOR_CONFIG(GUI_COLOR_OSC_BG3,"Background (bottom-left)"); + UI_COLOR_CONFIG(GUI_COLOR_OSC_BG4,"Background (bottom-right)"); + UI_COLOR_CONFIG(GUI_COLOR_OSC_WAVE,"Waveform"); + UI_COLOR_CONFIG(GUI_COLOR_OSC_WAVE_PEAK,"Waveform (clip)"); + UI_COLOR_CONFIG(GUI_COLOR_OSC_REF,"Reference"); + UI_COLOR_CONFIG(GUI_COLOR_OSC_GUIDE,"Guide"); + ImGui::TreePop(); + } if (ImGui::TreeNode("Volume Meter")) { UI_COLOR_CONFIG(GUI_COLOR_VOLMETER_LOW,"Low"); UI_COLOR_CONFIG(GUI_COLOR_VOLMETER_HIGH,"High"); From d5b07aa34794452543bbced4b56af8d1efc5e573 Mon Sep 17 00:00:00 2001 From: OPNA2608 Date: Sat, 9 Apr 2022 12:48:19 +0200 Subject: [PATCH 31/76] Move icon_enum_callback to separate function --- extern/pfd-fixed/portable-file-dialogs.h | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/extern/pfd-fixed/portable-file-dialogs.h b/extern/pfd-fixed/portable-file-dialogs.h index 3d90a854..fc6df0a1 100644 --- a/extern/pfd-fixed/portable-file-dialogs.h +++ b/extern/pfd-fixed/portable-file-dialogs.h @@ -1331,6 +1331,14 @@ inline std::string internal::file_dialog::select_folder_vista(IFileDialog *ifd, // notify implementation +#if _WIN32 +inline BOOL WINAPI icon_enum_callback(HMODULE hModule, LPCTSTR lpType, LPTSTR lpName, LONG_PTR lParam) +{ + ((NOTIFYICONDATAW *)lParam)->hIcon = ::LoadIcon(GetModuleHandle(nullptr), lpName); + return false; +}; +#endif + inline notify::notify(std::string const &title, std::string const &message, icon _icon /* = icon::info */) @@ -1383,14 +1391,8 @@ inline notify::notify(std::string const &title, /* case icon::info: */ default: nid->dwInfoFlags = NIIF_INFO; break; } - ENUMRESNAMEPROC icon_enum_callback = [](HMODULE, LPCTSTR, LPTSTR lpName, LONG_PTR lParam) WINAPI -> BOOL - { - ((NOTIFYICONDATAW *)lParam)->hIcon = ::LoadIcon(GetModuleHandle(nullptr), lpName); - return false; - }; - nid->hIcon = ::LoadIcon(nullptr, IDI_APPLICATION); - ::EnumResourceNames(nullptr, RT_GROUP_ICON, icon_enum_callback, (LONG_PTR)nid.get()); + ::EnumResourceNames(nullptr, RT_GROUP_ICON, (ENUMRESNAMEPROC)icon_enum_callback, (LONG_PTR)nid.get()); nid->uTimeout = 5000; From ae4968318e978709e77e6ebf5d834f9df492d807 Mon Sep 17 00:00:00 2001 From: OPNA2608 Date: Sat, 9 Apr 2022 14:33:13 +0200 Subject: [PATCH 32/76] Tell SDL headers in MSVC build that we have a libc --- CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index c240e37b..fef510ef 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -177,6 +177,10 @@ else() add_subdirectory(extern/SDL EXCLUDE_FROM_ALL) list(APPEND DEPENDENCIES_INCLUDE_DIRS extern/SDL/include) list(APPEND DEPENDENCIES_LIBRARIES SDL2-static) + # Work around add_subdirectory'd SDL not propagating HAVE_LIBC to MSVC furnace build + if (MSVC) + list(APPEND DEPENDENCIES_COMPILE_OPTIONS "/DHAVE_LIBC") + endif() message(STATUS "Using vendored SDL2") endif() From b6fb3820da16d5ea05204b00dda347025f209f4b Mon Sep 17 00:00:00 2001 From: OPNA2608 Date: Sat, 9 Apr 2022 21:00:38 +0200 Subject: [PATCH 33/76] Remove unneeded includes Some are harmless, some screw with SDL's standard includes due to preceeding `_USE_MATH_DEFINES`. --- src/engine/engine.cpp | 3 --- src/engine/filter.cpp | 3 +-- src/engine/playback.cpp | 3 --- src/gui/pattern.cpp | 2 -- 4 files changed, 1 insertion(+), 10 deletions(-) diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 78ae1ce4..a154277e 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -17,9 +17,6 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#include "dataErrors.h" -#include "song.h" -#include #define _USE_MATH_DEFINES #include "engine.h" #include "instrument.h" diff --git a/src/engine/filter.cpp b/src/engine/filter.cpp index 729c8caa..8e0ac02e 100644 --- a/src/engine/filter.cpp +++ b/src/engine/filter.cpp @@ -17,7 +17,6 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#include #define _USE_MATH_DEFINES #include #include "filter.h" @@ -85,4 +84,4 @@ float* DivFilterTables::getSincIntegralTable() { } } return sincIntegralTable; -} \ No newline at end of file +} diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index 8e1f1d66..409b4a08 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -17,9 +17,6 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#include "blip_buf.h" -#include "song.h" -#include "wavetable.h" #define _USE_MATH_DEFINES #include "dispatch.h" #include "engine.h" diff --git a/src/gui/pattern.cpp b/src/gui/pattern.cpp index d4bf904b..d6b6fce7 100644 --- a/src/gui/pattern.cpp +++ b/src/gui/pattern.cpp @@ -17,8 +17,6 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#include -#include #define _USE_MATH_DEFINES #include "gui.h" #include "../ta-log.h" From 366a7a24a009bca878e768841f713a012c34821b Mon Sep 17 00:00:00 2001 From: OPNA2608 Date: Sat, 9 Apr 2022 21:22:25 +0200 Subject: [PATCH 34/76] Decide amount of build cores on CI based on platform GitHub-hosted macOS runners actually get 3 cores instead of 2, according to https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners#supported-runners-and-hardware-resources --- .github/workflows/build.yml | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 19118f6a..2fbae0f5 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -89,6 +89,19 @@ jobs: echo "::set-output name=id::${package_name}" echo "::set-output name=filename::${package_name}${package_ext}" + - name: Set build cores amount + id: build-cores + run: | + # https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners#supported-runners-and-hardware-resources + set amount=2 + if [ '${{ runner.os }}' == 'macOS' ]; then + amount=3 + fi + + echo "Amount of cores we can build with: ${amount}" + + echo "::set-output name=amount::${amount}" + - name: Setup Toolchain [Windows MSVC] if: ${{ matrix.config.compiler == 'msvc' }} uses: seanmiddleditch/gha-setup-vsdevenv@v3 @@ -156,7 +169,7 @@ jobs: cmake \ --build ${PWD}/build \ --config ${{ env.BUILD_TYPE }} \ - --parallel 2 + --parallel ${{ steps.build-cores.outputs.amount }} - name: Install (System Libraries) if: ${{ runner.os == 'Linux' && matrix.config.compiler != 'mingw' }} @@ -205,7 +218,7 @@ jobs: cmake \ --build ${PWD}/build \ --config ${{ env.BUILD_TYPE }} \ - --parallel 2 + --parallel ${{ steps.build-cores.outputs.amount }} - name: Package [Windows] if: ${{ runner.os == 'Windows' || matrix.config.compiler == 'mingw' }} From 38ca43719015f610488ed55a433ce200ddcf6d8d Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 9 Apr 2022 18:25:25 -0500 Subject: [PATCH 35/76] DC offset improvements --- src/engine/dispatch.h | 12 ++++++++++++ src/engine/dispatchContainer.cpp | 8 ++++++++ src/engine/engine.h | 5 +++-- src/engine/platform/abstract.cpp | 8 ++++++++ src/engine/platform/ay.cpp | 4 ++++ src/engine/platform/ay.h | 1 + src/engine/platform/mmc5.cpp | 5 ++++- src/engine/platform/mmc5.h | 1 + src/engine/platform/nes.cpp | 18 ++++++++++++++++-- src/engine/platform/nes.h | 4 +++- src/engine/platform/saa.cpp | 10 ++++++++++ src/engine/platform/sound/nes/apu.c | 3 ++- src/engine/playback.cpp | 2 ++ src/gui/osc.cpp | 24 +++++++++++++++++++++--- 14 files changed, 95 insertions(+), 10 deletions(-) diff --git a/src/engine/dispatch.h b/src/engine/dispatch.h index b4394f60..5a1c2db6 100644 --- a/src/engine/dispatch.h +++ b/src/engine/dispatch.h @@ -319,6 +319,18 @@ class DivDispatch { */ virtual int getPortaFloor(int ch); + /** + * get the required amplification level of this dispatch's output. + * @return the amplification level. + */ + virtual float getPostAmp(); + + /** + * check whether DC offset correction is required. + * @return truth. + */ + virtual bool getDCOffRequired(); + /** * get a description of a dispatch-specific effect. * @param effect the effect. diff --git a/src/engine/dispatchContainer.cpp b/src/engine/dispatchContainer.cpp index ba72a695..c89a0fa0 100644 --- a/src/engine/dispatchContainer.cpp +++ b/src/engine/dispatchContainer.cpp @@ -79,6 +79,11 @@ void DivDispatchContainer::flush(size_t count) { } void DivDispatchContainer::fillBuf(size_t runtotal, size_t offset, size_t size) { + if (dcOffCompensation && runtotal>0) { + dcOffCompensation=false; + prevSample[0]=bbIn[0][0]; + if (dispatch->isStereo()) prevSample[1]=bbIn[1][0]; + } if (lowQuality) { for (size_t i=0; igetDCOffRequired()) { + dcOffCompensation=true; + } // run for one cycle to determine DC offset // TODO: SAA1099 doesn't like that /*dispatch->acquire(bbIn[0],bbIn[1],0,1); diff --git a/src/engine/engine.h b/src/engine/engine.h index 68ec0ce5..c359da25 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -154,7 +154,7 @@ struct DivDispatchContainer { int temp[2], prevSample[2]; short* bbIn[2]; short* bbOut[2]; - bool lowQuality; + bool lowQuality, dcOffCompensation; void setRates(double gotRate); void setQuality(bool lowQual); @@ -172,7 +172,8 @@ struct DivDispatchContainer { prevSample{0,0}, bbIn{NULL,NULL}, bbOut{NULL,NULL}, - lowQuality(false) {} + lowQuality(false), + dcOffCompensation(false) {} }; class DivEngine { diff --git a/src/engine/platform/abstract.cpp b/src/engine/platform/abstract.cpp index 7b6115ae..b860f680 100644 --- a/src/engine/platform/abstract.cpp +++ b/src/engine/platform/abstract.cpp @@ -74,6 +74,14 @@ int DivDispatch::getPortaFloor(int ch) { return 0x00; } +float DivDispatch::getPostAmp() { + return 1.0f; +} + +bool DivDispatch::getDCOffRequired() { + return false; +} + const char* DivDispatch::getEffectName(unsigned char effect) { return NULL; } diff --git a/src/engine/platform/ay.cpp b/src/engine/platform/ay.cpp index b798cba4..e174e345 100644 --- a/src/engine/platform/ay.cpp +++ b/src/engine/platform/ay.cpp @@ -497,6 +497,10 @@ void DivPlatformAY8910::flushWrites() { while (!writes.empty()) writes.pop(); } +bool DivPlatformAY8910::getDCOffRequired() { + return true; +} + void DivPlatformAY8910::reset() { while (!writes.empty()) writes.pop(); ay->device_reset(); diff --git a/src/engine/platform/ay.h b/src/engine/platform/ay.h index 82b647f2..b1a3ea12 100644 --- a/src/engine/platform/ay.h +++ b/src/engine/platform/ay.h @@ -95,6 +95,7 @@ class DivPlatformAY8910: public DivDispatch { void setFlags(unsigned int flags); bool isStereo(); bool keyOffAffectsArp(int ch); + bool getDCOffRequired(); void notifyInsDeletion(void* ins); void poke(unsigned int addr, unsigned short val); void poke(std::vector& wlist); diff --git a/src/engine/platform/mmc5.cpp b/src/engine/platform/mmc5.cpp index 3ccf9549..102d6a2e 100644 --- a/src/engine/platform/mmc5.cpp +++ b/src/engine/platform/mmc5.cpp @@ -89,7 +89,6 @@ void DivPlatformMMC5::acquire(short* bufL, short* bufR, size_t start, size_t len if (!isMuted[2]) { sample+=mmc5->pcm.output*2; } - sample=(sample-128)<<6; if (sample>32767) sample=32767; if (sample<-32768) sample=-32768; bufL[i]=sample; @@ -336,6 +335,10 @@ int DivPlatformMMC5::getRegisterPoolSize() { return 32; } +float DivPlatformMMC5::getPostAmp() { + return 64.0f; +} + void DivPlatformMMC5::reset() { for (int i=0; i<3; i++) { chan[i]=DivPlatformMMC5::Channel(); diff --git a/src/engine/platform/mmc5.h b/src/engine/platform/mmc5.h index a29ffc7d..6b364d5a 100644 --- a/src/engine/platform/mmc5.h +++ b/src/engine/platform/mmc5.h @@ -74,6 +74,7 @@ class DivPlatformMMC5: public DivDispatch { void tick(); void muteChannel(int ch, bool mute); bool keyOffAffectsArp(int ch); + float getPostAmp(); void setFlags(unsigned int flags); void notifyInsDeletion(void* ins); void poke(unsigned int addr, unsigned short val); diff --git a/src/engine/platform/nes.cpp b/src/engine/platform/nes.cpp index f61ed4fb..9dbf5554 100644 --- a/src/engine/platform/nes.cpp +++ b/src/engine/platform/nes.cpp @@ -80,7 +80,14 @@ void DivPlatformNES::acquire(short* bufL, short* bufR, size_t start, size_t len) DivSample* s=parent->getSample(dacSample); if (s->samples>0) { if (!isMuted[4]) { - rWrite(0x4011,((unsigned char)s->data8[dacPos]+0x80)>>1); + unsigned char next=((unsigned char)s->data8[dacPos]+0x80)>>1; + if (dacAntiClickOn && dacAntiClick=s->samples) { if (s->loopStart>=0 && s->loopStart<(int)s->samples) { @@ -101,7 +108,7 @@ void DivPlatformNES::acquire(short* bufL, short* bufR, size_t start, size_t len) if (nes->apu.clocked) { nes->apu.clocked=false; } - int sample=(pulse_output(nes)+tnd_output(nes)-128)<<7; + int sample=(pulse_output(nes)+tnd_output(nes)); if (sample>32767) sample=32767; if (sample<-32768) sample=-32768; bufL[i]=sample; @@ -454,6 +461,10 @@ int DivPlatformNES::getRegisterPoolSize() { return 32; } +float DivPlatformNES::getPostAmp() { + return 128.0f; +} + void DivPlatformNES::reset() { for (int i=0; i<5; i++) { chan[i]=DivPlatformNES::Channel(); @@ -476,6 +487,9 @@ void DivPlatformNES::reset() { rWrite(0x4015,0x1f); rWrite(0x4001,chan[0].sweep); rWrite(0x4005,chan[1].sweep); + + dacAntiClickOn=true; + dacAntiClick=0; } bool DivPlatformNES::keyOffAffectsArp(int ch) { diff --git a/src/engine/platform/nes.h b/src/engine/platform/nes.h index c1b699bc..1dbb4411 100644 --- a/src/engine/platform/nes.h +++ b/src/engine/platform/nes.h @@ -54,10 +54,11 @@ class DivPlatformNES: public DivDispatch { Channel chan[5]; bool isMuted[5]; int dacPeriod, dacRate; - unsigned int dacPos; + unsigned int dacPos, dacAntiClick; int dacSample; unsigned char sampleBank; unsigned char apuType; + bool dacAntiClickOn; struct NESAPU* nes; unsigned char regPool[128]; @@ -74,6 +75,7 @@ class DivPlatformNES: public DivDispatch { void tick(); void muteChannel(int ch, bool mute); bool keyOffAffectsArp(int ch); + float getPostAmp(); void setFlags(unsigned int flags); void notifyInsDeletion(void* ins); void poke(unsigned int addr, unsigned short val); diff --git a/src/engine/platform/saa.cpp b/src/engine/platform/saa.cpp index 0bafaf15..49adf5b1 100644 --- a/src/engine/platform/saa.cpp +++ b/src/engine/platform/saa.cpp @@ -414,6 +414,16 @@ void DivPlatformSAA1099::reset() { extMode=false; + rWrite(8,255); + rWrite(9,255); + rWrite(10,255); + rWrite(11,255); + rWrite(12,255); + rWrite(13,255); + rWrite(16,0x77); + rWrite(17,0x77); + rWrite(18,0x77); + rWrite(0x1c,2); rWrite(0x1c,1); } diff --git a/src/engine/platform/sound/nes/apu.c b/src/engine/platform/sound/nes/apu.c index 8d53e583..9e177a78 100644 --- a/src/engine/platform/sound/nes/apu.c +++ b/src/engine/platform/sound/nes/apu.c @@ -213,7 +213,8 @@ void apu_turn_on(struct NESAPU* a, BYTE apu_type) { a->S2.sweep.delay = 1; a->S2.sweep.divider = 1; a->TR.frequency = 1; - a->TR.sequencer = 0; + /* questo era 0 ma produce click nell'audio */ + a->TR.sequencer = 7; a->NS.frequency = 1; a->NS.shift = 1; a->DMC.frequency = 1; diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index 4a5cc646..0118acc4 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -1863,6 +1863,8 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi for (int i=0; igetPostAmp(); + volR*=disCont[i].dispatch->getPostAmp(); if (disCont[i].dispatch->isStereo()) { for (size_t j=0; jVtxBuffer.Size; - dl->AddRectFilled(rect.Min,rect.Max,0xffffffff,8.0f*dpiScale); + dl->AddRectFilled(inRect.Min,inRect.Max,0xffffffff,8.0f*dpiScale); const int v1 = dl->VtxBuffer.Size; for (int i=v0; icol); + col0.x*=conv.x; + col0.y*=conv.y; + col0.z*=conv.z; + col0.w*=conv.w; + v->col=ImGui::ColorConvertFloat4ToU32(col0); } + dl->AddLine( + ImLerp(rect.Min,rect.Max,ImVec2(0.0f,0.5f)), + ImLerp(rect.Min,rect.Max,ImVec2(0.0f,0.5f)), + refColor, + dpiScale + ); + for (size_t i=0; i<512; i++) { float x=(float)i/512.0f; float y=oscValues[i]*oscZoom; @@ -148,7 +166,7 @@ void FurnaceGUI::drawOsc() { waveform[i]=ImLerp(rect.Min,rect.Max,ImVec2(x,0.5f-y)); } dl->AddPolyline(waveform,512,color,ImDrawFlags_None,dpiScale); - dl->AddRect(rect.Min,rect.Max,borderColor,8.0f*dpiScale,0,dpiScale); + dl->AddRect(rect.Min,rect.Max,borderColor,8.0f*dpiScale,0,2.0f*dpiScale); } if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) { oscZoomSlider=!oscZoomSlider; From 0eb02422d5161767e9983bdaa5c429762d3477ce Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 9 Apr 2022 18:25:38 -0500 Subject: [PATCH 36/76] fix possible pattern crash issue #325 --- src/gui/pattern.cpp | 44 +++++++++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/src/gui/pattern.cpp b/src/gui/pattern.cpp index d6b6fce7..d56196d6 100644 --- a/src/gui/pattern.cpp +++ b/src/gui/pattern.cpp @@ -282,27 +282,33 @@ inline void FurnaceGUI::patternRow(int i, bool isPlaying, float lineHeight, int sprintf(id,"..##PE%d_%d_%d",k,i,j); ImGui::PushStyleColor(ImGuiCol_Text,inactiveColor); } else { - sprintf(id,"%.2X##PE%d_%d_%d",pat->data[i][index],k,i,j); - if (pat->data[i][index]<0x10) { - ImGui::PushStyleColor(ImGuiCol_Text,uiColors[fxColors[pat->data[i][index]]]); - } else if (pat->data[i][index]<0x20) { - ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY]); - } else if (pat->data[i][index]<0x30) { - ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_SYS_SECONDARY]); - } else if (pat->data[i][index]<0x48) { - ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY]); - } else if (pat->data[i][index]<0x90) { - ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_INVALID]); - } else if (pat->data[i][index]<0xa0) { - ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_MISC]); - } else if (pat->data[i][index]<0xc0) { - ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_INVALID]); - } else if (pat->data[i][index]<0xd0) { - ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_SPEED]); - } else if (pat->data[i][index]<0xe0) { + if (pat->data[i][index]>0xff) { + sprintf(id,"??##PE%d_%d_%d",k,i,j); ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_INVALID]); } else { - ImGui::PushStyleColor(ImGuiCol_Text,uiColors[extFxColors[pat->data[i][index]-0xe0]]); + const unsigned char data=pat->data[i][index]; + sprintf(id,"%.2X##PE%d_%d_%d",data,k,i,j); + if (data<0x10) { + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[fxColors[data]]); + } else if (data<0x20) { + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY]); + } else if (data<0x30) { + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_SYS_SECONDARY]); + } else if (data<0x48) { + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY]); + } else if (data<0x90) { + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_INVALID]); + } else if (data<0xa0) { + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_MISC]); + } else if (data<0xc0) { + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_INVALID]); + } else if (data<0xd0) { + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_SPEED]); + } else if (data<0xe0) { + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_INVALID]); + } else { + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[extFxColors[data-0xe0]]); + } } } ImGui::SameLine(0.0f,0.0f); From d3e5efe834fb1d88d66684a93eb41d4c1f3ad195 Mon Sep 17 00:00:00 2001 From: cam900 Date: Sun, 10 Apr 2022 14:01:55 +0900 Subject: [PATCH 37/76] Prepare for macro refactoring --- src/engine/engine.h | 2 +- src/engine/fileOps.cpp | 134 ++-- src/engine/fileOpsIns.cpp | 78 +- src/engine/instrument.cpp | 1197 +++++++++++++++++------------ src/engine/instrument.h | 363 +++------ src/engine/macroInt.cpp | 563 ++++++-------- src/engine/macroInt.h | 357 +++------ src/engine/platform/amiga.cpp | 26 +- src/engine/platform/arcade.cpp | 100 +-- src/engine/platform/ay.cpp | 40 +- src/engine/platform/ay8930.cpp | 54 +- src/engine/platform/bubsyswsg.cpp | 26 +- src/engine/platform/c64.cpp | 50 +- src/engine/platform/fds.cpp | 48 +- src/engine/platform/gb.cpp | 30 +- src/engine/platform/genesis.cpp | 78 +- src/engine/platform/lynx.cpp | 32 +- src/engine/platform/mmc5.cpp | 22 +- src/engine/platform/n163.cpp | 74 +- src/engine/platform/nes.cpp | 28 +- src/engine/platform/opl.cpp | 78 +- src/engine/platform/opll.cpp | 82 +- src/engine/platform/pce.cpp | 34 +- src/engine/platform/pcspkr.cpp | 18 +- src/engine/platform/pet.cpp | 26 +- src/engine/platform/qsound.cpp | 22 +- src/engine/platform/saa.cpp | 28 +- src/engine/platform/segapcm.cpp | 16 +- src/engine/platform/sms.cpp | 38 +- src/engine/platform/swan.cpp | 32 +- src/engine/platform/tia.cpp | 22 +- src/engine/platform/tx81z.cpp | 100 +-- src/engine/platform/vera.cpp | 38 +- src/engine/platform/vic20.cpp | 24 +- src/engine/platform/vrc6.cpp | 24 +- src/engine/platform/x1_010.cpp | 60 +- src/engine/platform/ym2610.cpp | 94 +-- src/engine/platform/ym2610b.cpp | 94 +-- src/engine/safeReader.cpp | 36 + src/engine/safeReader.h | 6 + src/engine/safeWriter.cpp | 33 + src/engine/safeWriter.h | 1 + src/gui/insEdit.cpp | 438 ++++++----- 43 files changed, 2337 insertions(+), 2309 deletions(-) diff --git a/src/engine/engine.h b/src/engine/engine.h index 89005675..bf9fe07e 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -43,7 +43,7 @@ #define BUSY_END isBusy.unlock(); softLocked=false; #define DIV_VERSION "dev80" -#define DIV_ENGINE_VERSION 80 +#define DIV_ENGINE_VERSION (80/*Test*/|0x80) // for imports #define DIV_VERSION_MOD 0xff01 diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index 37964c68..63cc1536 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -307,12 +307,12 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { if (!ins->mode) { ins->type=DIV_INS_AY; } - ins->std.dutyMacroHeight=31; - ins->std.waveMacroHeight=7; + ins->std.dutyMacro.height=31; + ins->std.waveMacro.height=7; } if (ds.system[0]==DIV_SYSTEM_PCE) { ins->type=DIV_INS_PCE; - ins->std.volMacroHeight=31; + ins->std.volMacro.height=31; } if ((ds.system[0]==DIV_SYSTEM_SMS_OPLL || ds.system[0]==DIV_SYSTEM_NES_VRC7) && ins->type==DIV_INS_FM) { ins->type=DIV_INS_OPLL; @@ -425,76 +425,76 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { } } else { // STD if (ds.system[0]!=DIV_SYSTEM_GB || ds.version<0x12) { - ins->std.volMacroLen=reader.readC(); - for (int j=0; jstd.volMacroLen; j++) { + ins->std.volMacro.len=reader.readC(); + for (int j=0; jstd.volMacro.len; j++) { if (ds.version<0x0e) { - ins->std.volMacro[j]=reader.readC(); + ins->std.volMacro.val[j]=reader.readC(); } else { - ins->std.volMacro[j]=reader.readI(); + ins->std.volMacro.val[j]=reader.readI(); } } - if (ins->std.volMacroLen>0) { - ins->std.volMacroOpen=true; - ins->std.volMacroLoop=reader.readC(); + if (ins->std.volMacro.len>0) { + ins->std.volMacro.open=true; + ins->std.volMacro.loop=reader.readC(); } else { - ins->std.volMacroOpen=false; + ins->std.volMacro.open=false; } } - ins->std.arpMacroLen=reader.readC(); - for (int j=0; jstd.arpMacroLen; j++) { + ins->std.arpMacro.len=reader.readC(); + for (int j=0; jstd.arpMacro.len; j++) { if (ds.version<0x0e) { - ins->std.arpMacro[j]=reader.readC(); + ins->std.arpMacro.val[j]=reader.readC(); } else { - ins->std.arpMacro[j]=reader.readI(); + ins->std.arpMacro.val[j]=reader.readI(); } } - if (ins->std.arpMacroLen>0) { - ins->std.arpMacroLoop=reader.readC(); - ins->std.arpMacroOpen=true; + if (ins->std.arpMacro.len>0) { + ins->std.arpMacro.loop=reader.readC(); + ins->std.arpMacro.open=true; } else { - ins->std.arpMacroOpen=false; + ins->std.arpMacro.open=false; } if (ds.version>0x0f) { - ins->std.arpMacroMode=reader.readC(); + ins->std.arpMacro.mode=reader.readC(); } - if (!ins->std.arpMacroMode) { - for (int j=0; jstd.arpMacroLen; j++) { - ins->std.arpMacro[j]-=12; + if (!ins->std.arpMacro.mode) { + for (int j=0; jstd.arpMacro.len; j++) { + ins->std.arpMacro.val[j]-=12; } } - ins->std.dutyMacroLen=reader.readC(); - for (int j=0; jstd.dutyMacroLen; j++) { + ins->std.dutyMacro.len=reader.readC(); + for (int j=0; jstd.dutyMacro.len; j++) { if (ds.version<0x0e) { - ins->std.dutyMacro[j]=reader.readC(); + ins->std.dutyMacro.val[j]=reader.readC(); } else { - ins->std.dutyMacro[j]=reader.readI(); + ins->std.dutyMacro.val[j]=reader.readI(); } - if ((ds.system[0]==DIV_SYSTEM_C64_8580 || ds.system[0]==DIV_SYSTEM_C64_6581) && ins->std.dutyMacro[j]>24) { - ins->std.dutyMacro[j]=24; + if ((ds.system[0]==DIV_SYSTEM_C64_8580 || ds.system[0]==DIV_SYSTEM_C64_6581) && ins->std.dutyMacro.val[j]>24) { + ins->std.dutyMacro.val[j]=24; } } - if (ins->std.dutyMacroLen>0) { - ins->std.dutyMacroOpen=true; - ins->std.dutyMacroLoop=reader.readC(); + if (ins->std.dutyMacro.len>0) { + ins->std.dutyMacro.open=true; + ins->std.dutyMacro.loop=reader.readC(); } else { - ins->std.dutyMacroOpen=false; + ins->std.dutyMacro.open=false; } - ins->std.waveMacroLen=reader.readC(); - for (int j=0; jstd.waveMacroLen; j++) { + ins->std.waveMacro.len=reader.readC(); + for (int j=0; jstd.waveMacro.len; j++) { if (ds.version<0x0e) { - ins->std.waveMacro[j]=reader.readC(); + ins->std.waveMacro.val[j]=reader.readC(); } else { - ins->std.waveMacro[j]=reader.readI(); + ins->std.waveMacro.val[j]=reader.readI(); } } - if (ins->std.waveMacroLen>0) { - ins->std.waveMacroOpen=true; - ins->std.waveMacroLoop=reader.readC(); + if (ins->std.waveMacro.len>0) { + ins->std.waveMacro.open=true; + ins->std.waveMacro.loop=reader.readC(); } else { - ins->std.waveMacroOpen=false; + ins->std.waveMacro.open=false; } if (ds.system[0]==DIV_SYSTEM_C64_6581 || ds.system[0]==DIV_SYSTEM_C64_8580) { @@ -533,18 +533,18 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { ins->gb.envDir=reader.readC(); ins->gb.envLen=reader.readC(); ins->gb.soundLen=reader.readC(); - ins->std.volMacroOpen=false; + ins->std.volMacro.open=false; logD("GB data: vol %d dir %d len %d sl %d\n",ins->gb.envVol,ins->gb.envDir,ins->gb.envLen,ins->gb.soundLen); } else if (ds.system[0]==DIV_SYSTEM_GB) { // try to convert macro to envelope - if (ins->std.volMacroLen>0) { - ins->gb.envVol=ins->std.volMacro[0]; - if (ins->std.volMacro[0]std.volMacro[1]) { + if (ins->std.volMacro.len>0) { + ins->gb.envVol=ins->std.volMacro.val[0]; + if (ins->std.volMacro.val[0]std.volMacro.val[1]) { ins->gb.envDir=true; } - if (ins->std.volMacro[ins->std.volMacroLen-1]==0) { - ins->gb.soundLen=ins->std.volMacroLen*2; + if (ins->std.volMacro.val[ins->std.volMacro.len-1]==0) { + ins->gb.soundLen=ins->std.volMacro.len*2; } } addWarning("Game Boy volume macros converted to envelopes. may not be perfect!"); @@ -2446,36 +2446,36 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) { } } else { // STD if (sys!=DIV_SYSTEM_GB) { - w->writeC(i->std.volMacroLen); - w->write(i->std.volMacro,4*i->std.volMacroLen); - if (i->std.volMacroLen>0) { - w->writeC(i->std.volMacroLoop); + w->writeC(i->std.volMacro.len); + w->write(i->std.volMacro.val,4*i->std.volMacro.len); + if (i->std.volMacro.len>0) { + w->writeC(i->std.volMacro.loop); } } - w->writeC(i->std.arpMacroLen); - if (i->std.arpMacroMode) { - w->write(i->std.arpMacro,4*i->std.arpMacroLen); + w->writeC(i->std.arpMacro.len); + if (i->std.arpMacro.mode) { + w->write(i->std.arpMacro.val,4*i->std.arpMacro.len); } else { - for (int j=0; jstd.arpMacroLen; j++) { - w->writeI(i->std.arpMacro[j]+12); + for (int j=0; jstd.arpMacro.len; j++) { + w->writeI(i->std.arpMacro.val[j]+12); } } - if (i->std.arpMacroLen>0) { - w->writeC(i->std.arpMacroLoop); + if (i->std.arpMacro.len>0) { + w->writeC(i->std.arpMacro.loop); } - w->writeC(i->std.arpMacroMode); + w->writeC(i->std.arpMacro.mode); - w->writeC(i->std.dutyMacroLen); - w->write(i->std.dutyMacro,4*i->std.dutyMacroLen); - if (i->std.dutyMacroLen>0) { - w->writeC(i->std.dutyMacroLoop); + w->writeC(i->std.dutyMacro.len); + w->write(i->std.dutyMacro.val,4*i->std.dutyMacro.len); + if (i->std.dutyMacro.len>0) { + w->writeC(i->std.dutyMacro.loop); } - w->writeC(i->std.waveMacroLen); - w->write(i->std.waveMacro,4*i->std.waveMacroLen); - if (i->std.waveMacroLen>0) { - w->writeC(i->std.waveMacroLoop); + w->writeC(i->std.waveMacro.len); + w->write(i->std.waveMacro.val,4*i->std.waveMacro.len); + if (i->std.waveMacro.len>0) { + w->writeC(i->std.waveMacro.loop); } if (sys==DIV_SYSTEM_C64_6581 || sys==DIV_SYSTEM_C64_8580) { diff --git a/src/engine/fileOpsIns.cpp b/src/engine/fileOpsIns.cpp index 6689c554..6658eea9 100644 --- a/src/engine/fileOpsIns.cpp +++ b/src/engine/fileOpsIns.cpp @@ -181,79 +181,79 @@ void DivEngine::loadDMP(SafeReader& reader, std::vector& ret, St } else { // STD logD("reading STD data...\n"); if (ins->type!=DIV_INS_GB) { - ins->std.volMacroLen=reader.readC(); + ins->std.volMacro.len=reader.readC(); if (version>5) { - for (int i=0; istd.volMacroLen; i++) { - ins->std.volMacro[i]=reader.readI(); + for (int i=0; istd.volMacro.len; i++) { + ins->std.volMacro.val[i]=reader.readI(); } } else { - for (int i=0; istd.volMacroLen; i++) { - ins->std.volMacro[i]=reader.readC(); + for (int i=0; istd.volMacro.len; i++) { + ins->std.volMacro.val[i]=reader.readC(); } } - if (version<11) for (int i=0; istd.volMacroLen; i++) { - if (ins->std.volMacro[i]>15 && ins->type==DIV_INS_STD) ins->type=DIV_INS_PCE; + if (version<11) for (int i=0; istd.volMacro.len; i++) { + if (ins->std.volMacro.val[i]>15 && ins->type==DIV_INS_STD) ins->type=DIV_INS_PCE; } - if (ins->std.volMacroLen>0) { - ins->std.volMacroOpen=true; - ins->std.volMacroLoop=reader.readC(); + if (ins->std.volMacro.len>0) { + ins->std.volMacro.open=true; + ins->std.volMacro.loop=reader.readC(); } else { - ins->std.volMacroOpen=false; + ins->std.volMacro.open=false; } } - ins->std.arpMacroLen=reader.readC(); + ins->std.arpMacro.len=reader.readC(); if (version>5) { - for (int i=0; istd.arpMacroLen; i++) { - ins->std.arpMacro[i]=reader.readI(); + for (int i=0; istd.arpMacro.len; i++) { + ins->std.arpMacro.val[i]=reader.readI(); } } else { - for (int i=0; istd.arpMacroLen; i++) { - ins->std.arpMacro[i]=reader.readC(); + for (int i=0; istd.arpMacro.len; i++) { + ins->std.arpMacro.val[i]=reader.readC(); } } - if (ins->std.arpMacroLen>0) { - ins->std.arpMacroOpen=true; - ins->std.arpMacroLoop=reader.readC(); + if (ins->std.arpMacro.len>0) { + ins->std.arpMacro.open=true; + ins->std.arpMacro.loop=reader.readC(); } else { - ins->std.arpMacroOpen=false; + ins->std.arpMacro.open=false; } if (version>8) { // TODO: when? - ins->std.arpMacroMode=reader.readC(); + ins->std.arpMacro.mode=reader.readC(); } - ins->std.dutyMacroLen=reader.readC(); + ins->std.dutyMacro.len=reader.readC(); if (version>5) { - for (int i=0; istd.dutyMacroLen; i++) { - ins->std.dutyMacro[i]=reader.readI(); + for (int i=0; istd.dutyMacro.len; i++) { + ins->std.dutyMacro.val[i]=reader.readI(); } } else { - for (int i=0; istd.dutyMacroLen; i++) { - ins->std.dutyMacro[i]=reader.readC(); + for (int i=0; istd.dutyMacro.len; i++) { + ins->std.dutyMacro.val[i]=reader.readC(); } } - if (ins->std.dutyMacroLen>0) { - ins->std.dutyMacroOpen=true; - ins->std.dutyMacroLoop=reader.readC(); + if (ins->std.dutyMacro.len>0) { + ins->std.dutyMacro.open=true; + ins->std.dutyMacro.loop=reader.readC(); } else { - ins->std.dutyMacroOpen=false; + ins->std.dutyMacro.open=false; } - ins->std.waveMacroLen=reader.readC(); + ins->std.waveMacro.len=reader.readC(); if (version>5) { - for (int i=0; istd.waveMacroLen; i++) { - ins->std.waveMacro[i]=reader.readI(); + for (int i=0; istd.waveMacro.len; i++) { + ins->std.waveMacro.val[i]=reader.readI(); } } else { - for (int i=0; istd.waveMacroLen; i++) { - ins->std.waveMacro[i]=reader.readC(); + for (int i=0; istd.waveMacro.len; i++) { + ins->std.waveMacro.val[i]=reader.readC(); } } - if (ins->std.waveMacroLen>0) { - ins->std.waveMacroOpen=true; - ins->std.waveMacroLoop=reader.readC(); + if (ins->std.waveMacro.len>0) { + ins->std.waveMacro.open=true; + ins->std.waveMacro.loop=reader.readC(); } else { - ins->std.waveMacroOpen=false; + ins->std.waveMacro.open=false; } if (ins->type==DIV_INS_C64) { diff --git a/src/engine/instrument.cpp b/src/engine/instrument.cpp index 60ce6810..9369df9d 100644 --- a/src/engine/instrument.cpp +++ b/src/engine/instrument.cpp @@ -23,13 +23,37 @@ #include "../ta-log.h" #include "../fileutils.h" +void DivInstrument::putMacroData(DivInstrumentMacro m, SafeWriter* w) { + w->write("MACR",4); + w->writeI(0); + + w->writeS(DIV_ENGINE_VERSION); + + w->writeS(type); + w->writeC(0); + + w->writeString(m.name,false); + + w->writeI(m.len); + w->writeI(m.loop); + w->writeI(m.rel); + w->writeI(m.mode); + w->writeC(m.open); + for (int v=0; vwriteI(m.val[v]); + w->writeI(0); // reserved + w->writeI(0); // reserved + } +} + void DivInstrument::putInsData(SafeWriter* w) { w->write("INST",4); w->writeI(0); w->writeS(DIV_ENGINE_VERSION); - w->writeC(type); + w->writeS(type); + //w->writeC(type); w->writeC(0); w->writeString(name,false); @@ -101,7 +125,7 @@ void DivInstrument::putInsData(SafeWriter* w) { w->writeC(c64.hp); w->writeC(c64.ch3off); w->writeS(c64.cut); - w->writeC(c64.dutyIsAbs); + //w->writeC(std.dutyMacro.mode); w->writeC(c64.filterIsAbs); // Amiga @@ -111,266 +135,326 @@ void DivInstrument::putInsData(SafeWriter* w) { } // standard - w->writeI(std.volMacroLen); - w->writeI(std.arpMacroLen); - w->writeI(std.dutyMacroLen); - w->writeI(std.waveMacroLen); - w->writeI(std.pitchMacroLen); - w->writeI(std.ex1MacroLen); - w->writeI(std.ex2MacroLen); - w->writeI(std.ex3MacroLen); - w->writeI(std.volMacroLoop); - w->writeI(std.arpMacroLoop); - w->writeI(std.dutyMacroLoop); - w->writeI(std.waveMacroLoop); - w->writeI(std.pitchMacroLoop); - w->writeI(std.ex1MacroLoop); - w->writeI(std.ex2MacroLoop); - w->writeI(std.ex3MacroLoop); - w->writeC(std.arpMacroMode); + putMacroData(std.volMacro,w); + putMacroData(std.arpMacro,w); + putMacroData(std.dutyMacro,w); + putMacroData(std.waveMacro,w); + putMacroData(std.pitchMacro,w); + putMacroData(std.ex1Macro,w); + putMacroData(std.ex2Macro,w); + putMacroData(std.ex3Macro,w); + putMacroData(std.algMacro,w); + putMacroData(std.fbMacro,w); + putMacroData(std.fmsMacro,w); + putMacroData(std.fms2Macro,w); + putMacroData(std.amsMacro,w); + putMacroData(std.ams2Macro,w); + putMacroData(std.panLMacro,w); + putMacroData(std.panRMacro,w); + putMacroData(std.phaseResetMacro,w); + putMacroData(std.ex4Macro,w); + putMacroData(std.ex5Macro,w); + putMacroData(std.ex6Macro,w); + putMacroData(std.ex7Macro,w); + putMacroData(std.ex8Macro,w); + // FM macros + for (int i=0; i<4; i++) { + DivInstrumentSTD::OpMacro& op=std.opMacros[i]; + putMacroData(op.amMacro,w); + putMacroData(op.arMacro,w); + putMacroData(op.drMacro,w); + putMacroData(op.multMacro,w); + putMacroData(op.rrMacro,w); + putMacroData(op.slMacro,w); + putMacroData(op.tlMacro,w); + putMacroData(op.dt2Macro,w); + putMacroData(op.rsMacro,w); + putMacroData(op.dtMacro,w); + putMacroData(op.d2rMacro,w); + putMacroData(op.ssgMacro,w); + putMacroData(op.damMacro,w); + putMacroData(op.dvbMacro,w); + putMacroData(op.egtMacro,w); + putMacroData(op.kslMacro,w); + putMacroData(op.susMacro,w); + putMacroData(op.vibMacro,w); + putMacroData(op.wsMacro,w); + putMacroData(op.ksrMacro,w); + } + // wavesynth macros + putMacroData(std.ws.wave1Macro,w); + putMacroData(std.ws.wave2Macro,w); + putMacroData(std.ws.rateDividerMacro,w); + putMacroData(std.ws.effectMacro,w); + putMacroData(std.ws.oneShotMacro,w); + putMacroData(std.ws.enabledMacro,w); + putMacroData(std.ws.globalMacro,w); + putMacroData(std.ws.speedMacro,w); + putMacroData(std.ws.param1Macro,w); + putMacroData(std.ws.param2Macro,w); + putMacroData(std.ws.param3Macro,w); + putMacroData(std.ws.param4Macro,w); + /* + w->writeI(std.volMacro.len); + w->writeI(std.arpMacro.len); + w->writeI(std.dutyMacro.len); + w->writeI(std.waveMacro.len); + w->writeI(std.pitchMacro.len); + w->writeI(std.ex1Macro.len); + w->writeI(std.ex2Macro.len); + w->writeI(std.ex3Macro.len); + w->writeI(std.volMacro.loop); + w->writeI(std.arpMacro.loop); + w->writeI(std.dutyMacro.loop); + w->writeI(std.waveMacro.loop); + w->writeI(std.pitchMacro.loop); + w->writeI(std.ex1Macro.loop); + w->writeI(std.ex2Macro.loop); + w->writeI(std.ex3Macro.loop); + w->writeC(std.arpMacro.mode); w->writeC(0); // reserved w->writeC(0); w->writeC(0); - for (int j=0; jwriteI(std.volMacro[j]); + for (int j=0; jwriteI(std.volMacro.val[j]); } - for (int j=0; jwriteI(std.arpMacro[j]); + for (int j=0; jwriteI(std.arpMacro.val[j]); } - for (int j=0; jwriteI(std.dutyMacro[j]); + for (int j=0; jwriteI(std.dutyMacro.val[j]); } - for (int j=0; jwriteI(std.waveMacro[j]); + for (int j=0; jwriteI(std.waveMacro.val[j]); } - for (int j=0; jwriteI(std.pitchMacro[j]); + for (int j=0; jwriteI(std.pitchMacro.val[j]); } - for (int j=0; jwriteI(std.ex1Macro[j]); + for (int j=0; jwriteI(std.ex1Macro.val[j]); } - for (int j=0; jwriteI(std.ex2Macro[j]); + for (int j=0; jwriteI(std.ex2Macro.val[j]); } - for (int j=0; jwriteI(std.ex3Macro[j]); + for (int j=0; jwriteI(std.ex3Macro.val[j]); } // FM macros and open status - w->writeI(std.algMacroLen); - w->writeI(std.fbMacroLen); - w->writeI(std.fmsMacroLen); - w->writeI(std.amsMacroLen); - w->writeI(std.algMacroLoop); - w->writeI(std.fbMacroLoop); - w->writeI(std.fmsMacroLoop); - w->writeI(std.amsMacroLoop); + w->writeI(std.algMacro.len); + w->writeI(std.fbMacro.len); + w->writeI(std.fmsMacro.len); + w->writeI(std.amsMacro.len); + w->writeI(std.algMacro.loop); + w->writeI(std.fbMacro.loop); + w->writeI(std.fmsMacro.loop); + w->writeI(std.amsMacro.loop); - w->writeC(std.volMacroOpen); - w->writeC(std.arpMacroOpen); - w->writeC(std.dutyMacroOpen); - w->writeC(std.waveMacroOpen); - w->writeC(std.pitchMacroOpen); - w->writeC(std.ex1MacroOpen); - w->writeC(std.ex2MacroOpen); - w->writeC(std.ex3MacroOpen); - w->writeC(std.algMacroOpen); - w->writeC(std.fbMacroOpen); - w->writeC(std.fmsMacroOpen); - w->writeC(std.amsMacroOpen); + w->writeC(std.volMacro.open); + w->writeC(std.arpMacro.open); + w->writeC(std.dutyMacro.open); + w->writeC(std.waveMacro.open); + w->writeC(std.pitchMacro.open); + w->writeC(std.ex1Macro.open); + w->writeC(std.ex2Macro.open); + w->writeC(std.ex3Macro.open); + w->writeC(std.algMacro.open); + w->writeC(std.fbMacro.open); + w->writeC(std.fmsMacro.open); + w->writeC(std.amsMacro.open); - for (int j=0; jwriteI(std.algMacro[j]); + for (int j=0; jwriteI(std.algMacro.val[j]); } - for (int j=0; jwriteI(std.fbMacro[j]); + for (int j=0; jwriteI(std.fbMacro.val[j]); } - for (int j=0; jwriteI(std.fmsMacro[j]); + for (int j=0; jwriteI(std.fmsMacro.val[j]); } - for (int j=0; jwriteI(std.amsMacro[j]); + for (int j=0; jwriteI(std.amsMacro.val[j]); } for (int i=0; i<4; i++) { DivInstrumentSTD::OpMacro& op=std.opMacros[i]; - w->writeI(op.amMacroLen); - w->writeI(op.arMacroLen); - w->writeI(op.drMacroLen); - w->writeI(op.multMacroLen); - w->writeI(op.rrMacroLen); - w->writeI(op.slMacroLen); - w->writeI(op.tlMacroLen); - w->writeI(op.dt2MacroLen); - w->writeI(op.rsMacroLen); - w->writeI(op.dtMacroLen); - w->writeI(op.d2rMacroLen); - w->writeI(op.ssgMacroLen); - w->writeI(op.amMacroLoop); - w->writeI(op.arMacroLoop); - w->writeI(op.drMacroLoop); - w->writeI(op.multMacroLoop); - w->writeI(op.rrMacroLoop); - w->writeI(op.slMacroLoop); - w->writeI(op.tlMacroLoop); - w->writeI(op.dt2MacroLoop); - w->writeI(op.rsMacroLoop); - w->writeI(op.dtMacroLoop); - w->writeI(op.d2rMacroLoop); - w->writeI(op.ssgMacroLoop); - w->writeC(op.amMacroOpen); - w->writeC(op.arMacroOpen); - w->writeC(op.drMacroOpen); - w->writeC(op.multMacroOpen); - w->writeC(op.rrMacroOpen); - w->writeC(op.slMacroOpen); - w->writeC(op.tlMacroOpen); - w->writeC(op.dt2MacroOpen); - w->writeC(op.rsMacroOpen); - w->writeC(op.dtMacroOpen); - w->writeC(op.d2rMacroOpen); - w->writeC(op.ssgMacroOpen); + w->writeI(op.amMacro.len); + w->writeI(op.arMacro.len); + w->writeI(op.drMacro.len); + w->writeI(op.multMacro.len); + w->writeI(op.rrMacro.len); + w->writeI(op.slMacro.len); + w->writeI(op.tlMacro.len); + w->writeI(op.dt2Macro.len); + w->writeI(op.rsMacro.len); + w->writeI(op.dtMacro.len); + w->writeI(op.d2rMacro.len); + w->writeI(op.ssgMacro.len); + w->writeI(op.amMacro.loop); + w->writeI(op.arMacro.loop); + w->writeI(op.drMacro.loop); + w->writeI(op.multMacro.loop); + w->writeI(op.rrMacro.loop); + w->writeI(op.slMacro.loop); + w->writeI(op.tlMacro.loop); + w->writeI(op.dt2Macro.loop); + w->writeI(op.rsMacro.loop); + w->writeI(op.dtMacro.loop); + w->writeI(op.d2rMacro.loop); + w->writeI(op.ssgMacro.loop); + w->writeC(op.amMacro.open); + w->writeC(op.arMacro.open); + w->writeC(op.drMacro.open); + w->writeC(op.multMacro.open); + w->writeC(op.rrMacro.open); + w->writeC(op.slMacro.open); + w->writeC(op.tlMacro.open); + w->writeC(op.dt2Macro.open); + w->writeC(op.rsMacro.open); + w->writeC(op.dtMacro.open); + w->writeC(op.d2rMacro.open); + w->writeC(op.ssgMacro.open); } for (int i=0; i<4; i++) { DivInstrumentSTD::OpMacro& op=std.opMacros[i]; - for (int j=0; jwriteC(op.amMacro[j]); + for (int j=0; jwriteC(op.amMacro.val[j]); } - for (int j=0; jwriteC(op.arMacro[j]); + for (int j=0; jwriteC(op.arMacro.val[j]); } - for (int j=0; jwriteC(op.drMacro[j]); + for (int j=0; jwriteC(op.drMacro.val[j]); } - for (int j=0; jwriteC(op.multMacro[j]); + for (int j=0; jwriteC(op.multMacro.val[j]); } - for (int j=0; jwriteC(op.rrMacro[j]); + for (int j=0; jwriteC(op.rrMacro.val[j]); } - for (int j=0; jwriteC(op.slMacro[j]); + for (int j=0; jwriteC(op.slMacro.val[j]); } - for (int j=0; jwriteC(op.tlMacro[j]); + for (int j=0; jwriteC(op.tlMacro.val[j]); } - for (int j=0; jwriteC(op.dt2Macro[j]); + for (int j=0; jwriteC(op.dt2Macro.val[j]); } - for (int j=0; jwriteC(op.rsMacro[j]); + for (int j=0; jwriteC(op.rsMacro.val[j]); } - for (int j=0; jwriteC(op.dtMacro[j]); + for (int j=0; jwriteC(op.dtMacro.val[j]); } - for (int j=0; jwriteC(op.d2rMacro[j]); + for (int j=0; jwriteC(op.d2rMacro.val[j]); } - for (int j=0; jwriteC(op.ssgMacro[j]); + for (int j=0; jwriteC(op.ssgMacro.val[j]); } } // release points - w->writeI(std.volMacroRel); - w->writeI(std.arpMacroRel); - w->writeI(std.dutyMacroRel); - w->writeI(std.waveMacroRel); - w->writeI(std.pitchMacroRel); - w->writeI(std.ex1MacroRel); - w->writeI(std.ex2MacroRel); - w->writeI(std.ex3MacroRel); - w->writeI(std.algMacroRel); - w->writeI(std.fbMacroRel); - w->writeI(std.fmsMacroRel); - w->writeI(std.amsMacroRel); + w->writeI(std.volMacro.rel); + w->writeI(std.arpMacro.rel); + w->writeI(std.dutyMacro.rel); + w->writeI(std.waveMacro.rel); + w->writeI(std.pitchMacro.rel); + w->writeI(std.ex1Macro.rel); + w->writeI(std.ex2Macro.rel); + w->writeI(std.ex3Macro.rel); + w->writeI(std.algMacro.rel); + w->writeI(std.fbMacro.rel); + w->writeI(std.fmsMacro.rel); + w->writeI(std.amsMacro.rel); for (int i=0; i<4; i++) { DivInstrumentSTD::OpMacro& op=std.opMacros[i]; - w->writeI(op.amMacroRel); - w->writeI(op.arMacroRel); - w->writeI(op.drMacroRel); - w->writeI(op.multMacroRel); - w->writeI(op.rrMacroRel); - w->writeI(op.slMacroRel); - w->writeI(op.tlMacroRel); - w->writeI(op.dt2MacroRel); - w->writeI(op.rsMacroRel); - w->writeI(op.dtMacroRel); - w->writeI(op.d2rMacroRel); - w->writeI(op.ssgMacroRel); + w->writeI(op.amMacro.rel); + w->writeI(op.arMacro.rel); + w->writeI(op.drMacro.rel); + w->writeI(op.multMacro.rel); + w->writeI(op.rrMacro.rel); + w->writeI(op.slMacro.rel); + w->writeI(op.tlMacro.rel); + w->writeI(op.dt2Macro.rel); + w->writeI(op.rsMacro.rel); + w->writeI(op.dtMacro.rel); + w->writeI(op.d2rMacro.rel); + w->writeI(op.ssgMacro.rel); } // extended op macros for (int i=0; i<4; i++) { DivInstrumentSTD::OpMacro& op=std.opMacros[i]; - w->writeI(op.damMacroLen); - w->writeI(op.dvbMacroLen); - w->writeI(op.egtMacroLen); - w->writeI(op.kslMacroLen); - w->writeI(op.susMacroLen); - w->writeI(op.vibMacroLen); - w->writeI(op.wsMacroLen); - w->writeI(op.ksrMacroLen); + w->writeI(op.damMacro.len); + w->writeI(op.dvbMacro.len); + w->writeI(op.egtMacro.len); + w->writeI(op.kslMacro.len); + w->writeI(op.susMacro.len); + w->writeI(op.vibMacro.len); + w->writeI(op.wsMacro.len); + w->writeI(op.ksrMacro.len); - w->writeI(op.damMacroLoop); - w->writeI(op.dvbMacroLoop); - w->writeI(op.egtMacroLoop); - w->writeI(op.kslMacroLoop); - w->writeI(op.susMacroLoop); - w->writeI(op.vibMacroLoop); - w->writeI(op.wsMacroLoop); - w->writeI(op.ksrMacroLoop); + w->writeI(op.damMacro.loop); + w->writeI(op.dvbMacro.loop); + w->writeI(op.egtMacro.loop); + w->writeI(op.kslMacro.loop); + w->writeI(op.susMacro.loop); + w->writeI(op.vibMacro.loop); + w->writeI(op.wsMacro.loop); + w->writeI(op.ksrMacro.loop); - w->writeI(op.damMacroRel); - w->writeI(op.dvbMacroRel); - w->writeI(op.egtMacroRel); - w->writeI(op.kslMacroRel); - w->writeI(op.susMacroRel); - w->writeI(op.vibMacroRel); - w->writeI(op.wsMacroRel); - w->writeI(op.ksrMacroRel); + w->writeI(op.damMacro.rel); + w->writeI(op.dvbMacro.rel); + w->writeI(op.egtMacro.rel); + w->writeI(op.kslMacro.rel); + w->writeI(op.susMacro.rel); + w->writeI(op.vibMacro.rel); + w->writeI(op.wsMacro.rel); + w->writeI(op.ksrMacro.rel); - w->writeC(op.damMacroOpen); - w->writeC(op.dvbMacroOpen); - w->writeC(op.egtMacroOpen); - w->writeC(op.kslMacroOpen); - w->writeC(op.susMacroOpen); - w->writeC(op.vibMacroOpen); - w->writeC(op.wsMacroOpen); - w->writeC(op.ksrMacroOpen); + w->writeC(op.damMacro.open); + w->writeC(op.dvbMacro.open); + w->writeC(op.egtMacro.open); + w->writeC(op.kslMacro.open); + w->writeC(op.susMacro.open); + w->writeC(op.vibMacro.open); + w->writeC(op.wsMacro.open); + w->writeC(op.ksrMacro.open); } for (int i=0; i<4; i++) { DivInstrumentSTD::OpMacro& op=std.opMacros[i]; - for (int j=0; jwriteC(op.damMacro[j]); + for (int j=0; jwriteC(op.damMacro.val[j]); } - for (int j=0; jwriteC(op.dvbMacro[j]); + for (int j=0; jwriteC(op.dvbMacro.val[j]); } - for (int j=0; jwriteC(op.egtMacro[j]); + for (int j=0; jwriteC(op.egtMacro.val[j]); } - for (int j=0; jwriteC(op.kslMacro[j]); + for (int j=0; jwriteC(op.kslMacro.val[j]); } - for (int j=0; jwriteC(op.susMacro[j]); + for (int j=0; jwriteC(op.susMacro.val[j]); } - for (int j=0; jwriteC(op.vibMacro[j]); + for (int j=0; jwriteC(op.vibMacro.val[j]); } - for (int j=0; jwriteC(op.wsMacro[j]); + for (int j=0; jwriteC(op.wsMacro.val[j]); } - for (int j=0; jwriteC(op.ksrMacro[j]); + for (int j=0; jwriteC(op.ksrMacro.val[j]); } - } + }*/ // OPL drum data w->writeC(fm.fixedDrums); @@ -394,66 +478,67 @@ void DivInstrument::putInsData(SafeWriter* w) { w->writeC(0); // reserved // more macros - w->writeI(std.panLMacroLen); - w->writeI(std.panRMacroLen); - w->writeI(std.phaseResetMacroLen); - w->writeI(std.ex4MacroLen); - w->writeI(std.ex5MacroLen); - w->writeI(std.ex6MacroLen); - w->writeI(std.ex7MacroLen); - w->writeI(std.ex8MacroLen); + /* + w->writeI(std.panLMacro.len); + w->writeI(std.panRMacro.len); + w->writeI(std.phaseResetMacro.len); + w->writeI(std.ex4Macro.len); + w->writeI(std.ex5Macro.len); + w->writeI(std.ex6Macro.len); + w->writeI(std.ex7Macro.len); + w->writeI(std.ex8Macro.len); - w->writeI(std.panLMacroLoop); - w->writeI(std.panRMacroLoop); - w->writeI(std.phaseResetMacroLoop); - w->writeI(std.ex4MacroLoop); - w->writeI(std.ex5MacroLoop); - w->writeI(std.ex6MacroLoop); - w->writeI(std.ex7MacroLoop); - w->writeI(std.ex8MacroLoop); + w->writeI(std.panLMacro.loop); + w->writeI(std.panRMacro.loop); + w->writeI(std.phaseResetMacro.loop); + w->writeI(std.ex4Macro.loop); + w->writeI(std.ex5Macro.loop); + w->writeI(std.ex6Macro.loop); + w->writeI(std.ex7Macro.loop); + w->writeI(std.ex8Macro.loop); - w->writeI(std.panLMacroRel); - w->writeI(std.panRMacroRel); - w->writeI(std.phaseResetMacroRel); - w->writeI(std.ex4MacroRel); - w->writeI(std.ex5MacroRel); - w->writeI(std.ex6MacroRel); - w->writeI(std.ex7MacroRel); - w->writeI(std.ex8MacroRel); + w->writeI(std.panLMacro.rel); + w->writeI(std.panRMacro.rel); + w->writeI(std.phaseResetMacro.rel); + w->writeI(std.ex4Macro.rel); + w->writeI(std.ex5Macro.rel); + w->writeI(std.ex6Macro.rel); + w->writeI(std.ex7Macro.rel); + w->writeI(std.ex8Macro.rel); - w->writeC(std.panLMacroOpen); - w->writeC(std.panRMacroOpen); - w->writeC(std.phaseResetMacroOpen); - w->writeC(std.ex4MacroOpen); - w->writeC(std.ex5MacroOpen); - w->writeC(std.ex6MacroOpen); - w->writeC(std.ex7MacroOpen); - w->writeC(std.ex8MacroOpen); + w->writeC(std.panLMacro.open); + w->writeC(std.panRMacro.open); + w->writeC(std.phaseResetMacro.open); + w->writeC(std.ex4Macro.open); + w->writeC(std.ex5Macro.open); + w->writeC(std.ex6Macro.open); + w->writeC(std.ex7Macro.open); + w->writeC(std.ex8Macro.open); - for (int j=0; jwriteI(std.panLMacro[j]); + for (int j=0; jwriteI(std.panLMacro.val[j]); } - for (int j=0; jwriteI(std.panRMacro[j]); + for (int j=0; jwriteI(std.panRMacro.val[j]); } - for (int j=0; jwriteI(std.phaseResetMacro[j]); + for (int j=0; jwriteI(std.phaseResetMacro.val[j]); } - for (int j=0; jwriteI(std.ex4Macro[j]); + for (int j=0; jwriteI(std.ex4Macro.val[j]); } - for (int j=0; jwriteI(std.ex5Macro[j]); + for (int j=0; jwriteI(std.ex5Macro.val[j]); } - for (int j=0; jwriteI(std.ex6Macro[j]); + for (int j=0; jwriteI(std.ex6Macro.val[j]); } - for (int j=0; jwriteI(std.ex7Macro[j]); - } - for (int j=0; jwriteI(std.ex8Macro[j]); + for (int j=0; jwriteI(std.ex7Macro.val[j]); } + for (int j=0; jwriteI(std.ex8Macro.val[j]); + }*/ // FDS w->writeI(fds.modSpeed); @@ -482,7 +567,35 @@ void DivInstrument::putInsData(SafeWriter* w) { w->writeC(ws.param4); } +void readMacroData(DivInstrumentMacro &m, SafeReader& reader, short version) { + char magic[4]; + reader.read(magic,4); + if (memcmp(magic,"MACR",4)!=0) { + logE("invalid macro header!\n"); + return /*DIV_DATA_INVALID_HEADER*/; + } + reader.readI(); + + reader.readS(); // format version. ignored. + /*type=(DivInstrumentType)*/reader.readS(); // instrument type + reader.readC(); + m.name=reader.readString(); + + m.len=reader.readI(); + m.loop=reader.readI(); + m.rel=reader.readI(); + m.mode=reader.readI(); + m.open=reader.readC(); + for (int v=0; v=17) { - std.pitchMacroLen=reader.readI(); - std.ex1MacroLen=reader.readI(); - std.ex2MacroLen=reader.readI(); - std.ex3MacroLen=reader.readI(); - } - std.volMacroLoop=reader.readI(); - std.arpMacroLoop=reader.readI(); - std.dutyMacroLoop=reader.readI(); - std.waveMacroLoop=reader.readI(); - if (version>=17) { - std.pitchMacroLoop=reader.readI(); - std.ex1MacroLoop=reader.readI(); - std.ex2MacroLoop=reader.readI(); - std.ex3MacroLoop=reader.readI(); - } - std.arpMacroMode=reader.readC(); - std.volMacroHeight=reader.readC(); - std.dutyMacroHeight=reader.readC(); - std.waveMacroHeight=reader.readC(); - if (std.volMacroHeight==0) std.volMacroHeight=15; - if (std.dutyMacroHeight==0) std.dutyMacroHeight=3; - if (std.waveMacroHeight==0) std.waveMacroHeight=63; - reader.read(std.volMacro,4*std.volMacroLen); - reader.read(std.arpMacro,4*std.arpMacroLen); - reader.read(std.dutyMacro,4*std.dutyMacroLen); - reader.read(std.waveMacro,4*std.waveMacroLen); - if (version<31) { - if (!std.arpMacroMode) for (int j=0; j=17) { - reader.read(std.pitchMacro,4*std.pitchMacroLen); - reader.read(std.ex1Macro,4*std.ex1MacroLen); - reader.read(std.ex2Macro,4*std.ex2MacroLen); - reader.read(std.ex3Macro,4*std.ex3MacroLen); - } else { - if (type==DIV_INS_STD) { - if (std.volMacroHeight==31) { - type=DIV_INS_PCE; - } - if (std.dutyMacroHeight==31) { - type=DIV_INS_AY; + if (!istest) { + // standard + std.volMacro.len=reader.readI(); + std.arpMacro.len=reader.readI(); + std.dutyMacro.len=reader.readI(); + std.waveMacro.len=reader.readI(); + if (version>=17) { + std.pitchMacro.len=reader.readI(); + std.ex1Macro.len=reader.readI(); + std.ex2Macro.len=reader.readI(); + std.ex3Macro.len=reader.readI(); + } + std.volMacro.loop=reader.readI(); + std.arpMacro.loop=reader.readI(); + std.dutyMacro.loop=reader.readI(); + std.waveMacro.loop=reader.readI(); + if (version>=17) { + std.pitchMacro.loop=reader.readI(); + std.ex1Macro.loop=reader.readI(); + std.ex2Macro.loop=reader.readI(); + std.ex3Macro.loop=reader.readI(); + } + std.arpMacro.mode=reader.readC(); + std.volMacro.height=reader.readC(); + std.dutyMacro.height=reader.readC(); + std.waveMacro.height=reader.readC(); + if (std.volMacro.height==0) std.volMacro.height=15; + if (std.dutyMacro.height==0) std.dutyMacro.height=3; + if (std.waveMacro.height==0) std.waveMacro.height=63; + reader.read(std.volMacro.val,4*std.volMacro.len); + reader.read(std.arpMacro.val,4*std.arpMacro.len); + reader.read(std.dutyMacro.val,4*std.dutyMacro.len); + reader.read(std.waveMacro.val,4*std.waveMacro.len); + if (version<31) { + if (!std.arpMacro.mode) for (int j=0; j=29) { - std.algMacroLen=reader.readI(); - std.fbMacroLen=reader.readI(); - std.fmsMacroLen=reader.readI(); - std.amsMacroLen=reader.readI(); - std.algMacroLoop=reader.readI(); - std.fbMacroLoop=reader.readI(); - std.fmsMacroLoop=reader.readI(); - std.amsMacroLoop=reader.readI(); - std.volMacroOpen=reader.readC(); - std.arpMacroOpen=reader.readC(); - std.dutyMacroOpen=reader.readC(); - std.waveMacroOpen=reader.readC(); - std.pitchMacroOpen=reader.readC(); - std.ex1MacroOpen=reader.readC(); - std.ex2MacroOpen=reader.readC(); - std.ex3MacroOpen=reader.readC(); - std.algMacroOpen=reader.readC(); - std.fbMacroOpen=reader.readC(); - std.fmsMacroOpen=reader.readC(); - std.amsMacroOpen=reader.readC(); - - reader.read(std.algMacro,4*std.algMacroLen); - reader.read(std.fbMacro,4*std.fbMacroLen); - reader.read(std.fmsMacro,4*std.fmsMacroLen); - reader.read(std.amsMacro,4*std.amsMacroLen); - - for (int i=0; i<4; i++) { - DivInstrumentSTD::OpMacro& op=std.opMacros[i]; - - op.amMacroLen=reader.readI(); - op.arMacroLen=reader.readI(); - op.drMacroLen=reader.readI(); - op.multMacroLen=reader.readI(); - op.rrMacroLen=reader.readI(); - op.slMacroLen=reader.readI(); - op.tlMacroLen=reader.readI(); - op.dt2MacroLen=reader.readI(); - op.rsMacroLen=reader.readI(); - op.dtMacroLen=reader.readI(); - op.d2rMacroLen=reader.readI(); - op.ssgMacroLen=reader.readI(); - - op.amMacroLoop=reader.readI(); - op.arMacroLoop=reader.readI(); - op.drMacroLoop=reader.readI(); - op.multMacroLoop=reader.readI(); - op.rrMacroLoop=reader.readI(); - op.slMacroLoop=reader.readI(); - op.tlMacroLoop=reader.readI(); - op.dt2MacroLoop=reader.readI(); - op.rsMacroLoop=reader.readI(); - op.dtMacroLoop=reader.readI(); - op.d2rMacroLoop=reader.readI(); - op.ssgMacroLoop=reader.readI(); - - op.amMacroOpen=reader.readC(); - op.arMacroOpen=reader.readC(); - op.drMacroOpen=reader.readC(); - op.multMacroOpen=reader.readC(); - op.rrMacroOpen=reader.readC(); - op.slMacroOpen=reader.readC(); - op.tlMacroOpen=reader.readC(); - op.dt2MacroOpen=reader.readC(); - op.rsMacroOpen=reader.readC(); - op.dtMacroOpen=reader.readC(); - op.d2rMacroOpen=reader.readC(); - op.ssgMacroOpen=reader.readC(); + if (version>=17) { + reader.read(std.pitchMacro.val,4*std.pitchMacro.len); + reader.read(std.ex1Macro.val,4*std.ex1Macro.len); + reader.read(std.ex2Macro.val,4*std.ex2Macro.len); + reader.read(std.ex3Macro.val,4*std.ex3Macro.len); + } else { + if (type==DIV_INS_STD) { + if (std.volMacro.height==31) { + type=DIV_INS_PCE; + } + if (std.dutyMacro.height==31) { + type=DIV_INS_AY; + } + } } - for (int i=0; i<4; i++) { - DivInstrumentSTD::OpMacro& op=std.opMacros[i]; - reader.read(op.amMacro,op.amMacroLen); - reader.read(op.arMacro,op.arMacroLen); - reader.read(op.drMacro,op.drMacroLen); - reader.read(op.multMacro,op.multMacroLen); - reader.read(op.rrMacro,op.rrMacroLen); - reader.read(op.slMacro,op.slMacroLen); - reader.read(op.tlMacro,op.tlMacroLen); - reader.read(op.dt2Macro,op.dt2MacroLen); - reader.read(op.rsMacro,op.rsMacroLen); - reader.read(op.dtMacro,op.dtMacroLen); - reader.read(op.d2rMacro,op.d2rMacroLen); - reader.read(op.ssgMacro,op.ssgMacroLen); - } - } + // FM macros + if (version>=29) { + std.algMacro.len=reader.readI(); + std.fbMacro.len=reader.readI(); + std.fmsMacro.len=reader.readI(); + std.amsMacro.len=reader.readI(); + std.algMacro.loop=reader.readI(); + std.fbMacro.loop=reader.readI(); + std.fmsMacro.loop=reader.readI(); + std.amsMacro.loop=reader.readI(); + std.volMacro.open=reader.readC(); + std.arpMacro.open=reader.readC(); + std.dutyMacro.open=reader.readC(); + std.waveMacro.open=reader.readC(); + std.pitchMacro.open=reader.readC(); + std.ex1Macro.open=reader.readC(); + std.ex2Macro.open=reader.readC(); + std.ex3Macro.open=reader.readC(); + std.algMacro.open=reader.readC(); + std.fbMacro.open=reader.readC(); + std.fmsMacro.open=reader.readC(); + std.amsMacro.open=reader.readC(); - // release points - if (version>=44) { - std.volMacroRel=reader.readI(); - std.arpMacroRel=reader.readI(); - std.dutyMacroRel=reader.readI(); - std.waveMacroRel=reader.readI(); - std.pitchMacroRel=reader.readI(); - std.ex1MacroRel=reader.readI(); - std.ex2MacroRel=reader.readI(); - std.ex3MacroRel=reader.readI(); - std.algMacroRel=reader.readI(); - std.fbMacroRel=reader.readI(); - std.fmsMacroRel=reader.readI(); - std.amsMacroRel=reader.readI(); + reader.read(std.algMacro.val,4*std.algMacro.len); + reader.read(std.fbMacro.val,4*std.fbMacro.len); + reader.read(std.fmsMacro.val,4*std.fmsMacro.len); + reader.read(std.amsMacro.val,4*std.amsMacro.len); - for (int i=0; i<4; i++) { - DivInstrumentSTD::OpMacro& op=std.opMacros[i]; + for (int i=0; i<4; i++) { + DivInstrumentSTD::OpMacro& op=std.opMacros[i]; - op.amMacroRel=reader.readI(); - op.arMacroRel=reader.readI(); - op.drMacroRel=reader.readI(); - op.multMacroRel=reader.readI(); - op.rrMacroRel=reader.readI(); - op.slMacroRel=reader.readI(); - op.tlMacroRel=reader.readI(); - op.dt2MacroRel=reader.readI(); - op.rsMacroRel=reader.readI(); - op.dtMacroRel=reader.readI(); - op.d2rMacroRel=reader.readI(); - op.ssgMacroRel=reader.readI(); - } - } + op.amMacro.len=reader.readI(); + op.arMacro.len=reader.readI(); + op.drMacro.len=reader.readI(); + op.multMacro.len=reader.readI(); + op.rrMacro.len=reader.readI(); + op.slMacro.len=reader.readI(); + op.tlMacro.len=reader.readI(); + op.dt2Macro.len=reader.readI(); + op.rsMacro.len=reader.readI(); + op.dtMacro.len=reader.readI(); + op.d2rMacro.len=reader.readI(); + op.ssgMacro.len=reader.readI(); - // extended op macros - if (version>=61) { - for (int i=0; i<4; i++) { - DivInstrumentSTD::OpMacro& op=std.opMacros[i]; + op.amMacro.loop=reader.readI(); + op.arMacro.loop=reader.readI(); + op.drMacro.loop=reader.readI(); + op.multMacro.loop=reader.readI(); + op.rrMacro.loop=reader.readI(); + op.slMacro.loop=reader.readI(); + op.tlMacro.loop=reader.readI(); + op.dt2Macro.loop=reader.readI(); + op.rsMacro.loop=reader.readI(); + op.dtMacro.loop=reader.readI(); + op.d2rMacro.loop=reader.readI(); + op.ssgMacro.loop=reader.readI(); - op.damMacroLen=reader.readI(); - op.dvbMacroLen=reader.readI(); - op.egtMacroLen=reader.readI(); - op.kslMacroLen=reader.readI(); - op.susMacroLen=reader.readI(); - op.vibMacroLen=reader.readI(); - op.wsMacroLen=reader.readI(); - op.ksrMacroLen=reader.readI(); + op.amMacro.open=reader.readC(); + op.arMacro.open=reader.readC(); + op.drMacro.open=reader.readC(); + op.multMacro.open=reader.readC(); + op.rrMacro.open=reader.readC(); + op.slMacro.open=reader.readC(); + op.tlMacro.open=reader.readC(); + op.dt2Macro.open=reader.readC(); + op.rsMacro.open=reader.readC(); + op.dtMacro.open=reader.readC(); + op.d2rMacro.open=reader.readC(); + op.ssgMacro.open=reader.readC(); + } - op.damMacroLoop=reader.readI(); - op.dvbMacroLoop=reader.readI(); - op.egtMacroLoop=reader.readI(); - op.kslMacroLoop=reader.readI(); - op.susMacroLoop=reader.readI(); - op.vibMacroLoop=reader.readI(); - op.wsMacroLoop=reader.readI(); - op.ksrMacroLoop=reader.readI(); - - op.damMacroRel=reader.readI(); - op.dvbMacroRel=reader.readI(); - op.egtMacroRel=reader.readI(); - op.kslMacroRel=reader.readI(); - op.susMacroRel=reader.readI(); - op.vibMacroRel=reader.readI(); - op.wsMacroRel=reader.readI(); - op.ksrMacroRel=reader.readI(); - - op.damMacroOpen=reader.readC(); - op.dvbMacroOpen=reader.readC(); - op.egtMacroOpen=reader.readC(); - op.kslMacroOpen=reader.readC(); - op.susMacroOpen=reader.readC(); - op.vibMacroOpen=reader.readC(); - op.wsMacroOpen=reader.readC(); - op.ksrMacroOpen=reader.readC(); + for (int i=0; i<4; i++) { + DivInstrumentSTD::OpMacro& op=std.opMacros[i]; + reader.readByte(op.amMacro.val,op.amMacro.len,1); + reader.readByte(op.arMacro.val,op.arMacro.len,1); + reader.readByte(op.drMacro.val,op.drMacro.len,1); + reader.readByte(op.multMacro.val,op.multMacro.len,1); + reader.readByte(op.rrMacro.val,op.rrMacro.len,1); + reader.readByte(op.slMacro.val,op.slMacro.len,1); + reader.readByte(op.tlMacro.val,op.tlMacro.len,1); + reader.readByte(op.dt2Macro.val,op.dt2Macro.len,1); + reader.readByte(op.rsMacro.val,op.rsMacro.len,1); + reader.readByte(op.dtMacro.val,op.dtMacro.len,1); + reader.readByte(op.d2rMacro.val,op.d2rMacro.len,1); + reader.readByte(op.ssgMacro.val,op.ssgMacro.len,1); + } } - for (int i=0; i<4; i++) { - DivInstrumentSTD::OpMacro& op=std.opMacros[i]; - reader.read(op.damMacro,op.damMacroLen); - reader.read(op.dvbMacro,op.dvbMacroLen); - reader.read(op.egtMacro,op.egtMacroLen); - reader.read(op.kslMacro,op.kslMacroLen); - reader.read(op.susMacro,op.susMacroLen); - reader.read(op.vibMacro,op.vibMacroLen); - reader.read(op.wsMacro,op.wsMacroLen); - reader.read(op.ksrMacro,op.ksrMacroLen); + // release points + if (version>=44) { + std.volMacro.rel=reader.readI(); + std.arpMacro.rel=reader.readI(); + std.dutyMacro.rel=reader.readI(); + std.waveMacro.rel=reader.readI(); + std.pitchMacro.rel=reader.readI(); + std.ex1Macro.rel=reader.readI(); + std.ex2Macro.rel=reader.readI(); + std.ex3Macro.rel=reader.readI(); + std.algMacro.rel=reader.readI(); + std.fbMacro.rel=reader.readI(); + std.fmsMacro.rel=reader.readI(); + std.amsMacro.rel=reader.readI(); + + for (int i=0; i<4; i++) { + DivInstrumentSTD::OpMacro& op=std.opMacros[i]; + + op.amMacro.rel=reader.readI(); + op.arMacro.rel=reader.readI(); + op.drMacro.rel=reader.readI(); + op.multMacro.rel=reader.readI(); + op.rrMacro.rel=reader.readI(); + op.slMacro.rel=reader.readI(); + op.tlMacro.rel=reader.readI(); + op.dt2Macro.rel=reader.readI(); + op.rsMacro.rel=reader.readI(); + op.dtMacro.rel=reader.readI(); + op.d2rMacro.rel=reader.readI(); + op.ssgMacro.rel=reader.readI(); + } + } + + // extended op macros + if (version>=61) { + for (int i=0; i<4; i++) { + DivInstrumentSTD::OpMacro& op=std.opMacros[i]; + + op.damMacro.len=reader.readI(); + op.dvbMacro.len=reader.readI(); + op.egtMacro.len=reader.readI(); + op.kslMacro.len=reader.readI(); + op.susMacro.len=reader.readI(); + op.vibMacro.len=reader.readI(); + op.wsMacro.len=reader.readI(); + op.ksrMacro.len=reader.readI(); + + op.damMacro.loop=reader.readI(); + op.dvbMacro.loop=reader.readI(); + op.egtMacro.loop=reader.readI(); + op.kslMacro.loop=reader.readI(); + op.susMacro.loop=reader.readI(); + op.vibMacro.loop=reader.readI(); + op.wsMacro.loop=reader.readI(); + op.ksrMacro.loop=reader.readI(); + + op.damMacro.rel=reader.readI(); + op.dvbMacro.rel=reader.readI(); + op.egtMacro.rel=reader.readI(); + op.kslMacro.rel=reader.readI(); + op.susMacro.rel=reader.readI(); + op.vibMacro.rel=reader.readI(); + op.wsMacro.rel=reader.readI(); + op.ksrMacro.rel=reader.readI(); + + op.damMacro.open=reader.readC(); + op.dvbMacro.open=reader.readC(); + op.egtMacro.open=reader.readC(); + op.kslMacro.open=reader.readC(); + op.susMacro.open=reader.readC(); + op.vibMacro.open=reader.readC(); + op.wsMacro.open=reader.readC(); + op.ksrMacro.open=reader.readC(); + } + + for (int i=0; i<4; i++) { + DivInstrumentSTD::OpMacro& op=std.opMacros[i]; + reader.readByte(op.damMacro.val,op.damMacro.len,1); + reader.readByte(op.dvbMacro.val,op.dvbMacro.len,1); + reader.readByte(op.egtMacro.val,op.egtMacro.len,1); + reader.readByte(op.kslMacro.val,op.kslMacro.len,1); + reader.readByte(op.susMacro.val,op.susMacro.len,1); + reader.readByte(op.vibMacro.val,op.vibMacro.len,1); + reader.readByte(op.wsMacro.val,op.wsMacro.len,1); + reader.readByte(op.ksrMacro.val,op.ksrMacro.len,1); + } } } @@ -814,16 +997,16 @@ DivDataErrors DivInstrument::readInsData(SafeReader& reader, short version) { // clear noise macro if PCE instrument and version<63 if (version<63 && type==DIV_INS_PCE) { - std.dutyMacroLen=0; - std.dutyMacroLoop=-1; - std.dutyMacroRel=-1; + std.dutyMacro.len=0; + std.dutyMacro.loop=-1; + std.dutyMacro.rel=-1; } // clear wave macro if OPLL instrument and version<70 if (version<70 && type==DIV_INS_OPLL) { - std.waveMacroLen=0; - std.waveMacroLoop=-1; - std.waveMacroRel=-1; + std.waveMacro.len=0; + std.waveMacro.loop=-1; + std.waveMacro.rel=-1; } // sample map @@ -845,51 +1028,53 @@ DivDataErrors DivInstrument::readInsData(SafeReader& reader, short version) { } // more macros - if (version>=76) { - std.panLMacroLen=reader.readI(); - std.panRMacroLen=reader.readI(); - std.phaseResetMacroLen=reader.readI(); - std.ex4MacroLen=reader.readI(); - std.ex5MacroLen=reader.readI(); - std.ex6MacroLen=reader.readI(); - std.ex7MacroLen=reader.readI(); - std.ex8MacroLen=reader.readI(); + if (!istest) { + if (version>=76) { + std.panLMacro.len=reader.readI(); + std.panRMacro.len=reader.readI(); + std.phaseResetMacro.len=reader.readI(); + std.ex4Macro.len=reader.readI(); + std.ex5Macro.len=reader.readI(); + std.ex6Macro.len=reader.readI(); + std.ex7Macro.len=reader.readI(); + std.ex8Macro.len=reader.readI(); - std.panLMacroLoop=reader.readI(); - std.panRMacroLoop=reader.readI(); - std.phaseResetMacroLoop=reader.readI(); - std.ex4MacroLoop=reader.readI(); - std.ex5MacroLoop=reader.readI(); - std.ex6MacroLoop=reader.readI(); - std.ex7MacroLoop=reader.readI(); - std.ex8MacroLoop=reader.readI(); + std.panLMacro.loop=reader.readI(); + std.panRMacro.loop=reader.readI(); + std.phaseResetMacro.loop=reader.readI(); + std.ex4Macro.loop=reader.readI(); + std.ex5Macro.loop=reader.readI(); + std.ex6Macro.loop=reader.readI(); + std.ex7Macro.loop=reader.readI(); + std.ex8Macro.loop=reader.readI(); - std.panLMacroRel=reader.readI(); - std.panRMacroRel=reader.readI(); - std.phaseResetMacroRel=reader.readI(); - std.ex4MacroRel=reader.readI(); - std.ex5MacroRel=reader.readI(); - std.ex6MacroRel=reader.readI(); - std.ex7MacroRel=reader.readI(); - std.ex8MacroRel=reader.readI(); + std.panLMacro.rel=reader.readI(); + std.panRMacro.rel=reader.readI(); + std.phaseResetMacro.rel=reader.readI(); + std.ex4Macro.rel=reader.readI(); + std.ex5Macro.rel=reader.readI(); + std.ex6Macro.rel=reader.readI(); + std.ex7Macro.rel=reader.readI(); + std.ex8Macro.rel=reader.readI(); - std.panLMacroOpen=reader.readC(); - std.panRMacroOpen=reader.readC(); - std.phaseResetMacroOpen=reader.readC(); - std.ex4MacroOpen=reader.readC(); - std.ex5MacroOpen=reader.readC(); - std.ex6MacroOpen=reader.readC(); - std.ex7MacroOpen=reader.readC(); - std.ex8MacroOpen=reader.readC(); + std.panLMacro.open=reader.readC(); + std.panRMacro.open=reader.readC(); + std.phaseResetMacro.open=reader.readC(); + std.ex4Macro.open=reader.readC(); + std.ex5Macro.open=reader.readC(); + std.ex6Macro.open=reader.readC(); + std.ex7Macro.open=reader.readC(); + std.ex8Macro.open=reader.readC(); - reader.read(std.panLMacro,4*std.panLMacroLen); - reader.read(std.panRMacro,4*std.panRMacroLen); - reader.read(std.phaseResetMacro,4*std.phaseResetMacroLen); - reader.read(std.ex4Macro,4*std.ex4MacroLen); - reader.read(std.ex5Macro,4*std.ex5MacroLen); - reader.read(std.ex6Macro,4*std.ex6MacroLen); - reader.read(std.ex7Macro,4*std.ex7MacroLen); - reader.read(std.ex8Macro,4*std.ex8MacroLen); + reader.read(std.panLMacro.val,4*std.panLMacro.len); + reader.read(std.panRMacro.val,4*std.panRMacro.len); + reader.read(std.phaseResetMacro.val,4*std.phaseResetMacro.len); + reader.read(std.ex4Macro.val,4*std.ex4Macro.len); + reader.read(std.ex5Macro.val,4*std.ex5Macro.len); + reader.read(std.ex6Macro.val,4*std.ex6Macro.len); + reader.read(std.ex7Macro.val,4*std.ex7Macro.len); + reader.read(std.ex8Macro.val,4*std.ex8Macro.len); + } } // FDS diff --git a/src/engine/instrument.h b/src/engine/instrument.h index 8109030e..dd56ef84 100644 --- a/src/engine/instrument.h +++ b/src/engine/instrument.h @@ -26,7 +26,7 @@ // NOTICE! // before adding new instrument types to this struct, please ask me first. // absolutely zero support granted to conflicting formats. -enum DivInstrumentType { +enum DivInstrumentType : unsigned short { DIV_INS_STD=0, DIV_INS_FM=1, DIV_INS_GB=2, @@ -77,6 +77,7 @@ struct DivInstrumentFM { bool fixedDrums; unsigned short kickFreq, snareHatFreq, tomTopFreq; struct Operator { + bool enable; unsigned char am, ar, dr, mult, rr, sl, tl, dt2, rs, dt, d2r, ssgEnv; unsigned char dam, dvb, egt, ksl, sus, vib, ws, ksr; // YMU759/OPL/OPZ Operator(): @@ -151,248 +152,122 @@ struct DivInstrumentFM { }; // this is getting out of hand +struct DivInstrumentMacro { + String name; + int val[256]; + int height; + unsigned int mode; + bool open; + unsigned char len; + signed char loop; + signed char rel; + DivInstrumentMacro(String n, int h=~0, bool initOpen=false): + name(n), + val{0}, + height(h), + mode(0), + open(initOpen), + len(0), + loop(-1), + rel(-1) {} +}; + struct DivInstrumentSTD { - int volMacro[256]; - int arpMacro[256]; - int dutyMacro[256]; - int waveMacro[256]; - int pitchMacro[256]; - int ex1Macro[256]; - int ex2Macro[256]; - int ex3Macro[256]; - int algMacro[256]; - int fbMacro[256]; - int fmsMacro[256]; - int amsMacro[256]; - int panLMacro[256]; - int panRMacro[256]; - int phaseResetMacro[256]; - int ex4Macro[256]; - int ex5Macro[256]; - int ex6Macro[256]; - int ex7Macro[256]; - int ex8Macro[256]; + DivInstrumentMacro volMacro; + DivInstrumentMacro arpMacro; + DivInstrumentMacro dutyMacro; + DivInstrumentMacro waveMacro; + DivInstrumentMacro pitchMacro; + DivInstrumentMacro ex1Macro; + DivInstrumentMacro ex2Macro; + DivInstrumentMacro ex3Macro; + DivInstrumentMacro algMacro; + DivInstrumentMacro fbMacro; + DivInstrumentMacro fmsMacro; + DivInstrumentMacro fms2Macro; + DivInstrumentMacro amsMacro; + DivInstrumentMacro ams2Macro; + DivInstrumentMacro panLMacro; + DivInstrumentMacro panRMacro; + DivInstrumentMacro phaseResetMacro; + DivInstrumentMacro ex4Macro; + DivInstrumentMacro ex5Macro; + DivInstrumentMacro ex6Macro; + DivInstrumentMacro ex7Macro; + DivInstrumentMacro ex8Macro; - bool arpMacroMode; - unsigned char volMacroHeight, dutyMacroHeight, waveMacroHeight; - - bool volMacroOpen, arpMacroOpen, dutyMacroOpen, waveMacroOpen; - bool pitchMacroOpen, ex1MacroOpen, ex2MacroOpen, ex3MacroOpen; - bool algMacroOpen, fbMacroOpen, fmsMacroOpen, amsMacroOpen; - bool panLMacroOpen, panRMacroOpen, phaseResetMacroOpen, ex4MacroOpen; - bool ex5MacroOpen, ex6MacroOpen, ex7MacroOpen, ex8MacroOpen; - - unsigned char volMacroLen, arpMacroLen, dutyMacroLen, waveMacroLen; - unsigned char pitchMacroLen, ex1MacroLen, ex2MacroLen, ex3MacroLen; - unsigned char algMacroLen, fbMacroLen, fmsMacroLen, amsMacroLen; - unsigned char panLMacroLen, panRMacroLen, phaseResetMacroLen, ex4MacroLen; - unsigned char ex5MacroLen, ex6MacroLen, ex7MacroLen, ex8MacroLen; - - signed char volMacroLoop, arpMacroLoop, dutyMacroLoop, waveMacroLoop; - signed char pitchMacroLoop, ex1MacroLoop, ex2MacroLoop, ex3MacroLoop; - signed char algMacroLoop, fbMacroLoop, fmsMacroLoop, amsMacroLoop; - signed char panLMacroLoop, panRMacroLoop, phaseResetMacroLoop, ex4MacroLoop; - signed char ex5MacroLoop, ex6MacroLoop, ex7MacroLoop, ex8MacroLoop; - - signed char volMacroRel, arpMacroRel, dutyMacroRel, waveMacroRel; - signed char pitchMacroRel, ex1MacroRel, ex2MacroRel, ex3MacroRel; - signed char algMacroRel, fbMacroRel, fmsMacroRel, amsMacroRel; - signed char panLMacroRel, panRMacroRel, phaseResetMacroRel, ex4MacroRel; - signed char ex5MacroRel, ex6MacroRel, ex7MacroRel, ex8MacroRel; struct OpMacro { // ar, dr, mult, rr, sl, tl, dt2, rs, dt, d2r, ssgEnv; - unsigned char amMacro[256]; - unsigned char arMacro[256]; - unsigned char drMacro[256]; - unsigned char multMacro[256]; - unsigned char rrMacro[256]; - unsigned char slMacro[256]; - unsigned char tlMacro[256]; - unsigned char dt2Macro[256]; - unsigned char rsMacro[256]; - unsigned char dtMacro[256]; - unsigned char d2rMacro[256]; - unsigned char ssgMacro[256]; - unsigned char damMacro[256]; - unsigned char dvbMacro[256]; - unsigned char egtMacro[256]; - unsigned char kslMacro[256]; - unsigned char susMacro[256]; - unsigned char vibMacro[256]; - unsigned char wsMacro[256]; - unsigned char ksrMacro[256]; - bool amMacroOpen, arMacroOpen, drMacroOpen, multMacroOpen; - bool rrMacroOpen, slMacroOpen, tlMacroOpen, dt2MacroOpen; - bool rsMacroOpen, dtMacroOpen, d2rMacroOpen, ssgMacroOpen; - bool damMacroOpen, dvbMacroOpen, egtMacroOpen, kslMacroOpen; - bool susMacroOpen, vibMacroOpen, wsMacroOpen, ksrMacroOpen; - unsigned char amMacroLen, arMacroLen, drMacroLen, multMacroLen; - unsigned char rrMacroLen, slMacroLen, tlMacroLen, dt2MacroLen; - unsigned char rsMacroLen, dtMacroLen, d2rMacroLen, ssgMacroLen; - unsigned char damMacroLen, dvbMacroLen, egtMacroLen, kslMacroLen; - unsigned char susMacroLen, vibMacroLen, wsMacroLen, ksrMacroLen; - signed char amMacroLoop, arMacroLoop, drMacroLoop, multMacroLoop; - signed char rrMacroLoop, slMacroLoop, tlMacroLoop, dt2MacroLoop; - signed char rsMacroLoop, dtMacroLoop, d2rMacroLoop, ssgMacroLoop; - signed char damMacroLoop, dvbMacroLoop, egtMacroLoop, kslMacroLoop; - signed char susMacroLoop, vibMacroLoop, wsMacroLoop, ksrMacroLoop; - signed char amMacroRel, arMacroRel, drMacroRel, multMacroRel; - signed char rrMacroRel, slMacroRel, tlMacroRel, dt2MacroRel; - signed char rsMacroRel, dtMacroRel, d2rMacroRel, ssgMacroRel; - signed char damMacroRel, dvbMacroRel, egtMacroRel, kslMacroRel; - signed char susMacroRel, vibMacroRel, wsMacroRel, ksrMacroRel; + DivInstrumentMacro amMacro; + DivInstrumentMacro arMacro; + DivInstrumentMacro drMacro; + DivInstrumentMacro multMacro; + DivInstrumentMacro rrMacro; + DivInstrumentMacro slMacro; + DivInstrumentMacro tlMacro; + DivInstrumentMacro dt2Macro; + DivInstrumentMacro rsMacro; + DivInstrumentMacro dtMacro; + DivInstrumentMacro d2rMacro; + DivInstrumentMacro ssgMacro; + DivInstrumentMacro damMacro; + DivInstrumentMacro dvbMacro; + DivInstrumentMacro egtMacro; + DivInstrumentMacro kslMacro; + DivInstrumentMacro susMacro; + DivInstrumentMacro vibMacro; + DivInstrumentMacro wsMacro; + DivInstrumentMacro ksrMacro; OpMacro(): - amMacroOpen(false), arMacroOpen(false), drMacroOpen(false), multMacroOpen(false), - rrMacroOpen(false), slMacroOpen(false), tlMacroOpen(true), dt2MacroOpen(false), - rsMacroOpen(false), dtMacroOpen(false), d2rMacroOpen(false), ssgMacroOpen(false), - damMacroOpen(false), dvbMacroOpen(false), egtMacroOpen(false), kslMacroOpen(false), - susMacroOpen(false), vibMacroOpen(false), wsMacroOpen(false), ksrMacroOpen(false), - amMacroLen(0), arMacroLen(0), drMacroLen(0), multMacroLen(0), - rrMacroLen(0), slMacroLen(0), tlMacroLen(0), dt2MacroLen(0), - rsMacroLen(0), dtMacroLen(0), d2rMacroLen(0), ssgMacroLen(0), - damMacroLen(0), dvbMacroLen(0), egtMacroLen(0), kslMacroLen(0), - susMacroLen(0), vibMacroLen(0), wsMacroLen(0), ksrMacroLen(0), - amMacroLoop(-1), arMacroLoop(-1), drMacroLoop(-1), multMacroLoop(-1), - rrMacroLoop(-1), slMacroLoop(-1), tlMacroLoop(-1), dt2MacroLoop(-1), - rsMacroLoop(-1), dtMacroLoop(-1), d2rMacroLoop(-1), ssgMacroLoop(-1), - damMacroLoop(-1), dvbMacroLoop(-1), egtMacroLoop(-1), kslMacroLoop(-1), - susMacroLoop(-1), vibMacroLoop(-1), wsMacroLoop(-1), ksrMacroLoop(-1), - amMacroRel(-1), arMacroRel(-1), drMacroRel(-1), multMacroRel(-1), - rrMacroRel(-1), slMacroRel(-1), tlMacroRel(-1), dt2MacroRel(-1), - rsMacroRel(-1), dtMacroRel(-1), d2rMacroRel(-1), ssgMacroRel(-1), - damMacroRel(-1), dvbMacroRel(-1), egtMacroRel(-1), kslMacroRel(-1), - susMacroRel(-1), vibMacroRel(-1), wsMacroRel(-1), ksrMacroRel(-1) { - memset(amMacro,0,256); - memset(arMacro,0,256); - memset(drMacro,0,256); - memset(multMacro,0,256); - memset(rrMacro,0,256); - memset(slMacro,0,256); - memset(tlMacro,0,256); - memset(dt2Macro,0,256); - memset(rsMacro,0,256); - memset(dtMacro,0,256); - memset(d2rMacro,0,256); - memset(ssgMacro,0,256); - memset(damMacro,0,256); - memset(dvbMacro,0,256); - memset(egtMacro,0,256); - memset(kslMacro,0,256); - memset(susMacro,0,256); - memset(vibMacro,0,256); - memset(wsMacro,0,256); - memset(ksrMacro,0,256); - } + amMacro("am"), arMacro("ar"), drMacro("dr"), multMacro("mult"), + rrMacro("rr"), slMacro("sl"), tlMacro("tl",~0,true), dt2Macro("dt2"), + rsMacro("rs"), dtMacro("dt"), d2rMacro("d2r"), ssgMacro("ssg"), + damMacro("dam"), dvbMacro("dvb"), egtMacro("egt"), kslMacro("ksl"), + susMacro("sus"), vibMacro("vib"), wsMacro("ws"), ksrMacro("ksr") {} } opMacros[4]; + struct WaveSynthMacro { + DivInstrumentMacro wave1Macro, wave2Macro; + DivInstrumentMacro rateDividerMacro; + DivInstrumentMacro effectMacro; + DivInstrumentMacro oneShotMacro, enabledMacro, globalMacro; + DivInstrumentMacro speedMacro, param1Macro, param2Macro, param3Macro, param4Macro; + WaveSynthMacro(): + wave1Macro("wave1"), + wave2Macro("wave2"), + rateDividerMacro("rateDivider"), + effectMacro("effect"), + oneShotMacro("oneShot"), + enabledMacro("enabled"), + globalMacro("global"), + speedMacro("speed"), + param1Macro("param1"), + param2Macro("param2"), + param3Macro("param3"), + param4Macro("param4") {} + } ws; DivInstrumentSTD(): - arpMacroMode(false), - volMacroHeight(15), - dutyMacroHeight(3), - waveMacroHeight(63), - volMacroOpen(true), - arpMacroOpen(false), - dutyMacroOpen(false), - waveMacroOpen(false), - pitchMacroOpen(false), - ex1MacroOpen(false), - ex2MacroOpen(false), - ex3MacroOpen(false), - algMacroOpen(false), - fbMacroOpen(false), - fmsMacroOpen(false), - amsMacroOpen(false), - panLMacroOpen(false), - panRMacroOpen(false), - phaseResetMacroOpen(false), - ex4MacroOpen(false), - ex5MacroOpen(false), - ex6MacroOpen(false), - ex7MacroOpen(false), - ex8MacroOpen(false), - - volMacroLen(0), - arpMacroLen(0), - dutyMacroLen(0), - waveMacroLen(0), - pitchMacroLen(0), - ex1MacroLen(0), - ex2MacroLen(0), - ex3MacroLen(0), - algMacroLen(0), - fbMacroLen(0), - fmsMacroLen(0), - amsMacroLen(0), - panLMacroLen(0), - panRMacroLen(0), - phaseResetMacroLen(0), - ex4MacroLen(0), - ex5MacroLen(0), - ex6MacroLen(0), - ex7MacroLen(0), - ex8MacroLen(0), - - volMacroLoop(-1), - arpMacroLoop(-1), - dutyMacroLoop(-1), - waveMacroLoop(-1), - pitchMacroLoop(-1), - ex1MacroLoop(-1), - ex2MacroLoop(-1), - ex3MacroLoop(-1), - algMacroLoop(-1), - fbMacroLoop(-1), - fmsMacroLoop(-1), - amsMacroLoop(-1), - panLMacroLoop(-1), - panRMacroLoop(-1), - phaseResetMacroLoop(-1), - ex4MacroLoop(-1), - ex5MacroLoop(-1), - ex6MacroLoop(-1), - ex7MacroLoop(-1), - ex8MacroLoop(-1), - - volMacroRel(-1), - arpMacroRel(-1), - dutyMacroRel(-1), - waveMacroRel(-1), - pitchMacroRel(-1), - ex1MacroRel(-1), - ex2MacroRel(-1), - ex3MacroRel(-1), - algMacroRel(-1), - fbMacroRel(-1), - fmsMacroRel(-1), - amsMacroRel(-1), - panLMacroRel(-1), - panRMacroRel(-1), - phaseResetMacroRel(-1), - ex4MacroRel(-1), - ex5MacroRel(-1), - ex6MacroRel(-1), - ex7MacroRel(-1), - ex8MacroRel(-1) { - memset(volMacro,0,256*sizeof(int)); - memset(arpMacro,0,256*sizeof(int)); - memset(dutyMacro,0,256*sizeof(int)); - memset(waveMacro,0,256*sizeof(int)); - memset(pitchMacro,0,256*sizeof(int)); - memset(ex1Macro,0,256*sizeof(int)); - memset(ex2Macro,0,256*sizeof(int)); - memset(ex3Macro,0,256*sizeof(int)); - memset(algMacro,0,256*sizeof(int)); - memset(fbMacro,0,256*sizeof(int)); - memset(fmsMacro,0,256*sizeof(int)); - memset(amsMacro,0,256*sizeof(int)); - memset(panLMacro,0,256*sizeof(int)); - memset(panRMacro,0,256*sizeof(int)); - memset(phaseResetMacro,0,256*sizeof(int)); - memset(ex4Macro,0,256*sizeof(int)); - memset(ex5Macro,0,256*sizeof(int)); - memset(ex6Macro,0,256*sizeof(int)); - memset(ex7Macro,0,256*sizeof(int)); - memset(ex8Macro,0,256*sizeof(int)); - } + volMacro("vol",15,true), + arpMacro("arp"), + dutyMacro("duty",3), + waveMacro("wave",63), + pitchMacro("pitch"), + ex1Macro("ex1"), + ex2Macro("ex2"), + ex3Macro("ex3"), + algMacro("alg"), + fbMacro("fb"), + fmsMacro("fms"), + fms2Macro("fms2"), + amsMacro("ams"), + ams2Macro("ams2"), + panLMacro("panL"), + panRMacro("panR"), + phaseResetMacro("phaseReset"), + ex4Macro("ex4"), + ex5Macro("ex5"), + ex6Macro("ex6"), + ex7Macro("ex7"), + ex8Macro("ex8") {} }; struct DivInstrumentGB { @@ -540,6 +415,13 @@ struct DivInstrument { */ void putInsData(SafeWriter* w); + /** + * save the macro to a SafeWriter. + * @param m the macro. + * @param w the SafeWriter in question. + */ + void putMacroData(DivInstrumentMacro m, SafeWriter* w); + /** * read instrument data in .fui format. * @param reader the reader. @@ -548,6 +430,15 @@ struct DivInstrument { */ DivDataErrors readInsData(SafeReader& reader, short version); + /** + * read macro data in .fui format. + * @param m the macro. + * @param reader the reader. + * @param version the format version. + * @return a DivDataErrors. + */ + void readMacroData(DivInstrumentMacro& m, SafeReader& reader, short version); + /** * save this instrument to a file. * @param path file path. diff --git a/src/engine/macroInt.cpp b/src/engine/macroInt.cpp index d74b59a6..9a878942 100644 --- a/src/engine/macroInt.cpp +++ b/src/engine/macroInt.cpp @@ -20,85 +20,39 @@ #include "macroInt.h" #include "instrument.h" -#define doMacro(finished,had,has,val,pos,source,sourceLen,sourceLoop,sourceRel) \ - if (finished) finished=false; \ - if (had!=has) { \ - finished=true; \ - } \ - had=has; \ - if (has) { \ - val=source[pos++]; \ - if (sourceRel>=0 && pos>sourceRel && !released) { \ - if (sourceLoop=0 && sourceLoop=sourceLen) { \ - if (sourceLoop=0 && (sourceLoop>=sourceRel || sourceRel>=sourceLen)) { \ - pos=sourceLoop; \ - } else { \ - has=false; \ - } \ - } \ +void DivMacroStruct::doMacro(DivInstrumentMacro& source, bool released) { + if (finished) finished=false; + if (had!=has) { + finished=true; } + had=has; + if (has) { + val=source.val[pos++]; + if (source.rel>=0 && pos>source.rel && !released) { + if (source.loop=0 && source.loop=source.len) { + if (source.loop=0 && (source.loop>=source.rel || source.rel>=source.len)) { + pos=source.loop; + } else { + has=false; + } + } + } +} // CPU hell void DivMacroInt::next() { if (ins==NULL) return; - - doMacro(finishedVol,hadVol,hasVol,vol,volPos,ins->std.volMacro,ins->std.volMacroLen,ins->std.volMacroLoop,ins->std.volMacroRel); - doMacro(finishedArp,hadArp,hasArp,arp,arpPos,ins->std.arpMacro,ins->std.arpMacroLen,ins->std.arpMacroLoop,ins->std.arpMacroRel); - doMacro(finishedDuty,hadDuty,hasDuty,duty,dutyPos,ins->std.dutyMacro,ins->std.dutyMacroLen,ins->std.dutyMacroLoop,ins->std.dutyMacroRel); - doMacro(finishedWave,hadWave,hasWave,wave,wavePos,ins->std.waveMacro,ins->std.waveMacroLen,ins->std.waveMacroLoop,ins->std.waveMacroRel); - - doMacro(finishedPitch,hadPitch,hasPitch,pitch,pitchPos,ins->std.pitchMacro,ins->std.pitchMacroLen,ins->std.pitchMacroLoop,ins->std.pitchMacroRel); - doMacro(finishedEx1,hadEx1,hasEx1,ex1,ex1Pos,ins->std.ex1Macro,ins->std.ex1MacroLen,ins->std.ex1MacroLoop,ins->std.ex1MacroRel); - doMacro(finishedEx2,hadEx2,hasEx2,ex2,ex2Pos,ins->std.ex2Macro,ins->std.ex2MacroLen,ins->std.ex2MacroLoop,ins->std.ex2MacroRel); - doMacro(finishedEx3,hadEx3,hasEx3,ex3,ex3Pos,ins->std.ex3Macro,ins->std.ex3MacroLen,ins->std.ex3MacroLoop,ins->std.ex3MacroRel); - - doMacro(finishedAlg,hadAlg,hasAlg,alg,algPos,ins->std.algMacro,ins->std.algMacroLen,ins->std.algMacroLoop,ins->std.algMacroRel); - doMacro(finishedFb,hadFb,hasFb,fb,fbPos,ins->std.fbMacro,ins->std.fbMacroLen,ins->std.fbMacroLoop,ins->std.fbMacroRel); - doMacro(finishedFms,hadFms,hasFms,fms,fmsPos,ins->std.fmsMacro,ins->std.fmsMacroLen,ins->std.fmsMacroLoop,ins->std.fmsMacroRel); - doMacro(finishedAms,hadAms,hasAms,ams,amsPos,ins->std.amsMacro,ins->std.amsMacroLen,ins->std.amsMacroLoop,ins->std.amsMacroRel); - - doMacro(finishedPanL,hadPanL,hasPanL,panL,panLPos,ins->std.panLMacro,ins->std.panLMacroLen,ins->std.panLMacroLoop,ins->std.panLMacroRel); - doMacro(finishedPanR,hadPanR,hasPanR,panR,panRPos,ins->std.panRMacro,ins->std.panRMacroLen,ins->std.panRMacroLoop,ins->std.panRMacroRel); - doMacro(finishedPhaseReset,hadPhaseReset,hasPhaseReset,phaseReset,phaseResetPos,ins->std.phaseResetMacro,ins->std.phaseResetMacroLen,ins->std.phaseResetMacroLoop,ins->std.phaseResetMacroRel); - doMacro(finishedEx4,hadEx4,hasEx4,ex4,ex4Pos,ins->std.ex4Macro,ins->std.ex4MacroLen,ins->std.ex4MacroLoop,ins->std.ex4MacroRel); - doMacro(finishedEx5,hadEx5,hasEx5,ex5,ex5Pos,ins->std.ex5Macro,ins->std.ex5MacroLen,ins->std.ex5MacroLoop,ins->std.ex5MacroRel); - doMacro(finishedEx6,hadEx6,hasEx6,ex6,ex6Pos,ins->std.ex6Macro,ins->std.ex6MacroLen,ins->std.ex6MacroLoop,ins->std.ex6MacroRel); - doMacro(finishedEx7,hadEx7,hasEx7,ex7,ex7Pos,ins->std.ex7Macro,ins->std.ex7MacroLen,ins->std.ex7MacroLoop,ins->std.ex7MacroRel); - doMacro(finishedEx8,hadEx8,hasEx8,ex8,ex8Pos,ins->std.ex8Macro,ins->std.ex8MacroLen,ins->std.ex8MacroLoop,ins->std.ex8MacroRel); - - for (int i=0; i<4; i++) { - DivInstrumentSTD::OpMacro& m=ins->std.opMacros[i]; - IntOp& o=op[i]; - doMacro(o.finishedAm,o.hadAm,o.hasAm,o.am,o.amPos,m.amMacro,m.amMacroLen,m.amMacroLoop,m.amMacroRel); - doMacro(o.finishedAr,o.hadAr,o.hasAr,o.ar,o.arPos,m.arMacro,m.arMacroLen,m.arMacroLoop,m.arMacroRel); - doMacro(o.finishedDr,o.hadDr,o.hasDr,o.dr,o.drPos,m.drMacro,m.drMacroLen,m.drMacroLoop,m.drMacroRel); - doMacro(o.finishedMult,o.hadMult,o.hasMult,o.mult,o.multPos,m.multMacro,m.multMacroLen,m.multMacroLoop,m.multMacroRel); - - doMacro(o.finishedRr,o.hadRr,o.hasRr,o.rr,o.rrPos,m.rrMacro,m.rrMacroLen,m.rrMacroLoop,m.rrMacroRel); - doMacro(o.finishedSl,o.hadSl,o.hasSl,o.sl,o.slPos,m.slMacro,m.slMacroLen,m.slMacroLoop,m.slMacroRel); - doMacro(o.finishedTl,o.hadTl,o.hasTl,o.tl,o.tlPos,m.tlMacro,m.tlMacroLen,m.tlMacroLoop,m.tlMacroRel); - doMacro(o.finishedDt2,o.hadDt2,o.hasDt2,o.dt2,o.dt2Pos,m.dt2Macro,m.dt2MacroLen,m.dt2MacroLoop,m.dt2MacroRel); - - doMacro(o.finishedRs,o.hadRs,o.hasRs,o.rs,o.rsPos,m.rsMacro,m.rsMacroLen,m.rsMacroLoop,m.rsMacroRel); - doMacro(o.finishedDt,o.hadDt,o.hasDt,o.dt,o.dtPos,m.dtMacro,m.dtMacroLen,m.dtMacroLoop,m.dtMacroRel); - doMacro(o.finishedD2r,o.hadD2r,o.hasD2r,o.d2r,o.d2rPos,m.d2rMacro,m.d2rMacroLen,m.d2rMacroLoop,m.d2rMacroRel); - doMacro(o.finishedSsg,o.hadSsg,o.hasSsg,o.ssg,o.ssgPos,m.ssgMacro,m.ssgMacroLen,m.ssgMacroLoop,m.ssgMacroRel); - - doMacro(o.finishedDam,o.hadDam,o.hasDam,o.dam,o.damPos,m.damMacro,m.damMacroLen,m.damMacroLoop,m.damMacroRel); - doMacro(o.finishedDvb,o.hadDvb,o.hasDvb,o.dvb,o.dvbPos,m.dvbMacro,m.dvbMacroLen,m.dvbMacroLoop,m.dvbMacroRel); - doMacro(o.finishedEgt,o.hadEgt,o.hasEgt,o.egt,o.egtPos,m.egtMacro,m.egtMacroLen,m.egtMacroLoop,m.egtMacroRel); - doMacro(o.finishedKsl,o.hadKsl,o.hasKsl,o.ksl,o.kslPos,m.kslMacro,m.kslMacroLen,m.kslMacroLoop,m.kslMacroRel); - - doMacro(o.finishedSus,o.hadSus,o.hasSus,o.sus,o.susPos,m.susMacro,m.susMacroLen,m.susMacroLoop,m.susMacroRel); - doMacro(o.finishedVib,o.hadVib,o.hasVib,o.vib,o.vibPos,m.vibMacro,m.vibMacroLen,m.vibMacroLoop,m.vibMacroRel); - doMacro(o.finishedWs,o.hadWs,o.hasWs,o.ws,o.wsPos,m.wsMacro,m.wsMacroLen,m.wsMacroLoop,m.wsMacroRel); - doMacro(o.finishedKsr,o.hadKsr,o.hasKsr,o.ksr,o.ksrPos,m.ksrMacro,m.ksrMacroLen,m.ksrMacroLoop,m.ksrMacroRel); + // Run macros + if (!macroList.empty()) { + for (std::list::iterator iter = macroList.begin(); iter!= macroList.end(); iter++) { + iter->doMacro(released); + } } } @@ -108,312 +62,275 @@ void DivMacroInt::release() { void DivMacroInt::init(DivInstrument* which) { ins=which; - volPos=0; - arpPos=0; - dutyPos=0; - wavePos=0; - pitchPos=0; - ex1Pos=0; - ex2Pos=0; - ex3Pos=0; - algPos=0; - fbPos=0; - fmsPos=0; - amsPos=0; - panLPos=0; - panRPos=0; - phaseResetPos=0; - ex4Pos=0; - ex5Pos=0; - ex6Pos=0; - ex7Pos=0; - ex8Pos=0; + macroList.clear(); + // initialize common macros + vol.init(); + arp.init(); + duty.init(); + wave.init(); + pitch.init(); + ex1.init(); + ex2.init(); + ex3.init(); + alg.init(); + fb.init(); + fms.init(); + ams.init(); + fms2.init(); + ams2.init(); + panL.init(); + panR.init(); + phaseReset.init(); + ex4.init(); + ex5.init(); + ex6.init(); + ex7.init(); + ex8.init(); released=false; - hasVol=false; - hasArp=false; - hasDuty=false; - hasWave=false; - hasPitch=false; - hasEx1=false; - hasEx2=false; - hasEx3=false; - hasAlg=false; - hasFb=false; - hasFms=false; - hasAms=false; - hasPanL=false; - hasPanR=false; - hasPhaseReset=false; - hasEx4=false; - hasEx5=false; - hasEx6=false; - hasEx7=false; - hasEx8=false; - - hadVol=false; - hadArp=false; - hadDuty=false; - hadWave=false; - hadPitch=false; - hadEx1=false; - hadEx2=false; - hadEx3=false; - hadAlg=false; - hadFb=false; - hadFms=false; - hadAms=false; - hadPanL=false; - hadPanR=false; - hadPhaseReset=false; - hadEx4=false; - hadEx5=false; - hadEx6=false; - hadEx7=false; - hadEx8=false; - - willVol=false; - willArp=false; - willDuty=false; - willWave=false; - willPitch=false; - willEx1=false; - willEx2=false; - willEx3=false; - willAlg=false; - willFb=false; - willFms=false; - willAms=false; - willPanL=false; - willPanR=false; - willPhaseReset=false; - willEx4=false; - willEx5=false; - willEx6=false; - willEx7=false; - willEx8=false; - + // initialize FM operator macro op[0]=IntOp(); op[1]=IntOp(); op[2]=IntOp(); op[3]=IntOp(); - arpMode=false; + // initialize wavesynth macro + ws=IntWS(); if (ins==NULL) return; - if (ins->std.volMacroLen>0) { - hadVol=true; - hasVol=true; - willVol=true; + // prepare common macro + if (ins->std.volMacro.len>0) { + macroList.push_back(DivMacroExecList(vol,ins->std.volMacro)); + vol.prepare(&ins->std.volMacro); } - if (ins->std.arpMacroLen>0) { - hadArp=true; - hasArp=true; - willArp=true; + if (ins->std.arpMacro.len>0) { + macroList.push_back(DivMacroExecList(arp,ins->std.arpMacro)); + arp.prepare(&ins->std.arpMacro); } - if (ins->std.dutyMacroLen>0) { - hadDuty=true; - hasDuty=true; - willDuty=true; + if (ins->std.dutyMacro.len>0) { + macroList.push_back(DivMacroExecList(duty,ins->std.dutyMacro)); + duty.prepare(&ins->std.dutyMacro); } - if (ins->std.waveMacroLen>0) { - hadWave=true; - hasWave=true; - willWave=true; + if (ins->std.waveMacro.len>0) { + macroList.push_back(DivMacroExecList(wave,ins->std.waveMacro)); + wave.prepare(&ins->std.waveMacro); } - if (ins->std.pitchMacroLen>0) { - hadPitch=true; - hasPitch=true; - willPitch=true; + if (ins->std.pitchMacro.len>0) { + macroList.push_back(DivMacroExecList(pitch,ins->std.pitchMacro)); + pitch.prepare(&ins->std.pitchMacro); } - if (ins->std.ex1MacroLen>0) { - hadEx1=true; - hasEx1=true; - willEx1=true; + if (ins->std.ex1Macro.len>0) { + macroList.push_back(DivMacroExecList(ex1,ins->std.ex1Macro)); + ex1.prepare(&ins->std.ex1Macro); } - if (ins->std.ex2MacroLen>0) { - hadEx2=true; - hasEx2=true; - willEx2=true; + if (ins->std.ex2Macro.len>0) { + macroList.push_back(DivMacroExecList(ex2,ins->std.ex2Macro)); + ex2.prepare(&ins->std.ex2Macro); } - if (ins->std.ex3MacroLen>0) { - hadEx3=true; - hasEx3=true; - willEx3=true; + if (ins->std.ex3Macro.len>0) { + macroList.push_back(DivMacroExecList(ex3,ins->std.ex3Macro)); + ex3.prepare(&ins->std.ex3Macro); } - if (ins->std.algMacroLen>0) { - hadAlg=true; - hasAlg=true; - willAlg=true; + if (ins->std.algMacro.len>0) { + macroList.push_back(DivMacroExecList(alg,ins->std.algMacro)); + alg.prepare(&ins->std.algMacro); } - if (ins->std.fbMacroLen>0) { - hadFb=true; - hasFb=true; - willFb=true; + if (ins->std.fbMacro.len>0) { + macroList.push_back(DivMacroExecList(fb,ins->std.fbMacro)); + fb.prepare(&ins->std.fbMacro); } - if (ins->std.fmsMacroLen>0) { - hadFms=true; - hasFms=true; - willFms=true; + if (ins->std.fmsMacro.len>0) { + macroList.push_back(DivMacroExecList(fms,ins->std.fmsMacro)); + fms.prepare(&ins->std.fmsMacro); } - if (ins->std.amsMacroLen>0) { - hadAms=true; - hasAms=true; - willAms=true; + if (ins->std.fms2Macro.len>0) { + macroList.push_back(DivMacroExecList(fms2,ins->std.fms2Macro)); + fms2.prepare(&ins->std.fms2Macro); + } + if (ins->std.amsMacro.len>0) { + macroList.push_back(DivMacroExecList(ams,ins->std.amsMacro)); + ams.prepare(&ins->std.amsMacro); + } + if (ins->std.ams2Macro.len>0) { + macroList.push_back(DivMacroExecList(ams2,ins->std.ams2Macro)); + ams2.prepare(&ins->std.ams2Macro); } // TODO: other macros - if (ins->std.panLMacroLen>0) { - hadPanL=true; - hasPanL=true; - willPanL=true; + if (ins->std.panLMacro.len>0) { + macroList.push_back(DivMacroExecList(panL,ins->std.panLMacro)); + panL.prepare(&ins->std.panLMacro); } - if (ins->std.panRMacroLen>0) { - hadPanR=true; - hasPanR=true; - willPanR=true; + if (ins->std.panRMacro.len>0) { + macroList.push_back(DivMacroExecList(panR,ins->std.panRMacro)); + panR.prepare(&ins->std.panRMacro); } - if (ins->std.phaseResetMacroLen>0) { - hadPhaseReset=true; - hasPhaseReset=true; - willPhaseReset=true; + if (ins->std.phaseResetMacro.len>0) { + macroList.push_back(DivMacroExecList(phaseReset,ins->std.phaseResetMacro)); + phaseReset.prepare(&ins->std.phaseResetMacro); } - if (ins->std.ex4MacroLen>0) { - hadEx4=true; - hasEx4=true; - willEx4=true; + if (ins->std.ex4Macro.len>0) { + macroList.push_back(DivMacroExecList(ex4,ins->std.ex4Macro)); + ex4.prepare(&ins->std.ex4Macro); } - if (ins->std.ex5MacroLen>0) { - hadEx5=true; - hasEx5=true; - willEx5=true; + if (ins->std.ex5Macro.len>0) { + macroList.push_back(DivMacroExecList(ex5,ins->std.ex5Macro)); + ex5.prepare(&ins->std.ex5Macro); } - if (ins->std.ex6MacroLen>0) { - hadEx6=true; - hasEx6=true; - willEx6=true; + if (ins->std.ex6Macro.len>0) { + macroList.push_back(DivMacroExecList(ex6,ins->std.ex6Macro)); + ex6.prepare(&ins->std.ex6Macro); } - if (ins->std.ex7MacroLen>0) { - hadEx7=true; - hasEx7=true; - willEx7=true; + if (ins->std.ex7Macro.len>0) { + macroList.push_back(DivMacroExecList(ex7,ins->std.ex7Macro)); + ex7.prepare(&ins->std.ex7Macro); } - if (ins->std.ex8MacroLen>0) { - hadEx8=true; - hasEx8=true; - willEx8=true; - } - - if (ins->std.arpMacroMode) { - arpMode=true; + if (ins->std.ex8Macro.len>0) { + macroList.push_back(DivMacroExecList(ex8,ins->std.ex8Macro)); + ex8.prepare(&ins->std.ex8Macro); } + // prepare FM operator macros for (int i=0; i<4; i++) { DivInstrumentSTD::OpMacro& m=ins->std.opMacros[i]; IntOp& o=op[i]; - - if (m.amMacroLen>0) { - o.hadAm=true; - o.hasAm=true; - o.willAm=true; + if (m.amMacro.len>0) { + macroList.push_back(DivMacroExecList(o.am,m.amMacro)); + o.am.prepare(&m.amMacro); } - if (m.arMacroLen>0) { - o.hadAr=true; - o.hasAr=true; - o.willAr=true; + if (m.arMacro.len>0) { + macroList.push_back(DivMacroExecList(o.ar,m.arMacro)); + o.ar.prepare(&m.arMacro); } - if (m.drMacroLen>0) { - o.hadDr=true; - o.hasDr=true; - o.willDr=true; + if (m.drMacro.len>0) { + macroList.push_back(DivMacroExecList(o.dr,m.drMacro)); + o.dr.prepare(&m.drMacro); } - if (m.multMacroLen>0) { - o.hadMult=true; - o.hasMult=true; - o.willMult=true; + if (m.multMacro.len>0) { + macroList.push_back(DivMacroExecList(o.mult,m.multMacro)); + o.mult.prepare(&m.multMacro); } - if (m.rrMacroLen>0) { - o.hadRr=true; - o.hasRr=true; - o.willRr=true; + if (m.rrMacro.len>0) { + macroList.push_back(DivMacroExecList(o.rr,m.rrMacro)); + o.rr.prepare(&m.rrMacro); } - if (m.slMacroLen>0) { - o.hadSl=true; - o.hasSl=true; - o.willSl=true; + if (m.slMacro.len>0) { + macroList.push_back(DivMacroExecList(o.sl,m.slMacro)); + o.sl.prepare(&m.slMacro); } - if (m.tlMacroLen>0) { - o.hadTl=true; - o.hasTl=true; - o.willTl=true; + if (m.tlMacro.len>0) { + macroList.push_back(DivMacroExecList(o.tl,m.tlMacro)); + o.tl.prepare(&m.tlMacro); } - if (m.dt2MacroLen>0) { - o.hadDt2=true; - o.hasDt2=true; - o.willDt2=true; + if (m.dt2Macro.len>0) { + macroList.push_back(DivMacroExecList(o.dt2,m.dt2Macro)); + o.dt2.prepare(&m.dt2Macro); } - if (m.rsMacroLen>0) { - o.hadRs=true; - o.hasRs=true; - o.willRs=true; + if (m.rsMacro.len>0) { + macroList.push_back(DivMacroExecList(o.rs,m.rsMacro)); + o.rs.prepare(&m.rsMacro); } - if (m.dtMacroLen>0) { - o.hadDt=true; - o.hasDt=true; - o.willDt=true; + if (m.dtMacro.len>0) { + macroList.push_back(DivMacroExecList(o.dt,m.dtMacro)); + o.dt.prepare(&m.dtMacro); } - if (m.d2rMacroLen>0) { - o.hadD2r=true; - o.hasD2r=true; - o.willD2r=true; + if (m.d2rMacro.len>0) { + macroList.push_back(DivMacroExecList(o.d2r,m.d2rMacro)); + o.d2r.prepare(&m.d2rMacro); } - if (m.ssgMacroLen>0) { - o.hadSsg=true; - o.hasSsg=true; - o.willSsg=true; + if (m.ssgMacro.len>0) { + macroList.push_back(DivMacroExecList(o.ssg,m.ssgMacro)); + o.ssg.prepare(&m.ssgMacro); } - if (m.damMacroLen>0) { - o.hadDam=true; - o.hasDam=true; - o.willDam=true; + if (m.damMacro.len>0) { + macroList.push_back(DivMacroExecList(o.dam,m.damMacro)); + o.dam.prepare(&m.damMacro); } - if (m.dvbMacroLen>0) { - o.hadDvb=true; - o.hasDvb=true; - o.willDvb=true; + if (m.dvbMacro.len>0) { + macroList.push_back(DivMacroExecList(o.dvb,m.dvbMacro)); + o.dvb.prepare(&m.dvbMacro); } - if (m.egtMacroLen>0) { - o.hadEgt=true; - o.hasEgt=true; - o.willEgt=true; + if (m.egtMacro.len>0) { + macroList.push_back(DivMacroExecList(o.egt,m.egtMacro)); + o.egt.prepare(&m.egtMacro); } - if (m.kslMacroLen>0) { - o.hadKsl=true; - o.hasKsl=true; - o.willKsl=true; + if (m.kslMacro.len>0) { + macroList.push_back(DivMacroExecList(o.ksl,m.kslMacro)); + o.ksl.prepare(&m.kslMacro); } - if (m.susMacroLen>0) { - o.hadSus=true; - o.hasSus=true; - o.willSus=true; + if (m.susMacro.len>0) { + macroList.push_back(DivMacroExecList(o.sus,m.susMacro)); + o.sus.prepare(&m.susMacro); } - if (m.vibMacroLen>0) { - o.hadVib=true; - o.hasVib=true; - o.willVib=true; + if (m.vibMacro.len>0) { + macroList.push_back(DivMacroExecList(o.vib,m.vibMacro)); + o.vib.prepare(&m.vibMacro); } - if (m.wsMacroLen>0) { - o.hadWs=true; - o.hasWs=true; - o.willWs=true; + if (m.wsMacro.len>0) { + macroList.push_back(DivMacroExecList(o.ws,m.wsMacro)); + o.ws.prepare(&m.wsMacro); } - if (m.ksrMacroLen>0) { - o.hadKsr=true; - o.hasKsr=true; - o.willKsr=true; + if (m.ksrMacro.len>0) { + macroList.push_back(DivMacroExecList(o.ksr,m.ksrMacro)); + o.ksr.prepare(&m.ksrMacro); + } + } + + // prepare wavesynth macros + if (ins->std.ws.wave1Macro.len>0) { + macroList.push_back(DivMacroExecList(ws.wave1,ins->std.ws.wave1Macro)); + ws.wave1.prepare(&ins->std.ws.wave1Macro); + } + if (ins->std.ws.wave2Macro.len>0) { + macroList.push_back(DivMacroExecList(ws.wave2,ins->std.ws.wave2Macro)); + ws.wave2.prepare(&ins->std.ws.wave2Macro); + } + if (ins->std.ws.rateDividerMacro.len>0) { + macroList.push_back(DivMacroExecList(ws.rateDivider,ins->std.ws.rateDividerMacro)); + ws.rateDivider.prepare(&ins->std.ws.rateDividerMacro); + } + if (ins->std.ws.effectMacro.len>0) { + macroList.push_back(DivMacroExecList(ws.effect,ins->std.ws.effectMacro)); + ws.effect.prepare(&ins->std.ws.effectMacro); + } + if (ins->std.ws.oneShotMacro.len>0) { + macroList.push_back(DivMacroExecList(ws.oneShot,ins->std.ws.oneShotMacro)); + ws.oneShot.prepare(&ins->std.ws.oneShotMacro); + } + if (ins->std.ws.enabledMacro.len>0) { + macroList.push_back(DivMacroExecList(ws.enabled,ins->std.ws.enabledMacro)); + ws.enabled.prepare(&ins->std.ws.enabledMacro); + } + if (ins->std.ws.globalMacro.len>0) { + macroList.push_back(DivMacroExecList(ws.global,ins->std.ws.globalMacro)); + ws.global.prepare(&ins->std.ws.globalMacro); + } + if (ins->std.ws.speedMacro.len>0) { + macroList.push_back(DivMacroExecList(ws.speed,ins->std.ws.speedMacro)); + ws.speed.prepare(&ins->std.ws.speedMacro); + } + if (ins->std.ws.param1Macro.len>0) { + macroList.push_back(DivMacroExecList(ws.param1,ins->std.ws.param1Macro)); + ws.param1.prepare(&ins->std.ws.param1Macro); + } + if (ins->std.ws.param2Macro.len>0) { + macroList.push_back(DivMacroExecList(ws.param2,ins->std.ws.param2Macro)); + ws.param2.prepare(&ins->std.ws.param2Macro); + } + if (ins->std.ws.param3Macro.len>0) { + macroList.push_back(DivMacroExecList(ws.param3,ins->std.ws.param3Macro)); + ws.param3.prepare(&ins->std.ws.param3Macro); + } + if (ins->std.ws.param4Macro.len>0) { + macroList.push_back(DivMacroExecList(ws.param4,ins->std.ws.param4Macro)); + ws.param4.prepare(&ins->std.ws.param4Macro); + } + if (!macroList.empty()) { + for (std::list::iterator iter = macroList.begin(); iter!= macroList.end(); iter++) { + iter->prepare(); } } } diff --git a/src/engine/macroInt.h b/src/engine/macroInt.h index d5e6fd14..d7236805 100644 --- a/src/engine/macroInt.h +++ b/src/engine/macroInt.h @@ -21,127 +21,115 @@ #define _MACROINT_H #include "instrument.h" +#include + +struct DivMacroStruct { + DivInstrumentMacro* source; + int pos; + int val; + bool has, had, finished, will; + unsigned int mode; + void doMacro(DivInstrumentMacro& source, bool released); + void init() { + source=NULL; + pos=mode=0; + has=had=will=false; + } + void prepare(DivInstrumentMacro* s) { + if (s!=NULL) { + source=s; + has=had=will=true; + mode=source->mode; + } + } + DivMacroStruct(): + source(NULL), + pos(0), + val(0), + has(false), + had(false), + finished(false), + will(false), + mode(0) {} +}; + +struct DivMacroExecList { + DivMacroStruct& macro; + DivInstrumentMacro& source; + void prepare() { + macro.prepare(&source); + } + void doMacro(bool released) { + macro.doMacro(source, released); + } + DivMacroExecList(DivMacroStruct &m, DivInstrumentMacro& s): + macro(m), + source(s) {} +}; class DivMacroInt { DivInstrument* ins; - int volPos, arpPos, dutyPos, wavePos, pitchPos, ex1Pos, ex2Pos, ex3Pos; - int algPos, fbPos, fmsPos, amsPos; - int panLPos, panRPos, phaseResetPos, ex4Pos, ex5Pos, ex6Pos, ex7Pos, ex8Pos; + std::list macroList; bool released; public: - int vol; - int arp; - int duty, wave, pitch, ex1, ex2, ex3; - int alg, fb, fms, ams; - int panL, panR, phaseReset, ex4, ex5, ex6, ex7, ex8; - bool hasVol, hasArp, hasDuty, hasWave, hasPitch, hasEx1, hasEx2, hasEx3, hasAlg, hasFb, hasFms, hasAms; - bool hasPanL, hasPanR, hasPhaseReset, hasEx4, hasEx5, hasEx6, hasEx7, hasEx8; - bool hadVol, hadArp, hadDuty, hadWave, hadPitch, hadEx1, hadEx2, hadEx3, hadAlg, hadFb, hadFms, hadAms; - bool hadPanL, hadPanR, hadPhaseReset, hadEx4, hadEx5, hadEx6, hadEx7, hadEx8; - bool finishedVol, finishedArp, finishedDuty, finishedWave, finishedPitch, finishedEx1, finishedEx2, finishedEx3; - bool finishedAlg, finishedFb, finishedFms, finishedAms; - bool finishedPanL, finishedPanR, finishedPhaseReset, finishedEx4, finishedEx5, finishedEx6, finishedEx7, finishedEx8; - bool willVol, willArp, willDuty, willWave, willPitch, willEx1, willEx2, willEx3, willAlg, willFb, willFms, willAms; - bool willPanL, willPanR, willPhaseReset, willEx4, willEx5, willEx6, willEx7, willEx8; - bool arpMode; + // common macro + DivMacroStruct vol; + DivMacroStruct arp; + DivMacroStruct duty, wave, pitch, ex1, ex2, ex3; + DivMacroStruct alg, fb, fms, fms2, ams, ams2; + DivMacroStruct panL, panR, phaseReset, ex4, ex5, ex6, ex7, ex8; + + // FM operator macro struct IntOp { - int amPos, arPos, drPos, multPos; - int rrPos, slPos, tlPos, dt2Pos; - int rsPos, dtPos, d2rPos, ssgPos; - int damPos, dvbPos, egtPos, kslPos; - int susPos, vibPos, wsPos, ksrPos; - - int am, ar, dr, mult; - int rr, sl, tl, dt2; - int rs, dt, d2r, ssg; - int dam, dvb, egt, ksl; - int sus, vib, ws, ksr; - - bool hasAm, hasAr, hasDr, hasMult; - bool hasRr, hasSl, hasTl, hasDt2; - bool hasRs, hasDt, hasD2r, hasSsg; - bool hasDam, hasDvb, hasEgt, hasKsl; - bool hasSus, hasVib, hasWs, hasKsr; - - bool hadAm, hadAr, hadDr, hadMult; - bool hadRr, hadSl, hadTl, hadDt2; - bool hadRs, hadDt, hadD2r, hadSsg; - bool hadDam, hadDvb, hadEgt, hadKsl; - bool hadSus, hadVib, hadWs, hadKsr; - - bool finishedAm, finishedAr, finishedDr, finishedMult; - bool finishedRr, finishedSl, finishedTl, finishedDt2; - bool finishedRs, finishedDt, finishedD2r, finishedSsg; - bool finishedDam, finishedDvb, finishedEgt, finishedKsl; - bool finishedSus, finishedVib, finishedWs, finishedKsr; - - bool willAm, willAr, willDr, willMult; - bool willRr, willSl, willTl, willDt2; - bool willRs, willDt, willD2r, willSsg; - bool willDam, willDvb, willEgt, willKsl; - bool willSus, willVib, willWs, willKsr; + DivMacroStruct am, ar, dr, mult; + DivMacroStruct rr, sl, tl, dt2; + DivMacroStruct rs, dt, d2r, ssg; + DivMacroStruct dam, dvb, egt, ksl; + DivMacroStruct sus, vib, ws, ksr; IntOp(): - amPos(0), - arPos(0), - drPos(0), - multPos(0), - rrPos(0), - slPos(0), - tlPos(0), - dt2Pos(0), - rsPos(0), - dtPos(0), - d2rPos(0), - ssgPos(0), - damPos(0), - dvbPos(0), - egtPos(0), - kslPos(0), - susPos(0), - vibPos(0), - wsPos(0), - ksrPos(0), - am(0), - ar(0), - dr(0), - mult(0), - rr(0), - sl(0), - tl(0), - dt2(0), - rs(0), - dt(0), - d2r(0), - ssg(0), - dam(0), - dvb(0), - egt(0), - ksl(0), - sus(0), - vib(0), - ws(0), - ksr(0), - hasAm(false), hasAr(false), hasDr(false), hasMult(false), - hasRr(false), hasSl(false), hasTl(false), hasDt2(false), - hasRs(false), hasDt(false), hasD2r(false), hasSsg(false), - hasDam(false), hasDvb(false), hasEgt(false), hasKsl(false), - hasSus(false), hasVib(false), hasWs(false), hasKsr(false), - hadAm(false), hadAr(false), hadDr(false), hadMult(false), - hadRr(false), hadSl(false), hadTl(false), hadDt2(false), - hadRs(false), hadDt(false), hadD2r(false), hadSsg(false), - hadDam(false), hadDvb(false), hadEgt(false), hadKsl(false), - hadSus(false), hadVib(false), hadWs(false), hadKsr(false), - finishedAm(false), finishedAr(false), finishedDr(false), finishedMult(false), - finishedRr(false), finishedSl(false), finishedTl(false), finishedDt2(false), - finishedRs(false), finishedDt(false), finishedD2r(false), finishedSsg(false), - finishedDam(false), finishedDvb(false), finishedEgt(false), finishedKsl(false), - finishedSus(false), finishedVib(false), finishedWs(false), finishedKsr(false), - willAm(false), willAr(false), willDr(false), willMult(false), - willRr(false), willSl(false), willTl(false), willDt2(false), - willRs(false), willDt(false), willD2r(false), willSsg(false), - willDam(false), willDvb(false), willEgt(false), willKsl(false), - willSus(false), willVib(false), willWs(false), willKsr(false) {} + am(), + ar(), + dr(), + mult(), + rr(), + sl(), + tl(), + dt2(), + rs(), + dt(), + d2r(), + ssg(), + dam(), + dvb(), + egt(), + ksl(), + sus(), + vib(), + ws(), + ksr() {} } op[4]; + + // wavesynth macro + struct IntWS { + DivMacroStruct wave1, wave2; + DivMacroStruct rateDivider; + DivMacroStruct effect; + DivMacroStruct oneShot, enabled, global; + DivMacroStruct speed, param1, param2, param3, param4; + IntWS(): + wave1(), + wave2(), + rateDivider(), + effect(), + oneShot(), + enabled(), + global(), + speed(), + param1(), + param2(), + param3(), + param4() {} + } ws; /** * trigger macro release. @@ -167,128 +155,29 @@ class DivMacroInt { DivMacroInt(): ins(NULL), - volPos(0), - arpPos(0), - dutyPos(0), - wavePos(0), - pitchPos(0), - ex1Pos(0), - ex2Pos(0), - ex3Pos(0), - algPos(0), - fbPos(0), - fmsPos(0), - amsPos(0), - panLPos(0), - panRPos(0), - phaseResetPos(0), - ex4Pos(0), - ex5Pos(0), - ex6Pos(0), - ex7Pos(0), - ex8Pos(0), released(false), - vol(0), - arp(0), - duty(0), - wave(0), - pitch(0), - ex1(0), - ex2(0), - ex3(0), - alg(0), - fb(0), - fms(0), - ams(0), - panL(0), - panR(0), - phaseReset(0), - ex4(0), - ex5(0), - ex6(0), - ex7(0), - ex8(0), - hasVol(false), - hasArp(false), - hasDuty(false), - hasWave(false), - hasPitch(false), - hasEx1(false), - hasEx2(false), - hasEx3(false), - hasAlg(false), - hasFb(false), - hasFms(false), - hasAms(false), - hasPanL(false), - hasPanR(false), - hasPhaseReset(false), - hasEx4(false), - hasEx5(false), - hasEx6(false), - hasEx7(false), - hasEx8(false), - hadVol(false), - hadArp(false), - hadDuty(false), - hadWave(false), - hadPitch(false), - hadEx1(false), - hadEx2(false), - hadEx3(false), - hadAlg(false), - hadFb(false), - hadFms(false), - hadAms(false), - hadPanL(false), - hadPanR(false), - hadPhaseReset(false), - hadEx4(false), - hadEx5(false), - hadEx6(false), - hadEx7(false), - hadEx8(false), - finishedVol(false), - finishedArp(false), - finishedDuty(false), - finishedWave(false), - finishedPitch(false), - finishedEx1(false), - finishedEx2(false), - finishedEx3(false), - finishedAlg(false), - finishedFb(false), - finishedFms(false), - finishedAms(false), - finishedPanL(false), - finishedPanR(false), - finishedPhaseReset(false), - finishedEx4(false), - finishedEx5(false), - finishedEx6(false), - finishedEx7(false), - finishedEx8(false), - willVol(false), - willArp(false), - willDuty(false), - willWave(false), - willPitch(false), - willEx1(false), - willEx2(false), - willEx3(false), - willAlg(false), - willFb(false), - willFms(false), - willAms(false), - willPanL(false), - willPanR(false), - willPhaseReset(false), - willEx4(false), - willEx5(false), - willEx6(false), - willEx7(false), - willEx8(false), - arpMode(false) {} + vol(), + arp(), + duty(), + wave(), + pitch(), + ex1(), + ex2(), + ex3(), + alg(), + fb(), + fms(), + fms2(), + ams(), + ams2(), + panL(), + panR(), + phaseReset(), + ex4(), + ex5(), + ex6(), + ex7(), + ex8() {} }; #endif diff --git a/src/engine/platform/amiga.cpp b/src/engine/platform/amiga.cpp index e1bc8394..458c9329 100644 --- a/src/engine/platform/amiga.cpp +++ b/src/engine/platform/amiga.cpp @@ -147,8 +147,8 @@ void DivPlatformAmiga::acquire(short* bufL, short* bufR, size_t start, size_t le void DivPlatformAmiga::tick() { for (int i=0; i<4; i++) { chan[i].std.next(); - if (chan[i].std.hadVol) { - chan[i].outVol=((chan[i].vol%65)*MIN(64,chan[i].std.vol))>>6; + if (chan[i].std.vol.had) { + chan[i].outVol=((chan[i].vol%65)*MIN(64,chan[i].std.vol.val))>>6; } double off=1.0; if (chan[i].sample>=0 && chan[i].samplesong.sampleLen) { @@ -159,24 +159,24 @@ void DivPlatformAmiga::tick() { off=8363.0/(double)s->centerRate; } } - if (chan[i].std.hadArp) { + if (chan[i].std.arp.had) { if (!chan[i].inPorta) { - if (chan[i].std.arpMode) { - chan[i].baseFreq=round(off*NOTE_PERIODIC_NOROUND(chan[i].std.arp)); + if (chan[i].std.arp.mode) { + chan[i].baseFreq=round(off*NOTE_PERIODIC_NOROUND(chan[i].std.arp.val)); } else { - chan[i].baseFreq=round(off*NOTE_PERIODIC_NOROUND(chan[i].note+chan[i].std.arp)); + chan[i].baseFreq=round(off*NOTE_PERIODIC_NOROUND(chan[i].note+chan[i].std.arp.val)); } } chan[i].freqChanged=true; } else { - if (chan[i].std.arpMode && chan[i].std.finishedArp) { + if (chan[i].std.arp.mode && chan[i].std.arp.finished) { chan[i].baseFreq=round(off*NOTE_PERIODIC_NOROUND(chan[i].note)); chan[i].freqChanged=true; } } - if (chan[i].std.hadWave) { - if (chan[i].wave!=chan[i].std.wave) { - chan[i].wave=chan[i].std.wave; + if (chan[i].std.wave.had) { + if (chan[i].wave!=chan[i].std.wave.val) { + chan[i].wave=chan[i].std.wave.val; if (!chan[i].keyOff) chan[i].keyOn=true; } } @@ -252,13 +252,13 @@ int DivPlatformAmiga::dispatch(DivCommand c) { case DIV_CMD_VOLUME: if (chan[c.chan].vol!=c.value) { chan[c.chan].vol=c.value; - if (!chan[c.chan].std.hasVol) { + if (!chan[c.chan].std.vol.has) { chan[c.chan].outVol=c.value; } } break; case DIV_CMD_GET_VOLUME: - if (chan[c.chan].std.hasVol) { + if (chan[c.chan].std.vol.has) { return chan[c.chan].vol; } return chan[c.chan].outVol; @@ -315,7 +315,7 @@ int DivPlatformAmiga::dispatch(DivCommand c) { off=8363.0/(double)s->centerRate; } } - chan[c.chan].baseFreq=round(off*NOTE_PERIODIC_NOROUND(c.value+((chan[c.chan].std.willArp && !chan[c.chan].std.arpMode)?(chan[c.chan].std.arp-12):(0)))); + chan[c.chan].baseFreq=round(off*NOTE_PERIODIC_NOROUND(c.value+((chan[c.chan].std.arp.will && !chan[c.chan].std.arp.mode)?(chan[c.chan].std.arp.val-12):(0)))); chan[c.chan].freqChanged=true; chan[c.chan].note=c.value; break; diff --git a/src/engine/platform/arcade.cpp b/src/engine/platform/arcade.cpp index 7c465a51..41530a0c 100644 --- a/src/engine/platform/arcade.cpp +++ b/src/engine/platform/arcade.cpp @@ -220,8 +220,8 @@ void DivPlatformArcade::tick() { for (int i=0; i<8; i++) { chan[i].std.next(); - if (chan[i].std.hadVol) { - chan[i].outVol=(chan[i].vol*MIN(127,chan[i].std.vol))/127; + if (chan[i].std.vol.had) { + chan[i].outVol=(chan[i].vol*MIN(127,chan[i].std.vol.val))/127; for (int j=0; j<4; j++) { unsigned short baseAddr=chanOffs[i]|opOffs[j]; DivInstrumentFM::Operator& op=chan[i].state.op[j]; @@ -233,50 +233,50 @@ void DivPlatformArcade::tick() { } } - if (chan[i].std.hadArp) { + if (chan[i].std.arp.had) { if (!chan[i].inPorta) { - if (chan[i].std.arpMode) { - chan[i].baseFreq=NOTE_LINEAR(chan[i].std.arp); + if (chan[i].std.arp.mode) { + chan[i].baseFreq=NOTE_LINEAR(chan[i].std.arp.val); } else { - chan[i].baseFreq=NOTE_LINEAR(chan[i].note+(signed char)chan[i].std.arp); + chan[i].baseFreq=NOTE_LINEAR(chan[i].note+(signed char)chan[i].std.arp.val); } } chan[i].freqChanged=true; } else { - if (chan[i].std.arpMode && chan[i].std.finishedArp) { + if (chan[i].std.arp.mode && chan[i].std.arp.finished) { chan[i].baseFreq=NOTE_LINEAR(chan[i].note); chan[i].freqChanged=true; } } - if (chan[i].std.hadDuty) { - if (chan[i].std.duty>0) { - rWrite(0x0f,0x80|(0x20-chan[i].std.duty)); + if (chan[i].std.duty.had) { + if (chan[i].std.duty.val>0) { + rWrite(0x0f,0x80|(0x20-chan[i].std.duty.val)); } else { rWrite(0x0f,0); } } - if (chan[i].std.hadWave) { - rWrite(0x1b,chan[i].std.wave&3); + if (chan[i].std.wave.had) { + rWrite(0x1b,chan[i].std.wave.val&3); } - if (chan[i].std.hadEx1) { - amDepth=chan[i].std.ex1; + if (chan[i].std.ex1.had) { + amDepth=chan[i].std.ex1.val; immWrite(0x19,amDepth); } - if (chan[i].std.hadEx2) { - pmDepth=chan[i].std.ex2; + if (chan[i].std.ex2.had) { + pmDepth=chan[i].std.ex2.val; immWrite(0x19,0x80|pmDepth); } - if (chan[i].std.hadEx3) { - immWrite(0x18,chan[i].std.ex3); + if (chan[i].std.ex3.had) { + immWrite(0x18,chan[i].std.ex3.val); } - if (chan[i].std.hadAlg) { - chan[i].state.alg=chan[i].std.alg; + if (chan[i].std.alg.had) { + chan[i].state.alg=chan[i].std.alg.val; if (isMuted[i]) { rWrite(chanOffs[i]+ADDR_LR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3)); } else { @@ -296,72 +296,72 @@ void DivPlatformArcade::tick() { } } } - if (chan[i].std.hadFb) { - chan[i].state.fb=chan[i].std.fb; + if (chan[i].std.fb.had) { + chan[i].state.fb=chan[i].std.fb.val; if (isMuted[i]) { rWrite(chanOffs[i]+ADDR_LR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3)); } else { rWrite(chanOffs[i]+ADDR_LR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3)|((chan[i].chVolL&1)<<6)|((chan[i].chVolR&1)<<7)); } } - if (chan[i].std.hadFms) { - chan[i].state.fms=chan[i].std.fms; + if (chan[i].std.fms.had) { + chan[i].state.fms=chan[i].std.fms.val; rWrite(chanOffs[i]+ADDR_FMS_AMS,((chan[i].state.fms&7)<<4)|(chan[i].state.ams&3)); } - if (chan[i].std.hadAms) { - chan[i].state.ams=chan[i].std.ams; + if (chan[i].std.ams.had) { + chan[i].state.ams=chan[i].std.ams.val; rWrite(chanOffs[i]+ADDR_FMS_AMS,((chan[i].state.fms&7)<<4)|(chan[i].state.ams&3)); } for (int j=0; j<4; j++) { unsigned short baseAddr=chanOffs[i]|opOffs[j]; DivInstrumentFM::Operator& op=chan[i].state.op[j]; DivMacroInt::IntOp& m=chan[i].std.op[j]; - if (m.hadAm) { - op.am=m.am; + if (m.am.had) { + op.am=m.am.val; rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7)); } - if (m.hadAr) { - op.ar=m.ar; + if (m.ar.had) { + op.ar=m.ar.val; rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6)); } - if (m.hadDr) { - op.dr=m.dr; + if (m.dr.had) { + op.dr=m.dr.val; rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7)); } - if (m.hadMult) { - op.mult=m.mult; + if (m.mult.had) { + op.mult=m.mult.val; rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4)); } - if (m.hadRr) { - op.rr=m.rr; + if (m.rr.had) { + op.rr=m.rr.val; rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4)); } - if (m.hadSl) { - op.sl=m.sl; + if (m.sl.had) { + op.sl=m.sl.val; rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4)); } - if (m.hadTl) { - op.tl=127-m.tl; + if (m.tl.had) { + op.tl=127-m.tl.val; if (isOutput[chan[i].state.alg][j]) { rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); } } - if (m.hadRs) { - op.rs=m.rs; + if (m.rs.had) { + op.rs=m.rs.val; rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6)); } - if (m.hadDt) { - op.dt=m.dt; + if (m.dt.had) { + op.dt=m.dt.val; rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4)); } - if (m.hadD2r) { - op.d2r=m.d2r; + if (m.d2r.had) { + op.d2r=m.d2r.val; rWrite(baseAddr+ADDR_DT2_D2R,(op.d2r&31)|(op.dt2<<6)); } - if (m.hadDt2) { - op.dt2=m.dt2; + if (m.dt2.had) { + op.dt2=m.dt2.val; rWrite(baseAddr+ADDR_DT2_D2R,(op.d2r&31)|(op.dt2<<6)); } } @@ -413,7 +413,7 @@ int DivPlatformArcade::dispatch(DivCommand c) { } chan[c.chan].std.init(ins); - if (!chan[c.chan].std.willVol) { + if (!chan[c.chan].std.vol.will) { chan[c.chan].outVol=chan[c.chan].vol; } @@ -472,7 +472,7 @@ int DivPlatformArcade::dispatch(DivCommand c) { break; case DIV_CMD_VOLUME: { chan[c.chan].vol=c.value; - if (!chan[c.chan].std.hasVol) { + if (!chan[c.chan].std.vol.has) { chan[c.chan].outVol=c.value; } for (int i=0; i<4; i++) { diff --git a/src/engine/platform/ay.cpp b/src/engine/platform/ay.cpp index b798cba4..6cdd6b03 100644 --- a/src/engine/platform/ay.cpp +++ b/src/engine/platform/ay.cpp @@ -176,8 +176,8 @@ void DivPlatformAY8910::tick() { // PSG for (int i=0; i<3; i++) { chan[i].std.next(); - if (chan[i].std.hadVol) { - chan[i].outVol=MIN(15,chan[i].std.vol)-(15-(chan[i].vol&15)); + if (chan[i].std.vol.had) { + chan[i].outVol=MIN(15,chan[i].std.vol.val)-(15-(chan[i].vol&15)); if (chan[i].outVol<0) chan[i].outVol=0; if (isMuted[i]) { rWrite(0x08+i,0); @@ -187,26 +187,26 @@ void DivPlatformAY8910::tick() { rWrite(0x08+i,(chan[i].outVol&15)|((chan[i].psgMode&4)<<2)); } } - if (chan[i].std.hadArp) { + if (chan[i].std.arp.had) { if (!chan[i].inPorta) { - if (chan[i].std.arpMode) { - chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp); + if (chan[i].std.arp.mode) { + chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val); } else { - chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp); + chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp.val); } } chan[i].freqChanged=true; } else { - if (chan[i].std.arpMode && chan[i].std.finishedArp) { + if (chan[i].std.arp.mode && chan[i].std.arp.finished) { chan[i].baseFreq=NOTE_PERIODIC(chan[i].note); chan[i].freqChanged=true; } } - if (chan[i].std.hadDuty) { - rWrite(0x06,31-chan[i].std.duty); + if (chan[i].std.duty.had) { + rWrite(0x06,31-chan[i].std.duty.val); } - if (chan[i].std.hadWave) { - chan[i].psgMode=(chan[i].std.wave+1)&7; + if (chan[i].std.wave.had) { + chan[i].psgMode=(chan[i].std.wave.val+1)&7; if (isMuted[i]) { rWrite(0x08+i,0); } else if (intellivision && (chan[i].psgMode&4)) { @@ -215,19 +215,19 @@ void DivPlatformAY8910::tick() { rWrite(0x08+i,(chan[i].outVol&15)|((chan[i].psgMode&4)<<2)); } } - if (chan[i].std.hadEx2) { - ayEnvMode=chan[i].std.ex2; + if (chan[i].std.ex2.had) { + ayEnvMode=chan[i].std.ex2.val; rWrite(0x0d,ayEnvMode); } - if (chan[i].std.hadEx3) { - chan[i].autoEnvNum=chan[i].std.ex3; + if (chan[i].std.ex3.had) { + chan[i].autoEnvNum=chan[i].std.ex3.val; chan[i].freqChanged=true; - if (!chan[i].std.willAlg) chan[i].autoEnvDen=1; + if (!chan[i].std.alg.will) chan[i].autoEnvDen=1; } - if (chan[i].std.hadAlg) { - chan[i].autoEnvDen=chan[i].std.alg; + if (chan[i].std.alg.had) { + chan[i].autoEnvDen=chan[i].std.alg.val; chan[i].freqChanged=true; - if (!chan[i].std.willEx3) chan[i].autoEnvNum=1; + if (!chan[i].std.ex3.will) chan[i].autoEnvNum=1; } if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true); @@ -314,7 +314,7 @@ int DivPlatformAY8910::dispatch(DivCommand c) { break; case DIV_CMD_VOLUME: { chan[c.chan].vol=c.value; - if (!chan[c.chan].std.hasVol) { + if (!chan[c.chan].std.vol.has) { chan[c.chan].outVol=c.value; } if (isMuted[c.chan]) { diff --git a/src/engine/platform/ay8930.cpp b/src/engine/platform/ay8930.cpp index 1849d0cd..de17fa67 100644 --- a/src/engine/platform/ay8930.cpp +++ b/src/engine/platform/ay8930.cpp @@ -191,8 +191,8 @@ void DivPlatformAY8930::tick() { // PSG for (int i=0; i<3; i++) { chan[i].std.next(); - if (chan[i].std.hadVol) { - chan[i].outVol=MIN(31,chan[i].std.vol)-(31-(chan[i].vol&31)); + if (chan[i].std.vol.had) { + chan[i].outVol=MIN(31,chan[i].std.vol.val)-(31-(chan[i].vol&31)); if (chan[i].outVol<0) chan[i].outVol=0; if (isMuted[i]) { rWrite(0x08+i,0); @@ -200,55 +200,55 @@ void DivPlatformAY8930::tick() { rWrite(0x08+i,(chan[i].outVol&31)|((chan[i].psgMode&4)<<3)); } } - if (chan[i].std.hadArp) { + if (chan[i].std.arp.had) { if (!chan[i].inPorta) { - if (chan[i].std.arpMode) { - chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp); + if (chan[i].std.arp.mode) { + chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val); } else { - chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp); + chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp.val); } } chan[i].freqChanged=true; } else { - if (chan[i].std.arpMode && chan[i].std.finishedArp) { + if (chan[i].std.arp.mode && chan[i].std.arp.finished) { chan[i].baseFreq=NOTE_PERIODIC(chan[i].note); chan[i].freqChanged=true; } } - if (chan[i].std.hadDuty) { - rWrite(0x06,chan[i].std.duty); + if (chan[i].std.duty.had) { + rWrite(0x06,chan[i].std.duty.val); } - if (chan[i].std.hadWave) { - chan[i].psgMode=(chan[i].std.wave+1)&7; + if (chan[i].std.wave.had) { + chan[i].psgMode=(chan[i].std.wave.val+1)&7; if (isMuted[i]) { rWrite(0x08+i,0); } else { rWrite(0x08+i,(chan[i].outVol&31)|((chan[i].psgMode&4)<<3)); } } - if (chan[i].std.hadEx1) { // duty - rWrite(0x16+i,chan[i].std.ex1); + if (chan[i].std.ex1.had) { // duty + rWrite(0x16+i,chan[i].std.ex1.val); } - if (chan[i].std.hadEx2) { - ayEnvMode[i]=chan[i].std.ex2; + if (chan[i].std.ex2.had) { + ayEnvMode[i]=chan[i].std.ex2.val; rWrite(regMode[i],ayEnvMode[i]); } - if (chan[i].std.hadEx3) { - chan[i].autoEnvNum=chan[i].std.ex3; + if (chan[i].std.ex3.had) { + chan[i].autoEnvNum=chan[i].std.ex3.val; chan[i].freqChanged=true; - if (!chan[i].std.willAlg) chan[i].autoEnvDen=1; + if (!chan[i].std.alg.will) chan[i].autoEnvDen=1; } - if (chan[i].std.hadAlg) { - chan[i].autoEnvDen=chan[i].std.alg; + if (chan[i].std.alg.had) { + chan[i].autoEnvDen=chan[i].std.alg.val; chan[i].freqChanged=true; - if (!chan[i].std.willEx3) chan[i].autoEnvNum=1; + if (!chan[i].std.ex3.will) chan[i].autoEnvNum=1; } - if (chan[i].std.hadFb) { - ayNoiseAnd=chan[i].std.fb; + if (chan[i].std.fb.had) { + ayNoiseAnd=chan[i].std.fb.val; immWrite(0x19,ayNoiseAnd); } - if (chan[i].std.hadFms) { - ayNoiseOr=chan[i].std.fms; + if (chan[i].std.fms.had) { + ayNoiseOr=chan[i].std.fms.val; immWrite(0x1a,ayNoiseOr); } if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { @@ -256,7 +256,7 @@ void DivPlatformAY8930::tick() { if (chan[i].freq>65535) chan[i].freq=65535; if (chan[i].keyOn) { if (chan[i].insChanged) { - if (!chan[i].std.willEx1) immWrite(0x16+i,chan[i].duty); + if (!chan[i].std.ex1.will) immWrite(0x16+i,chan[i].duty); chan[i].insChanged=false; } } @@ -336,7 +336,7 @@ int DivPlatformAY8930::dispatch(DivCommand c) { break; case DIV_CMD_VOLUME: { chan[c.chan].vol=c.value; - if (!chan[c.chan].std.hasVol) { + if (!chan[c.chan].std.vol.has) { chan[c.chan].outVol=c.value; } if (isMuted[c.chan]) { diff --git a/src/engine/platform/bubsyswsg.cpp b/src/engine/platform/bubsyswsg.cpp index 98961972..712496c1 100644 --- a/src/engine/platform/bubsyswsg.cpp +++ b/src/engine/platform/bubsyswsg.cpp @@ -84,28 +84,28 @@ void DivPlatformBubSysWSG::updateWave(int ch) { void DivPlatformBubSysWSG::tick() { for (int i=0; i<2; i++) { chan[i].std.next(); - if (chan[i].std.hadVol) { - chan[i].outVol=((chan[i].vol&15)*MIN(15,chan[i].std.vol))/15; + if (chan[i].std.vol.had) { + chan[i].outVol=((chan[i].vol&15)*MIN(15,chan[i].std.vol.val))/15; rWrite(2+i,(chan[i].wave<<5)|chan[i].outVol); } - if (chan[i].std.hadArp) { + if (chan[i].std.arp.had) { if (!chan[i].inPorta) { - if (chan[i].std.arpMode) { - chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp); + if (chan[i].std.arp.mode) { + chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val); } else { - chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp); + chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp.val); } } chan[i].freqChanged=true; } else { - if (chan[i].std.arpMode && chan[i].std.finishedArp) { + if (chan[i].std.arp.mode && chan[i].std.arp.finished) { chan[i].baseFreq=NOTE_PERIODIC(chan[i].note); chan[i].freqChanged=true; } } - if (chan[i].std.hadWave) { - if (chan[i].wave!=chan[i].std.wave || chan[i].ws.activeChanged()) { - chan[i].wave=chan[i].std.wave; + if (chan[i].std.wave.had) { + if (chan[i].wave!=chan[i].std.wave.val || chan[i].ws.activeChanged()) { + chan[i].wave=chan[i].std.wave.val; chan[i].ws.changeWave1(chan[i].wave); if (!chan[i].keyOff) chan[i].keyOn=true; } @@ -174,14 +174,14 @@ int DivPlatformBubSysWSG::dispatch(DivCommand c) { case DIV_CMD_VOLUME: if (chan[c.chan].vol!=c.value) { chan[c.chan].vol=c.value; - if (!chan[c.chan].std.hasVol) { + if (!chan[c.chan].std.vol.has) { chan[c.chan].outVol=c.value; if (chan[c.chan].active) rWrite(2+c.chan,(chan[c.chan].wave<<5)|chan[c.chan].outVol); } } break; case DIV_CMD_GET_VOLUME: - if (chan[c.chan].std.hasVol) { + if (chan[c.chan].std.vol.has) { return chan[c.chan].vol; } return chan[c.chan].outVol; @@ -219,7 +219,7 @@ int DivPlatformBubSysWSG::dispatch(DivCommand c) { break; } case DIV_CMD_LEGATO: - chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+((chan[c.chan].std.willArp && !chan[c.chan].std.arpMode)?(chan[c.chan].std.arp):(0))); + chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+((chan[c.chan].std.arp.will && !chan[c.chan].std.arp.mode)?(chan[c.chan].std.arp.val):(0))); chan[c.chan].freqChanged=true; chan[c.chan].note=c.value; break; diff --git a/src/engine/platform/c64.cpp b/src/engine/platform/c64.cpp index 49be60fb..786da058 100644 --- a/src/engine/platform/c64.cpp +++ b/src/engine/platform/c64.cpp @@ -125,43 +125,43 @@ void DivPlatformC64::updateFilter() { void DivPlatformC64::tick() { for (int i=0; i<3; i++) { chan[i].std.next(); - if (chan[i].std.hadVol) { + if (chan[i].std.vol.had) { DivInstrument* ins=parent->getIns(chan[i].ins); if (ins->c64.volIsCutoff) { if (ins->c64.filterIsAbs) { - filtCut=MIN(2047,chan[i].std.vol); + filtCut=MIN(2047,chan[i].std.vol.val); } else { - filtCut-=((signed char)chan[i].std.vol-18)*7; + filtCut-=((signed char)chan[i].std.vol.val-18)*7; if (filtCut>2047) filtCut=2047; if (filtCut<0) filtCut=0; } updateFilter(); } else { - vol=MIN(15,chan[i].std.vol); + vol=MIN(15,chan[i].std.vol.val); updateFilter(); } } - if (chan[i].std.hadArp) { + if (chan[i].std.arp.had) { if (!chan[i].inPorta) { - if (chan[i].std.arpMode) { - chan[i].baseFreq=NOTE_FREQUENCY(chan[i].std.arp); + if (chan[i].std.arp.mode) { + chan[i].baseFreq=NOTE_FREQUENCY(chan[i].std.arp.val); } else { - chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note+(signed char)chan[i].std.arp); + chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note+(signed char)chan[i].std.arp.val); } } chan[i].freqChanged=true; } else { - if (chan[i].std.arpMode && chan[i].std.finishedArp) { + if (chan[i].std.arp.mode && chan[i].std.arp.finished) { chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note); chan[i].freqChanged=true; } } - if (chan[i].std.hadDuty) { + if (chan[i].std.duty.had) { DivInstrument* ins=parent->getIns(chan[i].ins); - if (ins->c64.dutyIsAbs) { - chan[i].duty=chan[i].std.duty; + if (ins->std.dutyMacro.mode) { + chan[i].duty=chan[i].std.duty.val; } else { - chan[i].duty-=((signed char)chan[i].std.duty-12)*4; + chan[i].duty-=((signed char)chan[i].std.duty.val-12)*4; } rWrite(i*7+2,chan[i].duty&0xff); rWrite(i*7+3,chan[i].duty>>8); @@ -175,21 +175,21 @@ void DivPlatformC64::tick() { } } } - if (chan[i].std.hadWave) { - chan[i].wave=chan[i].std.wave; + if (chan[i].std.wave.had) { + chan[i].wave=chan[i].std.wave.val; rWrite(i*7+4,(isMuted[i]?8:(chan[i].wave<<4))|(chan[i].ring<<2)|(chan[i].sync<<1)|chan[i].active); } - if (chan[i].std.hadEx1) { - filtControl=chan[i].std.ex1&15; + if (chan[i].std.ex1.had) { + filtControl=chan[i].std.ex1.val&15; updateFilter(); } - if (chan[i].std.hadEx2) { - filtRes=chan[i].std.ex2&15; + if (chan[i].std.ex2.had) { + filtRes=chan[i].std.ex2.val&15; updateFilter(); } - if (chan[i].std.hadEx3) { - chan[i].sync=chan[i].std.ex3&1; - chan[i].ring=chan[i].std.ex3&2; + if (chan[i].std.ex3.had) { + chan[i].sync=chan[i].std.ex3.val&1; + chan[i].ring=chan[i].std.ex3.val&2; chan[i].freqChanged=true; } @@ -226,7 +226,7 @@ int DivPlatformC64::dispatch(DivCommand c) { } chan[c.chan].active=true; chan[c.chan].keyOn=true; - if (chan[c.chan].insChanged || chan[c.chan].resetDuty || ins->std.waveMacroLen>0) { + if (chan[c.chan].insChanged || chan[c.chan].resetDuty || ins->std.waveMacro.len>0) { chan[c.chan].duty=ins->c64.duty; rWrite(c.chan*7+2,chan[c.chan].duty&0xff); rWrite(c.chan*7+3,chan[c.chan].duty>>8); @@ -279,7 +279,7 @@ int DivPlatformC64::dispatch(DivCommand c) { case DIV_CMD_VOLUME: if (chan[c.chan].vol!=c.value) { chan[c.chan].vol=c.value; - if (!chan[c.chan].std.hasVol) { + if (!chan[c.chan].std.vol.has) { chan[c.chan].outVol=c.value; vol=chan[c.chan].outVol; } else { @@ -333,7 +333,7 @@ int DivPlatformC64::dispatch(DivCommand c) { rWrite(c.chan*7+4,(isMuted[c.chan]?8:(chan[c.chan].wave<<4))|(chan[c.chan].ring<<2)|(chan[c.chan].sync<<1)|chan[c.chan].active); break; case DIV_CMD_LEGATO: - chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value+((chan[c.chan].std.willArp && !chan[c.chan].std.arpMode)?(chan[c.chan].std.arp):(0))); + chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value+((chan[c.chan].std.arp.will && !chan[c.chan].std.arp.mode)?(chan[c.chan].std.arp.val):(0))); chan[c.chan].freqChanged=true; chan[c.chan].note=c.value; break; diff --git a/src/engine/platform/fds.cpp b/src/engine/platform/fds.cpp index cd70dfac..9960a0d7 100644 --- a/src/engine/platform/fds.cpp +++ b/src/engine/platform/fds.cpp @@ -100,40 +100,40 @@ void DivPlatformFDS::updateWave() { void DivPlatformFDS::tick() { for (int i=0; i<1; i++) { chan[i].std.next(); - if (chan[i].std.hadVol) { + if (chan[i].std.vol.had) { // ok, why are the volumes like that? - chan[i].outVol=MIN(32,chan[i].std.vol)-(32-MIN(32,chan[i].vol)); + chan[i].outVol=MIN(32,chan[i].std.vol.val)-(32-MIN(32,chan[i].vol)); if (chan[i].outVol<0) chan[i].outVol=0; rWrite(0x4080,0x80|chan[i].outVol); } - if (chan[i].std.hadArp) { + if (chan[i].std.arp.had) { if (i==3) { // noise - if (chan[i].std.arpMode) { - chan[i].baseFreq=chan[i].std.arp; + if (chan[i].std.arp.mode) { + chan[i].baseFreq=chan[i].std.arp.val; } else { - chan[i].baseFreq=chan[i].note+chan[i].std.arp; + chan[i].baseFreq=chan[i].note+chan[i].std.arp.val; } if (chan[i].baseFreq>255) chan[i].baseFreq=255; if (chan[i].baseFreq<0) chan[i].baseFreq=0; } else { if (!chan[i].inPorta) { - if (chan[i].std.arpMode) { - chan[i].baseFreq=NOTE_FREQUENCY(chan[i].std.arp); + if (chan[i].std.arp.mode) { + chan[i].baseFreq=NOTE_FREQUENCY(chan[i].std.arp.val); } else { - chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note+chan[i].std.arp); + chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note+chan[i].std.arp.val); } } } chan[i].freqChanged=true; } else { - if (chan[i].std.arpMode && chan[i].std.finishedArp) { + if (chan[i].std.arp.mode && chan[i].std.arp.finished) { chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note); chan[i].freqChanged=true; } } /* - if (chan[i].std.hadDuty) { - chan[i].duty=chan[i].std.duty; + if (chan[i].std.duty.had) { + chan[i].duty=chan[i].std.duty.val; if (i==3) { if (parent->song.properNoiseLayout) { chan[i].duty&=1; @@ -148,9 +148,9 @@ void DivPlatformFDS::tick() { chan[i].freqChanged=true; } }*/ - if (chan[i].std.hadWave) { - if (chan[i].wave!=chan[i].std.wave || ws.activeChanged()) { - chan[i].wave=chan[i].std.wave; + if (chan[i].std.wave.had) { + if (chan[i].wave!=chan[i].std.wave.val || ws.activeChanged()) { + chan[i].wave=chan[i].std.wave.val; ws.changeWave1(chan[i].wave); //if (!chan[i].keyOff) chan[i].keyOn=true; } @@ -161,18 +161,18 @@ void DivPlatformFDS::tick() { if (!chan[i].keyOff) chan[i].keyOn=true; } } - if (chan[i].std.hadEx1) { // mod depth - chan[i].modOn=chan[i].std.ex1; - chan[i].modDepth=chan[i].std.ex1; + if (chan[i].std.ex1.had) { // mod depth + chan[i].modOn=chan[i].std.ex1.val; + chan[i].modDepth=chan[i].std.ex1.val; rWrite(0x4084,(chan[i].modOn<<7)|0x40|chan[i].modDepth); } - if (chan[i].std.hadEx2) { // mod speed - chan[i].modFreq=chan[i].std.ex2; + if (chan[i].std.ex2.had) { // mod speed + chan[i].modFreq=chan[i].std.ex2.val; rWrite(0x4086,chan[i].modFreq&0xff); rWrite(0x4087,chan[i].modFreq>>8); } - if (chan[i].std.hadEx3) { // mod position - chan[i].modPos=chan[i].std.ex3; + if (chan[i].std.ex3.had) { // mod position + chan[i].modPos=chan[i].std.ex3.val; rWrite(0x4087,0x80|chan[i].modFreq>>8); rWrite(0x4085,chan[i].modPos); rWrite(0x4087,chan[i].modFreq>>8); @@ -276,7 +276,7 @@ int DivPlatformFDS::dispatch(DivCommand c) { case DIV_CMD_VOLUME: if (chan[c.chan].vol!=c.value) { chan[c.chan].vol=c.value; - if (!chan[c.chan].std.hasVol) { + if (!chan[c.chan].std.vol.has) { chan[c.chan].outVol=c.value; } rWrite(0x4080,0x80|chan[c.chan].vol); @@ -359,7 +359,7 @@ int DivPlatformFDS::dispatch(DivCommand c) { } case DIV_CMD_LEGATO: if (c.chan==3) break; - chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value+((chan[c.chan].std.willArp && !chan[c.chan].std.arpMode)?(chan[c.chan].std.arp):(0))); + chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value+((chan[c.chan].std.arp.will && !chan[c.chan].std.arp.mode)?(chan[c.chan].std.arp.val):(0))); chan[c.chan].freqChanged=true; chan[c.chan].note=c.value; break; diff --git a/src/engine/platform/gb.cpp b/src/engine/platform/gb.cpp index 263e8e2b..13eac1f3 100644 --- a/src/engine/platform/gb.cpp +++ b/src/engine/platform/gb.cpp @@ -149,45 +149,45 @@ static unsigned char noiseTable[256]={ void DivPlatformGB::tick() { for (int i=0; i<4; i++) { chan[i].std.next(); - if (chan[i].std.hadArp) { + if (chan[i].std.arp.had) { if (i==3) { // noise - if (chan[i].std.arpMode) { - chan[i].baseFreq=chan[i].std.arp+24; + if (chan[i].std.arp.mode) { + chan[i].baseFreq=chan[i].std.arp.val+24; } else { - chan[i].baseFreq=chan[i].note+chan[i].std.arp; + chan[i].baseFreq=chan[i].note+chan[i].std.arp.val; } if (chan[i].baseFreq>255) chan[i].baseFreq=255; if (chan[i].baseFreq<0) chan[i].baseFreq=0; } else { if (!chan[i].inPorta) { - if (chan[i].std.arpMode) { - chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp+24); + if (chan[i].std.arp.mode) { + chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val+24); } else { - chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp); + chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp.val); } } } chan[i].freqChanged=true; } else { - if (chan[i].std.arpMode && chan[i].std.finishedArp) { + if (chan[i].std.arp.mode && chan[i].std.arp.finished) { chan[i].baseFreq=NOTE_PERIODIC(chan[i].note); chan[i].freqChanged=true; } } - if (chan[i].std.hadDuty) { - chan[i].duty=chan[i].std.duty; + if (chan[i].std.duty.had) { + chan[i].duty=chan[i].std.duty.val; DivInstrument* ins=parent->getIns(chan[i].ins); if (i!=2) { rWrite(16+i*5+1,((chan[i].duty&3)<<6)|(63-(ins->gb.soundLen&63))); } else { if (parent->song.waveDutyIsVol) { - rWrite(16+i*5+2,gbVolMap[(chan[i].std.duty&3)<<2]); + rWrite(16+i*5+2,gbVolMap[(chan[i].std.duty.val&3)<<2]); } } } - if (i==2 && chan[i].std.hadWave) { - if (chan[i].wave!=chan[i].std.wave || ws.activeChanged()) { - chan[i].wave=chan[i].std.wave; + if (i==2 && chan[i].std.wave.had) { + if (chan[i].wave!=chan[i].std.wave.val || ws.activeChanged()) { + chan[i].wave=chan[i].std.wave.val; ws.changeWave1(chan[i].wave); if (!chan[i].keyOff) chan[i].keyOn=true; } @@ -359,7 +359,7 @@ int DivPlatformGB::dispatch(DivCommand c) { } case DIV_CMD_LEGATO: if (c.chan==3) break; - chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+((chan[c.chan].std.willArp && !chan[c.chan].std.arpMode)?(chan[c.chan].std.arp):(0))); + chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+((chan[c.chan].std.arp.will && !chan[c.chan].std.arp.mode)?(chan[c.chan].std.arp.val):(0))); chan[c.chan].freqChanged=true; chan[c.chan].note=c.value; break; diff --git a/src/engine/platform/genesis.cpp b/src/engine/platform/genesis.cpp index 0aff2b43..c1c1648e 100644 --- a/src/engine/platform/genesis.cpp +++ b/src/engine/platform/genesis.cpp @@ -225,8 +225,8 @@ void DivPlatformGenesis::tick() { if (i==2 && extMode) continue; chan[i].std.next(); - if (chan[i].std.hadVol) { - chan[i].outVol=(chan[i].vol*MIN(127,chan[i].std.vol))/127; + if (chan[i].std.vol.had) { + chan[i].outVol=(chan[i].vol*MIN(127,chan[i].std.vol.val))/127; for (int j=0; j<4; j++) { unsigned short baseAddr=chanOffs[i]|opOffs[j]; DivInstrumentFM::Operator& op=chan[i].state.op[j]; @@ -242,24 +242,24 @@ void DivPlatformGenesis::tick() { } } - if (chan[i].std.hadArp) { + if (chan[i].std.arp.had) { if (!chan[i].inPorta) { - if (chan[i].std.arpMode) { - chan[i].baseFreq=NOTE_FREQUENCY(chan[i].std.arp); + if (chan[i].std.arp.mode) { + chan[i].baseFreq=NOTE_FREQUENCY(chan[i].std.arp.val); } else { - chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note+(signed char)chan[i].std.arp); + chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note+(signed char)chan[i].std.arp.val); } } chan[i].freqChanged=true; } else { - if (chan[i].std.arpMode && chan[i].std.finishedArp) { + if (chan[i].std.arp.mode && chan[i].std.arp.finished) { chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note); chan[i].freqChanged=true; } } - if (chan[i].std.hadAlg) { - chan[i].state.alg=chan[i].std.alg; + if (chan[i].std.alg.had) { + chan[i].state.alg=chan[i].std.alg.val; rWrite(chanOffs[i]+ADDR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3)); if (!parent->song.algMacroBehavior) for (int j=0; j<4; j++) { unsigned short baseAddr=chanOffs[i]|opOffs[j]; @@ -275,48 +275,48 @@ void DivPlatformGenesis::tick() { } } } - if (chan[i].std.hadFb) { - chan[i].state.fb=chan[i].std.fb; + if (chan[i].std.fb.had) { + chan[i].state.fb=chan[i].std.fb.val; rWrite(chanOffs[i]+ADDR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3)); } - if (chan[i].std.hadFms) { - chan[i].state.fms=chan[i].std.fms; + if (chan[i].std.fms.had) { + chan[i].state.fms=chan[i].std.fms.val; rWrite(chanOffs[i]+ADDR_LRAF,(isMuted[i]?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4)); } - if (chan[i].std.hadAms) { - chan[i].state.ams=chan[i].std.ams; + if (chan[i].std.ams.had) { + chan[i].state.ams=chan[i].std.ams.val; rWrite(chanOffs[i]+ADDR_LRAF,(isMuted[i]?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4)); } for (int j=0; j<4; j++) { unsigned short baseAddr=chanOffs[i]|opOffs[j]; DivInstrumentFM::Operator& op=chan[i].state.op[j]; DivMacroInt::IntOp& m=chan[i].std.op[j]; - if (m.hadAm) { - op.am=m.am; + if (m.am.had) { + op.am=m.am.val; rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7)); } - if (m.hadAr) { - op.ar=m.ar; + if (m.ar.had) { + op.ar=m.ar.val; rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6)); } - if (m.hadDr) { - op.dr=m.dr; + if (m.dr.had) { + op.dr=m.dr.val; rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7)); } - if (m.hadMult) { - op.mult=m.mult; + if (m.mult.had) { + op.mult=m.mult.val; rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4)); } - if (m.hadRr) { - op.rr=m.rr; + if (m.rr.had) { + op.rr=m.rr.val; rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4)); } - if (m.hadSl) { - op.sl=m.sl; + if (m.sl.had) { + op.sl=m.sl.val; rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4)); } - if (m.hadTl) { - op.tl=127-m.tl; + if (m.tl.had) { + op.tl=127-m.tl.val; if (isMuted[i]) { rWrite(baseAddr+ADDR_TL,127); } else { @@ -327,20 +327,20 @@ void DivPlatformGenesis::tick() { } } } - if (m.hadRs) { - op.rs=m.rs; + if (m.rs.had) { + op.rs=m.rs.val; rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6)); } - if (m.hadDt) { - op.dt=m.dt; + if (m.dt.had) { + op.dt=m.dt.val; rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4)); } - if (m.hadD2r) { - op.d2r=m.d2r; + if (m.d2r.had) { + op.d2r=m.d2r.val; rWrite(baseAddr+ADDR_DT2_D2R,op.d2r&31); } - if (m.hadSsg) { - op.ssgEnv=m.ssg; + if (m.ssg.had) { + op.ssgEnv=m.ssg.val; rWrite(baseAddr+ADDR_SSG,op.ssgEnv&15); } } @@ -505,7 +505,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) { } chan[c.chan].std.init(ins); - if (!chan[c.chan].std.willVol) { + if (!chan[c.chan].std.vol.will) { chan[c.chan].outVol=chan[c.chan].vol; } @@ -578,7 +578,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) { break; case DIV_CMD_VOLUME: { chan[c.chan].vol=c.value; - if (!chan[c.chan].std.hasVol) { + if (!chan[c.chan].std.vol.has) { chan[c.chan].outVol=c.value; } for (int i=0; i<4; i++) { diff --git a/src/engine/platform/lynx.cpp b/src/engine/platform/lynx.cpp index dc0df8a6..70e7bc41 100644 --- a/src/engine/platform/lynx.cpp +++ b/src/engine/platform/lynx.cpp @@ -148,23 +148,23 @@ void DivPlatformLynx::acquire(short* bufL, short* bufR, size_t start, size_t len void DivPlatformLynx::tick() { for (int i=0; i<4; i++) { chan[i].std.next(); - if (chan[i].std.hadVol) { - chan[i].outVol=((chan[i].vol&127)*MIN(127,chan[i].std.vol))>>7; + if (chan[i].std.vol.had) { + chan[i].outVol=((chan[i].vol&127)*MIN(127,chan[i].std.vol.val))>>7; WRITE_VOLUME(i,(isMuted[i]?0:(chan[i].outVol&127))); } - if (chan[i].std.hadArp) { + if (chan[i].std.arp.had) { if (!chan[i].inPorta) { - if (chan[i].std.arpMode) { - chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp); - chan[i].actualNote=chan[i].std.arp; + if (chan[i].std.arp.mode) { + chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val); + chan[i].actualNote=chan[i].std.arp.val; } else { - chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp); - chan[i].actualNote=chan[i].note+chan[i].std.arp; + chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp.val); + chan[i].actualNote=chan[i].note+chan[i].std.arp.val; } chan[i].freqChanged=true; } } else { - if (chan[i].std.arpMode && chan[i].std.finishedArp) { + if (chan[i].std.arp.mode && chan[i].std.arp.finished) { chan[i].baseFreq=NOTE_PERIODIC(chan[i].note); chan[i].actualNote=chan[i].note; chan[i].freqChanged=true; @@ -178,15 +178,15 @@ void DivPlatformLynx::tick() { chan[i].lfsr=-1; } chan[i].fd=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true); - if (chan[i].std.hadDuty) { - chan[i].duty=chan[i].std.duty; + if (chan[i].std.duty.had) { + chan[i].duty=chan[i].std.duty.val; WRITE_FEEDBACK(i, chan[i].duty.feedback); } WRITE_CONTROL(i, (chan[i].fd.clockDivider|0x18|chan[i].duty.int_feedback7)); WRITE_BACKUP( i, chan[i].fd.backup ); } - else if (chan[i].std.hadDuty) { - chan[i].duty = chan[i].std.duty; + else if (chan[i].std.duty.had) { + chan[i].duty = chan[i].std.duty.val; WRITE_FEEDBACK(i, chan[i].duty.feedback); WRITE_CONTROL(i, (chan[i].fd.clockDivider|0x18|chan[i].duty.int_feedback7)); } @@ -228,7 +228,7 @@ int DivPlatformLynx::dispatch(DivCommand c) { case DIV_CMD_VOLUME: if (chan[c.chan].vol!=c.value) { chan[c.chan].vol=c.value; - if (!chan[c.chan].std.hasVol) { + if (!chan[c.chan].std.vol.has) { chan[c.chan].outVol=c.value; } if (chan[c.chan].active) WRITE_VOLUME(c.chan,(isMuted[c.chan]?0:(chan[c.chan].vol&127))); @@ -239,7 +239,7 @@ int DivPlatformLynx::dispatch(DivCommand c) { WRITE_ATTEN(c.chan,chan[c.chan].pan); break; case DIV_CMD_GET_VOLUME: - if (chan[c.chan].std.hasVol) { + if (chan[c.chan].std.vol.has) { return chan[c.chan].vol; } return chan[c.chan].outVol; @@ -272,7 +272,7 @@ int DivPlatformLynx::dispatch(DivCommand c) { break; } case DIV_CMD_LEGATO: - chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+((chan[c.chan].std.willArp && !chan[c.chan].std.arpMode)?(chan[c.chan].std.arp):(0))); + chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+((chan[c.chan].std.arp.will && !chan[c.chan].std.arp.mode)?(chan[c.chan].std.arp.val):(0))); chan[c.chan].freqChanged=true; chan[c.chan].note=c.value; chan[c.chan].actualNote=c.value; diff --git a/src/engine/platform/mmc5.cpp b/src/engine/platform/mmc5.cpp index 3ccf9549..0f803ee2 100644 --- a/src/engine/platform/mmc5.cpp +++ b/src/engine/platform/mmc5.cpp @@ -99,29 +99,29 @@ void DivPlatformMMC5::acquire(short* bufL, short* bufR, size_t start, size_t len void DivPlatformMMC5::tick() { for (int i=0; i<2; i++) { chan[i].std.next(); - if (chan[i].std.hadVol) { + if (chan[i].std.vol.had) { // ok, why are the volumes like that? - chan[i].outVol=MIN(15,chan[i].std.vol)-(15-(chan[i].vol&15)); + chan[i].outVol=MIN(15,chan[i].std.vol.val)-(15-(chan[i].vol&15)); if (chan[i].outVol<0) chan[i].outVol=0; rWrite(0x5000+i*4,0x30|chan[i].outVol|((chan[i].duty&3)<<6)); } - if (chan[i].std.hadArp) { + if (chan[i].std.arp.had) { if (!chan[i].inPorta) { - if (chan[i].std.arpMode) { - chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp); + if (chan[i].std.arp.mode) { + chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val); } else { - chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp); + chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp.val); } } chan[i].freqChanged=true; } else { - if (chan[i].std.arpMode && chan[i].std.finishedArp) { + if (chan[i].std.arp.mode && chan[i].std.arp.finished) { chan[i].baseFreq=NOTE_PERIODIC(chan[i].note); chan[i].freqChanged=true; } } - if (chan[i].std.hadDuty) { - chan[i].duty=chan[i].std.duty; + if (chan[i].std.duty.had) { + chan[i].duty=chan[i].std.duty.val; rWrite(0x5000+i*4,0x30|chan[i].outVol|((chan[i].duty&3)<<6)); } if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { @@ -243,7 +243,7 @@ int DivPlatformMMC5::dispatch(DivCommand c) { case DIV_CMD_VOLUME: if (chan[c.chan].vol!=c.value) { chan[c.chan].vol=c.value; - if (!chan[c.chan].std.hasVol) { + if (!chan[c.chan].std.vol.has) { chan[c.chan].outVol=c.value; } if (chan[c.chan].active) { @@ -291,7 +291,7 @@ int DivPlatformMMC5::dispatch(DivCommand c) { } break; case DIV_CMD_LEGATO: - chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+((chan[c.chan].std.willArp && !chan[c.chan].std.arpMode)?(chan[c.chan].std.arp):(0))); + chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+((chan[c.chan].std.arp.will && !chan[c.chan].std.arp.mode)?(chan[c.chan].std.arp.val):(0))); chan[c.chan].freqChanged=true; chan[c.chan].note=c.value; break; diff --git a/src/engine/platform/n163.cpp b/src/engine/platform/n163.cpp index 2800fad1..6248cb56 100644 --- a/src/engine/platform/n163.cpp +++ b/src/engine/platform/n163.cpp @@ -203,8 +203,8 @@ void DivPlatformN163::updateWaveCh(int ch) { void DivPlatformN163::tick() { for (int i=0; i<=chanMax; i++) { chan[i].std.next(); - if (chan[i].std.hadVol) { - chan[i].outVol=(MIN(15,chan[i].std.vol)*(chan[i].vol&15))/15; + if (chan[i].std.vol.had) { + chan[i].outVol=(MIN(15,chan[i].std.vol.val)*(chan[i].vol&15))/15; if (chan[i].outVol<0) chan[i].outVol=0; if (chan[i].outVol>15) chan[i].outVol=15; if (chan[i].resVol!=chan[i].outVol) { @@ -214,87 +214,87 @@ void DivPlatformN163::tick() { } } } - if (chan[i].std.hadArp) { + if (chan[i].std.arp.had) { if (!chan[i].inPorta) { - if (chan[i].std.arpMode) { - chan[i].baseFreq=NOTE_FREQUENCY(chan[i].std.arp); + if (chan[i].std.arp.mode) { + chan[i].baseFreq=NOTE_FREQUENCY(chan[i].std.arp.val); } else { - chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note+(signed char)chan[i].std.arp); + chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note+(signed char)chan[i].std.arp.val); } } chan[i].freqChanged=true; } else { - if (chan[i].std.arpMode && chan[i].std.finishedArp) { + if (chan[i].std.arp.mode && chan[i].std.arp.finished) { chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note); chan[i].freqChanged=true; } } - if (chan[i].std.hadDuty) { - if (chan[i].wavePos!=chan[i].std.duty) { - chan[i].wavePos=chan[i].std.duty; + if (chan[i].std.duty.had) { + if (chan[i].wavePos!=chan[i].std.duty.val) { + chan[i].wavePos=chan[i].std.duty.val; if (chan[i].waveMode&0x2) { chan[i].waveUpdated=true; } chan[i].waveChanged=true; } } - if (chan[i].std.hadWave) { - if (chan[i].wave!=chan[i].std.wave) { - chan[i].wave=chan[i].std.wave; + if (chan[i].std.wave.had) { + if (chan[i].wave!=chan[i].std.wave.val) { + chan[i].wave=chan[i].std.wave.val; if (chan[i].waveMode&0x2) { chan[i].waveUpdated=true; } } } - if (chan[i].std.hadEx1) { - if (chan[i].waveLen!=(chan[i].std.ex1&0xfc)) { - chan[i].waveLen=chan[i].std.ex1&0xfc; + if (chan[i].std.ex1.had) { + if (chan[i].waveLen!=(chan[i].std.ex1.val&0xfc)) { + chan[i].waveLen=chan[i].std.ex1.val&0xfc; if (chan[i].waveMode&0x2) { chan[i].waveUpdated=true; } chan[i].freqChanged=true; } } - if (chan[i].std.hadEx2) { - if ((chan[i].waveMode&0x2)!=(chan[i].std.ex2&0x2)) { // update when every waveform changed - chan[i].waveMode=(chan[i].waveMode&~0x2)|(chan[i].std.ex2&0x2); + if (chan[i].std.ex2.had) { + if ((chan[i].waveMode&0x2)!=(chan[i].std.ex2.val&0x2)) { // update when every waveform changed + chan[i].waveMode=(chan[i].waveMode&~0x2)|(chan[i].std.ex2.val&0x2); if (chan[i].waveMode&0x2) { chan[i].waveUpdated=true; chan[i].waveChanged=true; } } - if ((chan[i].waveMode&0x1)!=(chan[i].std.ex2&0x1)) { // update waveform now - chan[i].waveMode=(chan[i].waveMode&~0x1)|(chan[i].std.ex2&0x1); + if ((chan[i].waveMode&0x1)!=(chan[i].std.ex2.val&0x1)) { // update waveform now + chan[i].waveMode=(chan[i].waveMode&~0x1)|(chan[i].std.ex2.val&0x1); if (chan[i].waveMode&0x1) { // rising edge chan[i].waveUpdated=true; chan[i].waveChanged=true; } } } - if (chan[i].std.hadEx3) { - if (chan[i].loadWave!=chan[i].std.ex3) { - chan[i].loadWave=chan[i].std.ex3; + if (chan[i].std.ex3.had) { + if (chan[i].loadWave!=chan[i].std.ex3.val) { + chan[i].loadWave=chan[i].std.ex3.val; if (chan[i].loadMode&0x2) { updateWave(chan[i].loadWave,chan[i].loadPos,chan[i].loadLen&0xfc); } } } - if (chan[i].std.hadAlg) { - if (chan[i].loadPos!=chan[i].std.alg) { - chan[i].loadPos=chan[i].std.alg; + if (chan[i].std.alg.had) { + if (chan[i].loadPos!=chan[i].std.alg.val) { + chan[i].loadPos=chan[i].std.alg.val; } } - if (chan[i].std.hadFb) { - if (chan[i].loadLen!=(chan[i].std.fb&0xfc)) { - chan[i].loadLen=chan[i].std.fb&0xfc; + if (chan[i].std.fb.had) { + if (chan[i].loadLen!=(chan[i].std.fb.val&0xfc)) { + chan[i].loadLen=chan[i].std.fb.val&0xfc; } } - if (chan[i].std.hadFms) { - if ((chan[i].loadMode&0x2)!=(chan[i].std.fms&0x2)) { // load when every waveform changes - chan[i].loadMode=(chan[i].loadMode&~0x2)|(chan[i].std.fms&0x2); + if (chan[i].std.fms.had) { + if ((chan[i].loadMode&0x2)!=(chan[i].std.fms.val&0x2)) { // load when every waveform changes + chan[i].loadMode=(chan[i].loadMode&~0x2)|(chan[i].std.fms.val&0x2); } - if ((chan[i].loadMode&0x1)!=(chan[i].std.fms&0x1)) { // load now - chan[i].loadMode=(chan[i].loadMode&~0x1)|(chan[i].std.fms&0x1); + if ((chan[i].loadMode&0x1)!=(chan[i].std.fms.val&0x1)) { // load now + chan[i].loadMode=(chan[i].loadMode&~0x1)|(chan[i].std.fms.val&0x1); if (chan[i].loadMode&0x1) { // rising edge updateWave(chan[i].loadWave,chan[i].loadPos,chan[i].loadLen&0xfc); } @@ -400,7 +400,7 @@ int DivPlatformN163::dispatch(DivCommand c) { case DIV_CMD_VOLUME: if (chan[c.chan].vol!=c.value) { chan[c.chan].vol=c.value; - if (!chan[c.chan].std.hasVol) { + if (!chan[c.chan].std.vol.has) { chan[c.chan].outVol=c.value; chan[c.chan].resVol=chan[c.chan].outVol; } else { @@ -513,7 +513,7 @@ int DivPlatformN163::dispatch(DivCommand c) { } break; case DIV_CMD_LEGATO: - chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value+((chan[c.chan].std.willArp && !chan[c.chan].std.arpMode)?(chan[c.chan].std.arp):(0))); + chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value+((chan[c.chan].std.arp.will && !chan[c.chan].std.arp.mode)?(chan[c.chan].std.arp.val):(0))); chan[c.chan].freqChanged=true; chan[c.chan].note=c.value; break; diff --git a/src/engine/platform/nes.cpp b/src/engine/platform/nes.cpp index f61ed4fb..5380b0b4 100644 --- a/src/engine/platform/nes.cpp +++ b/src/engine/platform/nes.cpp @@ -136,9 +136,9 @@ static unsigned char noiseTable[253]={ void DivPlatformNES::tick() { for (int i=0; i<4; i++) { chan[i].std.next(); - if (chan[i].std.hadVol) { + if (chan[i].std.vol.had) { // ok, why are the volumes like that? - chan[i].outVol=MIN(15,chan[i].std.vol)-(15-(chan[i].vol&15)); + chan[i].outVol=MIN(15,chan[i].std.vol.val)-(15-(chan[i].vol&15)); if (chan[i].outVol<0) chan[i].outVol=0; if (i==2) { // triangle rWrite(0x4000+i*4,(chan[i].outVol==0)?0:255); @@ -147,33 +147,33 @@ void DivPlatformNES::tick() { rWrite(0x4000+i*4,0x30|chan[i].outVol|((chan[i].duty&3)<<6)); } } - if (chan[i].std.hadArp) { + if (chan[i].std.arp.had) { if (i==3) { // noise - if (chan[i].std.arpMode) { - chan[i].baseFreq=chan[i].std.arp; + if (chan[i].std.arp.mode) { + chan[i].baseFreq=chan[i].std.arp.val; } else { - chan[i].baseFreq=chan[i].note+chan[i].std.arp; + chan[i].baseFreq=chan[i].note+chan[i].std.arp.val; } if (chan[i].baseFreq>255) chan[i].baseFreq=255; if (chan[i].baseFreq<0) chan[i].baseFreq=0; } else { if (!chan[i].inPorta) { - if (chan[i].std.arpMode) { - chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp); + if (chan[i].std.arp.mode) { + chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val); } else { - chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp); + chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp.val); } } } chan[i].freqChanged=true; } else { - if (chan[i].std.arpMode && chan[i].std.finishedArp) { + if (chan[i].std.arp.mode && chan[i].std.arp.finished) { chan[i].baseFreq=NOTE_PERIODIC(chan[i].note); chan[i].freqChanged=true; } } - if (chan[i].std.hadDuty) { - chan[i].duty=chan[i].std.duty; + if (chan[i].std.duty.had) { + chan[i].duty=chan[i].std.duty.val; if (i==3) { if (parent->song.properNoiseLayout) { chan[i].duty&=1; @@ -337,7 +337,7 @@ int DivPlatformNES::dispatch(DivCommand c) { case DIV_CMD_VOLUME: if (chan[c.chan].vol!=c.value) { chan[c.chan].vol=c.value; - if (!chan[c.chan].std.hasVol) { + if (!chan[c.chan].std.vol.has) { chan[c.chan].outVol=c.value; } if (chan[c.chan].active) { @@ -406,7 +406,7 @@ int DivPlatformNES::dispatch(DivCommand c) { break; case DIV_CMD_LEGATO: if (c.chan==3) break; - chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+((chan[c.chan].std.willArp && !chan[c.chan].std.arpMode)?(chan[c.chan].std.arp):(0))); + chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+((chan[c.chan].std.arp.will && !chan[c.chan].std.arp.mode)?(chan[c.chan].std.arp.val):(0))); chan[c.chan].freqChanged=true; chan[c.chan].note=c.value; break; diff --git a/src/engine/platform/opl.cpp b/src/engine/platform/opl.cpp index fcba9f80..6b4db8c6 100644 --- a/src/engine/platform/opl.cpp +++ b/src/engine/platform/opl.cpp @@ -233,8 +233,8 @@ void DivPlatformOPL::tick() { int ops=(slots[3][i]!=255 && chan[i].state.ops==4 && oplType==3)?4:2; chan[i].std.next(); - if (chan[i].std.hadVol) { - chan[i].outVol=(chan[i].vol*MIN(63,chan[i].std.vol))/63; + if (chan[i].std.vol.had) { + chan[i].outVol=(chan[i].vol*MIN(63,chan[i].std.vol.val))/63; for (int j=0; j1) { - if (m.hadWs) { - op.ws=m.ws; + if (m.ws.had) { + op.ws=m.ws.val; rWrite(baseAddr+ADDR_WS,op.ws&((oplType==3)?7:3)); } } - if (m.hadTl) { - op.tl=63-m.tl; + if (m.tl.had) { + op.tl=63-m.tl.val; } - if (m.hadKsl) { - op.ksl=m.ksl; + if (m.ksl.had) { + op.ksl=m.ksl.val; } - if (m.hadTl || m.hadKsl) { + if (m.tl.had || m.ksl.had) { if (isMuted[i]) { rWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6)); } else { @@ -528,7 +528,7 @@ int DivPlatformOPL::dispatch(DivCommand c) { } chan[c.chan].std.init(ins); - if (!chan[c.chan].std.willVol) { + if (!chan[c.chan].std.vol.will) { chan[c.chan].outVol=chan[c.chan].vol; } if (chan[c.chan].insChanged) { @@ -620,7 +620,7 @@ int DivPlatformOPL::dispatch(DivCommand c) { if (c.value>63) c.value=63; } chan[c.chan].vol=c.value; - if (!chan[c.chan].std.hasVol) { + if (!chan[c.chan].std.vol.has) { chan[c.chan].outVol=c.value; } int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2; diff --git a/src/engine/platform/opll.cpp b/src/engine/platform/opll.cpp index 55a1fa80..2c23639b 100644 --- a/src/engine/platform/opll.cpp +++ b/src/engine/platform/opll.cpp @@ -115,51 +115,51 @@ void DivPlatformOPLL::tick() { for (int i=0; i<11; i++) { chan[i].std.next(); - if (chan[i].std.hadVol) { - chan[i].outVol=(chan[i].vol*MIN(15,chan[i].std.vol))/15; + if (chan[i].std.vol.had) { + chan[i].outVol=(chan[i].vol*MIN(15,chan[i].std.vol.val))/15; if (i<9) { rWrite(0x30+i,((15-(chan[i].outVol*(15-chan[i].state.op[1].tl))/15)&15)|(chan[i].state.opllPreset<<4)); } } - if (chan[i].std.hadArp) { + if (chan[i].std.arp.had) { if (!chan[i].inPorta) { - if (chan[i].std.arpMode) { - chan[i].baseFreq=NOTE_FREQUENCY(chan[i].std.arp); + if (chan[i].std.arp.mode) { + chan[i].baseFreq=NOTE_FREQUENCY(chan[i].std.arp.val); } else { - chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note+(signed char)chan[i].std.arp); + chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note+(signed char)chan[i].std.arp.val); } } chan[i].freqChanged=true; } else { - if (chan[i].std.arpMode && chan[i].std.finishedArp) { + if (chan[i].std.arp.mode && chan[i].std.arp.finished) { chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note); chan[i].freqChanged=true; } } - if (chan[i].std.hadWave && chan[i].state.opllPreset!=16) { - chan[i].state.opllPreset=chan[i].std.wave; + if (chan[i].std.wave.had && chan[i].state.opllPreset!=16) { + chan[i].state.opllPreset=chan[i].std.wave.val; if (i<9) { rWrite(0x30+i,((15-(chan[i].outVol*(15-chan[i].state.op[1].tl))/15)&15)|(chan[i].state.opllPreset<<4)); } } if (chan[i].state.opllPreset==0) { - if (chan[i].std.hadAlg) { // SUS - chan[i].state.alg=chan[i].std.alg; + if (chan[i].std.alg.had) { // SUS + chan[i].state.alg=chan[i].std.alg.val; chan[i].freqChanged=true; } - if (chan[i].std.hadFb) { - chan[i].state.fb=chan[i].std.fb; + if (chan[i].std.fb.had) { + chan[i].state.fb=chan[i].std.fb.val; rWrite(0x03,(chan[i].state.op[1].ksl<<6)|((chan[i].state.fms&1)<<4)|((chan[i].state.ams&1)<<3)|chan[i].state.fb); } - if (chan[i].std.hadFms) { - chan[i].state.fms=chan[i].std.fms; + if (chan[i].std.fms.had) { + chan[i].state.fms=chan[i].std.fms.val; rWrite(0x03,(chan[i].state.op[1].ksl<<6)|((chan[i].state.fms&1)<<4)|((chan[i].state.ams&1)<<3)|chan[i].state.fb); } - if (chan[i].std.hadAms) { - chan[i].state.ams=chan[i].std.ams; + if (chan[i].std.ams.had) { + chan[i].state.ams=chan[i].std.ams.val; rWrite(0x03,(chan[i].state.op[1].ksl<<6)|((chan[i].state.fms&1)<<4)|((chan[i].state.ams&1)<<3)|chan[i].state.fb); } @@ -167,32 +167,32 @@ void DivPlatformOPLL::tick() { DivInstrumentFM::Operator& op=chan[i].state.op[j]; DivMacroInt::IntOp& m=chan[i].std.op[j]; - if (m.hadAm) { - op.am=m.am; + if (m.am.had) { + op.am=m.am.val; rWrite(0x00+j,(op.am<<7)|(op.vib<<6)|((op.ssgEnv&8)<<2)|(op.ksr<<4)|(op.mult)); } - if (m.hadAr) { - op.ar=m.ar; + if (m.ar.had) { + op.ar=m.ar.val; rWrite(0x04+j,(op.ar<<4)|(op.dr)); } - if (m.hadDr) { - op.dr=m.dr; + if (m.dr.had) { + op.dr=m.dr.val; rWrite(0x04+j,(op.ar<<4)|(op.dr)); } - if (m.hadMult) { - op.mult=m.mult; + if (m.mult.had) { + op.mult=m.mult.val; rWrite(0x00+j,(op.am<<7)|(op.vib<<6)|((op.ssgEnv&8)<<2)|(op.ksr<<4)|(op.mult)); } - if (m.hadRr) { - op.rr=m.rr; + if (m.rr.had) { + op.rr=m.rr.val; rWrite(0x06+j,(op.sl<<4)|(op.rr)); } - if (m.hadSl) { - op.sl=m.sl; + if (m.sl.had) { + op.sl=m.sl.val; rWrite(0x06+j,(op.sl<<4)|(op.rr)); } - if (m.hadTl) { - op.tl=((j==1)?15:63)-m.tl; + if (m.tl.had) { + op.tl=((j==1)?15:63)-m.tl.val; if (j==1) { if (i<9) { rWrite(0x30+i,((15-(chan[i].outVol*(15-chan[i].state.op[1].tl))/15)&15)|(chan[i].state.opllPreset<<4)); @@ -202,24 +202,24 @@ void DivPlatformOPLL::tick() { } } - if (m.hadEgt) { - op.ssgEnv=(m.egt&1)?8:0; + if (m.egt.had) { + op.ssgEnv=(m.egt.val&1)?8:0; rWrite(0x00+j,(op.am<<7)|(op.vib<<6)|((op.ssgEnv&8)<<2)|(op.ksr<<4)|(op.mult)); } - if (m.hadKsl) { - op.ksl=m.ksl; + if (m.ksl.had) { + op.ksl=m.ksl.val; if (j==1) { rWrite(0x02,(chan[i].state.op[0].ksl<<6)|(chan[i].state.op[0].tl&63)); } else { rWrite(0x03,(chan[i].state.op[1].ksl<<6)|((chan[i].state.fms&1)<<4)|((chan[i].state.ams&1)<<3)|chan[i].state.fb); } } - if (m.hadKsr) { - op.ksr=m.ksr; + if (m.ksr.had) { + op.ksr=m.ksr.val; rWrite(0x00+j,(op.am<<7)|(op.vib<<6)|((op.ssgEnv&8)<<2)|(op.ksr<<4)|(op.mult)); } - if (m.hadVib) { - op.vib=m.vib; + if (m.vib.had) { + op.vib=m.vib.val; rWrite(0x00+j,(op.am<<7)|(op.vib<<6)|((op.ssgEnv&8)<<2)|(op.ksr<<4)|(op.mult)); } } @@ -361,7 +361,7 @@ int DivPlatformOPLL::dispatch(DivCommand c) { } chan[c.chan].std.init(ins); - if (!chan[c.chan].std.willVol) { + if (!chan[c.chan].std.vol.will) { chan[c.chan].outVol=chan[c.chan].vol; } @@ -490,7 +490,7 @@ int DivPlatformOPLL::dispatch(DivCommand c) { case DIV_CMD_VOLUME: { if (c.chan>=9 && !properDrums) return 0; chan[c.chan].vol=c.value; - if (!chan[c.chan].std.hasVol) { + if (!chan[c.chan].std.vol.has) { chan[c.chan].outVol=c.value; } if (c.chan>=6 && properDrums) { diff --git a/src/engine/platform/pce.cpp b/src/engine/platform/pce.cpp index aa78aa62..0789c804 100644 --- a/src/engine/platform/pce.cpp +++ b/src/engine/platform/pce.cpp @@ -149,39 +149,39 @@ static unsigned char noiseFreq[12]={ void DivPlatformPCE::tick() { for (int i=0; i<6; i++) { chan[i].std.next(); - if (chan[i].std.hadVol) { - chan[i].outVol=((chan[i].vol&31)*MIN(31,chan[i].std.vol))>>5; + if (chan[i].std.vol.had) { + chan[i].outVol=((chan[i].vol&31)*MIN(31,chan[i].std.vol.val))>>5; if (chan[i].furnaceDac) { // ignore for now } else { chWrite(i,0x04,0x80|chan[i].outVol); } } - if (chan[i].std.hadDuty && i>=4) { - chan[i].noise=chan[i].std.duty; + if (chan[i].std.duty.had && i>=4) { + chan[i].noise=chan[i].std.duty.val; chan[i].freqChanged=true; int noiseSeek=chan[i].note; if (noiseSeek<0) noiseSeek=0; chWrite(i,0x07,chan[i].noise?(0x80|(parent->song.properNoiseLayout?(noiseSeek&31):noiseFreq[noiseSeek%12])):0); } - if (chan[i].std.hadArp) { + if (chan[i].std.arp.had) { if (!chan[i].inPorta) { - if (chan[i].std.arpMode) { - chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp); + if (chan[i].std.arp.mode) { + chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val); // noise - int noiseSeek=chan[i].std.arp; + int noiseSeek=chan[i].std.arp.val; if (noiseSeek<0) noiseSeek=0; chWrite(i,0x07,chan[i].noise?(0x80|(parent->song.properNoiseLayout?(noiseSeek&31):noiseFreq[noiseSeek%12])):0); } else { - chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp); - int noiseSeek=chan[i].note+chan[i].std.arp; + chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp.val); + int noiseSeek=chan[i].note+chan[i].std.arp.val; if (noiseSeek<0) noiseSeek=0; chWrite(i,0x07,chan[i].noise?(0x80|(parent->song.properNoiseLayout?(noiseSeek&31):noiseFreq[noiseSeek%12])):0); } } chan[i].freqChanged=true; } else { - if (chan[i].std.arpMode && chan[i].std.finishedArp) { + if (chan[i].std.arp.mode && chan[i].std.arp.finished) { chan[i].baseFreq=NOTE_PERIODIC(chan[i].note); int noiseSeek=chan[i].note; if (noiseSeek<0) noiseSeek=0; @@ -189,9 +189,9 @@ void DivPlatformPCE::tick() { chan[i].freqChanged=true; } } - if (chan[i].std.hadWave && !chan[i].pcm) { - if (chan[i].wave!=chan[i].std.wave || chan[i].ws.activeChanged()) { - chan[i].wave=chan[i].std.wave; + if (chan[i].std.wave.had && !chan[i].pcm) { + if (chan[i].wave!=chan[i].std.wave.val || chan[i].ws.activeChanged()) { + chan[i].wave=chan[i].std.wave.val; chan[i].ws.changeWave1(chan[i].wave); if (!chan[i].keyOff) chan[i].keyOn=true; } @@ -332,14 +332,14 @@ int DivPlatformPCE::dispatch(DivCommand c) { case DIV_CMD_VOLUME: if (chan[c.chan].vol!=c.value) { chan[c.chan].vol=c.value; - if (!chan[c.chan].std.hasVol) { + if (!chan[c.chan].std.vol.has) { chan[c.chan].outVol=c.value; if (chan[c.chan].active) chWrite(c.chan,0x04,0x80|chan[c.chan].outVol); } } break; case DIV_CMD_GET_VOLUME: - if (chan[c.chan].std.hasVol) { + if (chan[c.chan].std.vol.has) { return chan[c.chan].vol; } return chan[c.chan].outVol; @@ -409,7 +409,7 @@ int DivPlatformPCE::dispatch(DivCommand c) { break; } case DIV_CMD_LEGATO: - chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+((chan[c.chan].std.willArp && !chan[c.chan].std.arpMode)?(chan[c.chan].std.arp):(0))); + chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+((chan[c.chan].std.arp.will && !chan[c.chan].std.arp.mode)?(chan[c.chan].std.arp.val):(0))); chan[c.chan].freqChanged=true; chan[c.chan].note=c.value; break; diff --git a/src/engine/platform/pcspkr.cpp b/src/engine/platform/pcspkr.cpp index 5cfcdac3..ee6ba7ef 100644 --- a/src/engine/platform/pcspkr.cpp +++ b/src/engine/platform/pcspkr.cpp @@ -167,21 +167,21 @@ void DivPlatformPCSpeaker::acquire(short* bufL, short* bufR, size_t start, size_ void DivPlatformPCSpeaker::tick() { for (int i=0; i<1; i++) { chan[i].std.next(); - if (chan[i].std.hadVol) { - chan[i].outVol=(chan[i].vol && chan[i].std.vol); + if (chan[i].std.vol.had) { + chan[i].outVol=(chan[i].vol && chan[i].std.vol.val); on=chan[i].outVol; } - if (chan[i].std.hadArp) { + if (chan[i].std.arp.had) { if (!chan[i].inPorta) { - if (chan[i].std.arpMode) { - chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp); + if (chan[i].std.arp.mode) { + chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val); } else { - chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp); + chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp.val); } } chan[i].freqChanged=true; } else { - if (chan[i].std.arpMode && chan[i].std.finishedArp) { + if (chan[i].std.arp.mode && chan[i].std.arp.finished) { chan[i].baseFreq=NOTE_PERIODIC(chan[i].note); chan[i].freqChanged=true; } @@ -233,7 +233,7 @@ int DivPlatformPCSpeaker::dispatch(DivCommand c) { case DIV_CMD_VOLUME: if (chan[c.chan].vol!=c.value) { chan[c.chan].vol=c.value; - if (!chan[c.chan].std.hasVol) { + if (!chan[c.chan].std.vol.has) { chan[c.chan].outVol=c.value; } if (chan[c.chan].active) { @@ -273,7 +273,7 @@ int DivPlatformPCSpeaker::dispatch(DivCommand c) { } case DIV_CMD_LEGATO: if (c.chan==3) break; - chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+((chan[c.chan].std.willArp && !chan[c.chan].std.arpMode)?(chan[c.chan].std.arp):(0))); + chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+((chan[c.chan].std.arp.will && !chan[c.chan].std.arp.mode)?(chan[c.chan].std.arp.val):(0))); chan[c.chan].freqChanged=true; chan[c.chan].note=c.value; break; diff --git a/src/engine/platform/pet.cpp b/src/engine/platform/pet.cpp index b89f9510..e46277e0 100644 --- a/src/engine/platform/pet.cpp +++ b/src/engine/platform/pet.cpp @@ -87,28 +87,28 @@ void DivPlatformPET::writeOutVol() { void DivPlatformPET::tick() { chan.std.next(); - if (chan.std.hadVol) { - chan.outVol=chan.std.vol&chan.vol; + if (chan.std.vol.had) { + chan.outVol=chan.std.vol.val&chan.vol; writeOutVol(); } - if (chan.std.hadArp) { + if (chan.std.arp.had) { if (!chan.inPorta) { - if (chan.std.arpMode) { - chan.baseFreq=NOTE_PERIODIC(chan.std.arp); + if (chan.std.arp.mode) { + chan.baseFreq=NOTE_PERIODIC(chan.std.arp.val); } else { - chan.baseFreq=NOTE_PERIODIC(chan.note+chan.std.arp); + chan.baseFreq=NOTE_PERIODIC(chan.note+chan.std.arp.val); } } chan.freqChanged=true; } else { - if (chan.std.arpMode && chan.std.finishedArp) { + if (chan.std.arp.mode && chan.std.arp.finished) { chan.baseFreq=NOTE_PERIODIC(chan.note); chan.freqChanged=true; } } - if (chan.std.hadWave) { - if (chan.wave!=chan.std.wave) { - chan.wave=chan.std.wave; + if (chan.std.wave.had) { + if (chan.wave!=chan.std.wave.val) { + chan.wave=chan.std.wave.val; rWrite(10,chan.wave); } } @@ -118,7 +118,7 @@ void DivPlatformPET::tick() { if (chan.freq<2) chan.freq=2; rWrite(8,chan.freq-2); if (chan.keyOn) { - if (!chan.std.willVol) { + if (!chan.std.vol.will) { chan.outVol=chan.vol; writeOutVol(); } @@ -163,7 +163,7 @@ int DivPlatformPET::dispatch(DivCommand c) { case DIV_CMD_VOLUME: if (chan.vol!=c.value) { chan.vol=c.value; - if (!chan.std.hadVol) { + if (!chan.std.vol.had) { chan.outVol=chan.vol; writeOutVol(); } @@ -204,7 +204,7 @@ int DivPlatformPET::dispatch(DivCommand c) { break; } case DIV_CMD_LEGATO: - chan.baseFreq=NOTE_PERIODIC(c.value+((chan.std.willArp && !chan.std.arpMode)?(chan.std.arp):(0))); + chan.baseFreq=NOTE_PERIODIC(c.value+((chan.std.arp.will && !chan.std.arp.mode)?(chan.std.arp.val):(0))); chan.freqChanged=true; chan.note=c.value; break; diff --git a/src/engine/platform/qsound.cpp b/src/engine/platform/qsound.cpp index 12bf1c58..a63ca9e5 100644 --- a/src/engine/platform/qsound.cpp +++ b/src/engine/platform/qsound.cpp @@ -277,8 +277,8 @@ void DivPlatformQSound::acquire(short* bufL, short* bufR, size_t start, size_t l void DivPlatformQSound::tick() { for (int i=0; i<16; i++) { chan[i].std.next(); - if (chan[i].std.hadVol) { - chan[i].outVol=((chan[i].vol&0xff)*chan[i].std.vol)>>6; + if (chan[i].std.vol.had) { + chan[i].outVol=((chan[i].vol&0xff)*chan[i].std.vol.val)>>6; // Check if enabled and write volume if (chan[i].active) { rWrite(q1_reg_map[Q1V_VOL][i], chan[i].outVol << 4); @@ -311,17 +311,17 @@ void DivPlatformQSound::tick() { qsound_loop = length - s->loopStart; } } - if (chan[i].std.hadArp) { + if (chan[i].std.arp.had) { if (!chan[i].inPorta) { - if (chan[i].std.arpMode) { - chan[i].baseFreq=off*QS_NOTE_FREQUENCY(chan[i].std.arp); + if (chan[i].std.arp.mode) { + chan[i].baseFreq=off*QS_NOTE_FREQUENCY(chan[i].std.arp.val); } else { - chan[i].baseFreq=off*QS_NOTE_FREQUENCY(chan[i].note+chan[i].std.arp); + chan[i].baseFreq=off*QS_NOTE_FREQUENCY(chan[i].note+chan[i].std.arp.val); } } chan[i].freqChanged=true; } else { - if (chan[i].std.arpMode && chan[i].std.finishedArp) { + if (chan[i].std.arp.mode && chan[i].std.arp.finished) { chan[i].baseFreq=off*QS_NOTE_FREQUENCY(chan[i].note); chan[i].freqChanged=true; } @@ -338,7 +338,7 @@ void DivPlatformQSound::tick() { rWrite(q1_reg_map[Q1V_PHASE][i], 0x8000); //logW("ch %d bank=%04x, addr=%04x, end=%04x, loop=%04x!\n",i,qsound_bank,qsound_addr,qsound_end,qsound_loop); // Write sample address. Enable volume - if (!chan[i].std.hadVol) { + if (!chan[i].std.vol.had) { rWrite(q1_reg_map[Q1V_VOL][i], chan[i].vol << 4); } } @@ -404,7 +404,7 @@ int DivPlatformQSound::dispatch(DivCommand c) { case DIV_CMD_VOLUME: if (chan[c.chan].vol!=c.value) { chan[c.chan].vol=c.value; - if (!chan[c.chan].std.hasVol) { + if (!chan[c.chan].std.vol.has) { // Check if enabled and write volume chan[c.chan].outVol=c.value; if (chan[c.chan].active && c.chan < 16) { @@ -414,7 +414,7 @@ int DivPlatformQSound::dispatch(DivCommand c) { } break; case DIV_CMD_GET_VOLUME: - if (chan[c.chan].std.hasVol) { + if (chan[c.chan].std.vol.has) { return chan[c.chan].vol; } return chan[c.chan].outVol; @@ -477,7 +477,7 @@ int DivPlatformQSound::dispatch(DivCommand c) { off=(double)s->centerRate/24038.0/16.0; } } - chan[c.chan].baseFreq=off*QS_NOTE_FREQUENCY(c.value+((chan[c.chan].std.willArp && !chan[c.chan].std.arpMode)?(chan[c.chan].std.arp-12):(0))); + chan[c.chan].baseFreq=off*QS_NOTE_FREQUENCY(c.value+((chan[c.chan].std.arp.will && !chan[c.chan].std.arp.mode)?(chan[c.chan].std.arp.val-12):(0))); chan[c.chan].freqChanged=true; chan[c.chan].note=c.value; break; diff --git a/src/engine/platform/saa.cpp b/src/engine/platform/saa.cpp index 0bafaf15..db614ee7 100644 --- a/src/engine/platform/saa.cpp +++ b/src/engine/platform/saa.cpp @@ -135,8 +135,8 @@ inline unsigned char applyPan(unsigned char vol, unsigned char pan) { void DivPlatformSAA1099::tick() { for (int i=0; i<6; i++) { chan[i].std.next(); - if (chan[i].std.hadVol) { - chan[i].outVol=MIN(15,chan[i].std.vol)-(15-(chan[i].vol&15)); + if (chan[i].std.vol.had) { + chan[i].outVol=MIN(15,chan[i].std.vol.val)-(15-(chan[i].vol&15)); if (chan[i].outVol<0) chan[i].outVol=0; if (isMuted[i]) { rWrite(i,0); @@ -144,30 +144,30 @@ void DivPlatformSAA1099::tick() { rWrite(i,applyPan(chan[i].outVol&15,chan[i].pan)); } } - if (chan[i].std.hadArp) { + if (chan[i].std.arp.had) { if (!chan[i].inPorta) { - if (chan[i].std.arpMode) { - chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp); + if (chan[i].std.arp.mode) { + chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val); } else { - chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp); + chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp.val); } } chan[i].freqChanged=true; } else { - if (chan[i].std.arpMode && chan[i].std.finishedArp) { + if (chan[i].std.arp.mode && chan[i].std.arp.finished) { chan[i].baseFreq=NOTE_PERIODIC(chan[i].note); chan[i].freqChanged=true; } } - if (chan[i].std.hadDuty) { - saaNoise[i/3]=chan[i].std.duty&3; + if (chan[i].std.duty.had) { + saaNoise[i/3]=chan[i].std.duty.val&3; rWrite(0x16,saaNoise[0]|(saaNoise[1]<<4)); } - if (chan[i].std.hadWave) { - chan[i].psgMode=chan[i].std.wave&3; + if (chan[i].std.wave.had) { + chan[i].psgMode=chan[i].std.wave.val&3; } - if (chan[i].std.hadEx1) { - saaEnv[i/3]=chan[i].std.ex1; + if (chan[i].std.ex1.had) { + saaEnv[i/3]=chan[i].std.ex1.val; rWrite(0x18+(i/3),saaEnv[i/3]); } if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { @@ -253,7 +253,7 @@ int DivPlatformSAA1099::dispatch(DivCommand c) { break; case DIV_CMD_VOLUME: { chan[c.chan].vol=c.value; - if (!chan[c.chan].std.hasVol) { + if (!chan[c.chan].std.vol.has) { chan[c.chan].outVol=c.value; } if (isMuted[c.chan]) { diff --git a/src/engine/platform/segapcm.cpp b/src/engine/platform/segapcm.cpp index 69d8bd6e..b87ee9a8 100644 --- a/src/engine/platform/segapcm.cpp +++ b/src/engine/platform/segapcm.cpp @@ -80,21 +80,21 @@ void DivPlatformSegaPCM::tick() { for (int i=0; i<16; i++) { chan[i].std.next(); - if (chan[i].std.hadVol) { - chan[i].outVol=(chan[i].vol*MIN(127,chan[i].std.vol))/127; + if (chan[i].std.vol.had) { + chan[i].outVol=(chan[i].vol*MIN(127,chan[i].std.vol.val))/127; } - if (chan[i].std.hadArp) { + if (chan[i].std.arp.had) { if (!chan[i].inPorta) { - if (chan[i].std.arpMode) { - chan[i].baseFreq=(chan[i].std.arp<<6); + if (chan[i].std.arp.mode) { + chan[i].baseFreq=(chan[i].std.arp.val<<6); } else { - chan[i].baseFreq=((chan[i].note+(signed char)chan[i].std.arp)<<6); + chan[i].baseFreq=((chan[i].note+(signed char)chan[i].std.arp.val)<<6); } } chan[i].freqChanged=true; } else { - if (chan[i].std.arpMode && chan[i].std.finishedArp) { + if (chan[i].std.arp.mode && chan[i].std.arp.finished) { chan[i].baseFreq=(chan[i].note<<6); chan[i].freqChanged=true; } @@ -214,7 +214,7 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) { break; case DIV_CMD_VOLUME: { chan[c.chan].vol=c.value; - if (!chan[c.chan].std.hasVol) { + if (!chan[c.chan].std.vol.has) { chan[c.chan].outVol=c.value; } chan[c.chan].chVolL=c.value; diff --git a/src/engine/platform/sms.cpp b/src/engine/platform/sms.cpp index 08cf568d..f4bbc46e 100644 --- a/src/engine/platform/sms.cpp +++ b/src/engine/platform/sms.cpp @@ -56,21 +56,21 @@ int DivPlatformSMS::acquireOne() { void DivPlatformSMS::tick() { for (int i=0; i<4; i++) { chan[i].std.next(); - if (chan[i].std.hadVol) { - chan[i].outVol=MIN(15,chan[i].std.vol)-(15-(chan[i].vol&15)); + if (chan[i].std.vol.had) { + chan[i].outVol=MIN(15,chan[i].std.vol.val)-(15-(chan[i].vol&15)); if (chan[i].outVol<0) chan[i].outVol=0; // old formula - // ((chan[i].vol&15)*MIN(15,chan[i].std.vol))>>4; + // ((chan[i].vol&15)*MIN(15,chan[i].std.vol.val))>>4; rWrite(0x90|(i<<5)|(isMuted[i]?15:(15-(chan[i].outVol&15)))); } - if (chan[i].std.hadArp) { + if (chan[i].std.arp.had) { if (!chan[i].inPorta) { - if (chan[i].std.arpMode) { - chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp); - chan[i].actualNote=chan[i].std.arp; + if (chan[i].std.arp.mode) { + chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val); + chan[i].actualNote=chan[i].std.arp.val; } else { // TODO: check whether this weird octave boundary thing applies to other systems as well - int areYouSerious=chan[i].note+chan[i].std.arp; + int areYouSerious=chan[i].note+chan[i].std.arp.val; while (areYouSerious>0x60) areYouSerious-=12; chan[i].baseFreq=NOTE_PERIODIC(areYouSerious); chan[i].actualNote=areYouSerious; @@ -78,15 +78,15 @@ void DivPlatformSMS::tick() { chan[i].freqChanged=true; } } else { - if (chan[i].std.arpMode && chan[i].std.finishedArp) { + if (chan[i].std.arp.mode && chan[i].std.arp.finished) { chan[i].baseFreq=NOTE_PERIODIC(chan[i].note); chan[i].actualNote=chan[i].note; chan[i].freqChanged=true; } } - if (i==3) if (chan[i].std.hadDuty) { - snNoiseMode=chan[i].std.duty; - if (chan[i].std.duty<2) { + if (i==3) if (chan[i].std.duty.had) { + snNoiseMode=chan[i].std.duty.val; + if (chan[i].std.duty.val<2) { chan[3].freqChanged=false; } updateSNMode=true; @@ -130,11 +130,11 @@ void DivPlatformSMS::tick() { } } else { // 3 fixed values unsigned char value; - if (chan[3].std.hadArp) { - if (chan[3].std.arpMode) { - value=chan[3].std.arp%12; + if (chan[3].std.arp.had) { + if (chan[3].std.arp.mode) { + value=chan[3].std.arp.val%12; } else { - value=(chan[3].note+chan[3].std.arp)%12; + value=(chan[3].note+chan[3].std.arp.val)%12; } } else { value=chan[3].note%12; @@ -181,14 +181,14 @@ int DivPlatformSMS::dispatch(DivCommand c) { case DIV_CMD_VOLUME: if (chan[c.chan].vol!=c.value) { chan[c.chan].vol=c.value; - if (!chan[c.chan].std.hasVol) { + if (!chan[c.chan].std.vol.has) { chan[c.chan].outVol=c.value; } if (chan[c.chan].active) rWrite(0x90|c.chan<<5|(isMuted[c.chan]?15:(15-(chan[c.chan].vol&15)))); } break; case DIV_CMD_GET_VOLUME: - if (chan[c.chan].std.hasVol) { + if (chan[c.chan].std.vol.has) { return chan[c.chan].vol; } return chan[c.chan].outVol; @@ -225,7 +225,7 @@ int DivPlatformSMS::dispatch(DivCommand c) { updateSNMode=true; break; case DIV_CMD_LEGATO: - chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+((chan[c.chan].std.willArp && !chan[c.chan].std.arpMode)?(chan[c.chan].std.arp):(0))); + chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+((chan[c.chan].std.arp.will && !chan[c.chan].std.arp.mode)?(chan[c.chan].std.arp.val):(0))); chan[c.chan].freqChanged=true; chan[c.chan].note=c.value; chan[c.chan].actualNote=c.value; diff --git a/src/engine/platform/swan.cpp b/src/engine/platform/swan.cpp index 6966a2d1..802f27b8 100644 --- a/src/engine/platform/swan.cpp +++ b/src/engine/platform/swan.cpp @@ -145,31 +145,31 @@ void DivPlatformSwan::tick() { unsigned char sndCtrl=(pcm?0x20:0)|(sweep?0x40:0)|((noise>0)?0x80:0); for (int i=0; i<4; i++) { chan[i].std.next(); - if (chan[i].std.hadVol) { - int env=chan[i].std.vol; + if (chan[i].std.vol.had) { + int env=chan[i].std.vol.val; if(parent->getIns(chan[i].ins)->type==DIV_INS_AMIGA) { env=MIN(env/4,15); } calcAndWriteOutVol(i,env); } - if (chan[i].std.hadArp) { + if (chan[i].std.arp.had) { if (!chan[i].inPorta) { - if (chan[i].std.arpMode) { - chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp); + if (chan[i].std.arp.mode) { + chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val); } else { - chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp); + chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp.val); } } chan[i].freqChanged=true; } else { - if (chan[i].std.arpMode && chan[i].std.finishedArp) { + if (chan[i].std.arp.mode && chan[i].std.arp.finished) { chan[i].baseFreq=NOTE_PERIODIC(chan[i].note); chan[i].freqChanged=true; } } - if (chan[i].std.hadWave && !(i==1 && pcm)) { - if (chan[i].wave!=chan[i].std.wave || chan[i].ws.activeChanged()) { - chan[i].wave=chan[i].std.wave; + if (chan[i].std.wave.had && !(i==1 && pcm)) { + if (chan[i].wave!=chan[i].std.wave.val || chan[i].ws.activeChanged()) { + chan[i].wave=chan[i].std.wave.val; chan[i].ws.changeWave1(chan[i].wave); } } @@ -200,7 +200,7 @@ void DivPlatformSwan::tick() { rWrite(i*2,rVal&0xff); rWrite(i*2+1,rVal>>8); if (chan[i].keyOn) { - if (!chan[i].std.willVol) { + if (!chan[i].std.vol.will) { calcAndWriteOutVol(i,15); } chan[i].keyOn=false; @@ -211,8 +211,8 @@ void DivPlatformSwan::tick() { chan[i].freqChanged=false; } } - if (chan[3].std.hadDuty) { - noise=chan[3].std.duty; + if (chan[3].std.duty.had) { + noise=chan[3].std.duty.val; if (noise>0) { rWrite(0x0e,((noise-1)&0x07)|0x18); sndCtrl|=0x80; @@ -319,7 +319,7 @@ int DivPlatformSwan::dispatch(DivCommand c) { case DIV_CMD_VOLUME: if (chan[c.chan].vol!=c.value) { chan[c.chan].vol=c.value; - if (!chan[c.chan].std.hadVol) { + if (!chan[c.chan].std.vol.had) { calcAndWriteOutVol(c.chan,15); } } @@ -391,11 +391,11 @@ int DivPlatformSwan::dispatch(DivCommand c) { break; case DIV_CMD_PANNING: { chan[c.chan].pan=c.value; - calcAndWriteOutVol(c.chan,chan[c.chan].std.willVol?chan[c.chan].std.vol:15); + calcAndWriteOutVol(c.chan,chan[c.chan].std.vol.will?chan[c.chan].std.vol.val:15); break; } case DIV_CMD_LEGATO: - chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+((chan[c.chan].std.willArp && !chan[c.chan].std.arpMode)?(chan[c.chan].std.arp):(0))); + chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+((chan[c.chan].std.arp.will && !chan[c.chan].std.arp.mode)?(chan[c.chan].std.arp.val):(0))); chan[c.chan].freqChanged=true; chan[c.chan].note=c.value; break; diff --git a/src/engine/platform/tia.cpp b/src/engine/platform/tia.cpp index 2b99731f..e06c5c74 100644 --- a/src/engine/platform/tia.cpp +++ b/src/engine/platform/tia.cpp @@ -87,8 +87,8 @@ unsigned char DivPlatformTIA::dealWithFreq(unsigned char shape, int base, int pi void DivPlatformTIA::tick() { for (int i=0; i<2; i++) { chan[i].std.next(); - if (chan[i].std.hadVol) { - chan[i].outVol=MIN(15,chan[i].std.vol)-(15-(chan[i].vol&15)); + if (chan[i].std.vol.had) { + chan[i].outVol=MIN(15,chan[i].std.vol.val)-(15-(chan[i].vol&15)); if (chan[i].outVol<0) chan[i].outVol=0; if (isMuted[i]) { rWrite(0x19+i,0); @@ -96,29 +96,29 @@ void DivPlatformTIA::tick() { rWrite(0x19+i,chan[i].outVol&15); } } - if (chan[i].std.hadArp) { + if (chan[i].std.arp.had) { if (!chan[i].inPorta) { - if (chan[i].std.arpMode) { - chan[i].baseFreq=0x80000000|chan[i].std.arp; + if (chan[i].std.arp.mode) { + chan[i].baseFreq=0x80000000|chan[i].std.arp.val; } else { - chan[i].baseFreq=(chan[i].note+chan[i].std.arp)<<8; + chan[i].baseFreq=(chan[i].note+chan[i].std.arp.val)<<8; } } chan[i].freqChanged=true; } else { - if (chan[i].std.arpMode && chan[i].std.finishedArp) { + if (chan[i].std.arp.mode && chan[i].std.arp.finished) { chan[i].baseFreq=chan[i].note<<8; chan[i].freqChanged=true; } } - if (chan[i].std.hadWave) { - chan[i].shape=chan[i].std.wave&15; + if (chan[i].std.wave.had) { + chan[i].shape=chan[i].std.wave.val&15; rWrite(0x15+i,chan[i].shape); chan[i].freqChanged=true; } if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { if (chan[i].insChanged) { - if (!chan[i].std.willWave) { + if (!chan[i].std.wave.will) { chan[i].shape=4; rWrite(0x15+i,chan[i].shape); } @@ -179,7 +179,7 @@ int DivPlatformTIA::dispatch(DivCommand c) { break; case DIV_CMD_VOLUME: { chan[c.chan].vol=c.value; - if (!chan[c.chan].std.hasVol) { + if (!chan[c.chan].std.vol.has) { chan[c.chan].outVol=c.value; } if (isMuted[c.chan]) { diff --git a/src/engine/platform/tx81z.cpp b/src/engine/platform/tx81z.cpp index e9e817cd..8ae4c688 100644 --- a/src/engine/platform/tx81z.cpp +++ b/src/engine/platform/tx81z.cpp @@ -184,8 +184,8 @@ void DivPlatformTX81Z::tick() { for (int i=0; i<8; i++) { chan[i].std.next(); - if (chan[i].std.hadVol) { - chan[i].outVol=(chan[i].vol*MIN(127,chan[i].std.vol))/127; + if (chan[i].std.vol.had) { + chan[i].outVol=(chan[i].vol*MIN(127,chan[i].std.vol.val))/127; for (int j=0; j<4; j++) { unsigned short baseAddr=chanOffs[i]|opOffs[j]; DivInstrumentFM::Operator& op=chan[i].state.op[j]; @@ -197,50 +197,50 @@ void DivPlatformTX81Z::tick() { } } - if (chan[i].std.hadArp) { + if (chan[i].std.arp.had) { if (!chan[i].inPorta) { - if (chan[i].std.arpMode) { - chan[i].baseFreq=NOTE_LINEAR(chan[i].std.arp); + if (chan[i].std.arp.mode) { + chan[i].baseFreq=NOTE_LINEAR(chan[i].std.arp.val); } else { - chan[i].baseFreq=NOTE_LINEAR(chan[i].note+(signed char)chan[i].std.arp); + chan[i].baseFreq=NOTE_LINEAR(chan[i].note+(signed char)chan[i].std.arp.val); } } chan[i].freqChanged=true; } else { - if (chan[i].std.arpMode && chan[i].std.finishedArp) { + if (chan[i].std.arp.mode && chan[i].std.arp.finished) { chan[i].baseFreq=NOTE_LINEAR(chan[i].note); chan[i].freqChanged=true; } } - if (chan[i].std.hadDuty) { - if (chan[i].std.duty>0) { - rWrite(0x0f,0x80|(0x20-chan[i].std.duty)); + if (chan[i].std.duty.had) { + if (chan[i].std.duty.val>0) { + rWrite(0x0f,0x80|(0x20-chan[i].std.duty.val)); } else { rWrite(0x0f,0); } } - if (chan[i].std.hadWave) { - rWrite(0x1b,chan[i].std.wave&3); + if (chan[i].std.wave.had) { + rWrite(0x1b,chan[i].std.wave.val&3); } - if (chan[i].std.hadEx1) { - amDepth=chan[i].std.ex1; + if (chan[i].std.ex1.had) { + amDepth=chan[i].std.ex1.val; immWrite(0x19,amDepth); } - if (chan[i].std.hadEx2) { - pmDepth=chan[i].std.ex2; + if (chan[i].std.ex2.had) { + pmDepth=chan[i].std.ex2.val; immWrite(0x19,0x80|pmDepth); } - if (chan[i].std.hadEx3) { - immWrite(0x18,chan[i].std.ex3); + if (chan[i].std.ex3.had) { + immWrite(0x18,chan[i].std.ex3.val); } - if (chan[i].std.hadAlg) { - chan[i].state.alg=chan[i].std.alg; + if (chan[i].std.alg.had) { + chan[i].state.alg=chan[i].std.alg.val; if (isMuted[i]) { immWrite(chanOffs[i]+ADDR_LR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3)|0x40); } else { @@ -260,72 +260,72 @@ void DivPlatformTX81Z::tick() { } } } - if (chan[i].std.hadFb) { - chan[i].state.fb=chan[i].std.fb; + if (chan[i].std.fb.had) { + chan[i].state.fb=chan[i].std.fb.val; if (isMuted[i]) { immWrite(chanOffs[i]+ADDR_LR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3)|0x40); } else { immWrite(chanOffs[i]+ADDR_LR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3)|(chan[i].active?0:0x40)|(chan[i].chVolR<<7)); } } - if (chan[i].std.hadFms) { - chan[i].state.fms=chan[i].std.fms; + if (chan[i].std.fms.had) { + chan[i].state.fms=chan[i].std.fms.val; rWrite(chanOffs[i]+ADDR_FMS_AMS,((chan[i].state.fms&7)<<4)|(chan[i].state.ams&3)); } - if (chan[i].std.hadAms) { - chan[i].state.ams=chan[i].std.ams; + if (chan[i].std.ams.had) { + chan[i].state.ams=chan[i].std.ams.val; rWrite(chanOffs[i]+ADDR_FMS_AMS,((chan[i].state.fms&7)<<4)|(chan[i].state.ams&3)); } for (int j=0; j<4; j++) { unsigned short baseAddr=chanOffs[i]|opOffs[j]; DivInstrumentFM::Operator& op=chan[i].state.op[j]; DivMacroInt::IntOp& m=chan[i].std.op[j]; - if (m.hadAm) { - op.am=m.am; + if (m.am.had) { + op.am=m.am.val; rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7)); } - if (m.hadAr) { - op.ar=m.ar; + if (m.ar.had) { + op.ar=m.ar.val; rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.egt<<5)|(op.rs<<6)); } - if (m.hadDr) { - op.dr=m.dr; + if (m.dr.had) { + op.dr=m.dr.val; rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7)); } - if (m.hadMult) { - op.mult=m.mult; + if (m.mult.had) { + op.mult=m.mult.val; rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4)); } - if (m.hadRr) { - op.rr=m.rr; + if (m.rr.had) { + op.rr=m.rr.val; rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4)); } - if (m.hadSl) { - op.sl=m.sl; + if (m.sl.had) { + op.sl=m.sl.val; rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4)); } - if (m.hadTl) { - op.tl=127-m.tl; + if (m.tl.had) { + op.tl=127-m.tl.val; if (isOutput[chan[i].state.alg][j]) { rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); } } - if (m.hadRs) { - op.rs=m.rs; + if (m.rs.had) { + op.rs=m.rs.val; rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.egt<<5)|(op.rs<<6)); } - if (m.hadDt) { - op.dt=m.dt; + if (m.dt.had) { + op.dt=m.dt.val; rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4)); } - if (m.hadD2r) { - op.d2r=m.d2r; + if (m.d2r.had) { + op.d2r=m.d2r.val; rWrite(baseAddr+ADDR_DT2_D2R,(op.d2r&31)|(op.dt2<<6)); } - if (m.hadDt2) { - op.dt2=m.dt2; + if (m.dt2.had) { + op.dt2=m.dt2.val; rWrite(baseAddr+ADDR_DT2_D2R,(op.d2r&31)|(op.dt2<<6)); } } @@ -401,7 +401,7 @@ int DivPlatformTX81Z::dispatch(DivCommand c) { } chan[c.chan].std.init(ins); - if (!chan[c.chan].std.willVol) { + if (!chan[c.chan].std.vol.will) { chan[c.chan].outVol=chan[c.chan].vol; } @@ -463,7 +463,7 @@ int DivPlatformTX81Z::dispatch(DivCommand c) { break; case DIV_CMD_VOLUME: { chan[c.chan].vol=c.value; - if (!chan[c.chan].std.hasVol) { + if (!chan[c.chan].std.vol.has) { chan[c.chan].outVol=c.value; } for (int i=0; i<4; i++) { diff --git a/src/engine/platform/vera.cpp b/src/engine/platform/vera.cpp index 8965719f..77f5c805 100644 --- a/src/engine/platform/vera.cpp +++ b/src/engine/platform/vera.cpp @@ -158,30 +158,30 @@ int DivPlatformVERA::calcNoteFreq(int ch, int note) { void DivPlatformVERA::tick() { for (int i=0; i<16; i++) { chan[i].std.next(); - if (chan[i].std.hadVol) { - chan[i].outVol=MAX(chan[i].vol+chan[i].std.vol-63,0); + if (chan[i].std.vol.had) { + chan[i].outVol=MAX(chan[i].vol+chan[i].std.vol.val-63,0); rWriteLo(i,2,chan[i].outVol); } - if (chan[i].std.hadArp) { + if (chan[i].std.arp.had) { if (!chan[i].inPorta) { - if (chan[i].std.arpMode) { - chan[i].baseFreq=calcNoteFreq(0,chan[i].std.arp); + if (chan[i].std.arp.mode) { + chan[i].baseFreq=calcNoteFreq(0,chan[i].std.arp.val); } else { - chan[i].baseFreq=calcNoteFreq(0,chan[i].note+chan[i].std.arp); + chan[i].baseFreq=calcNoteFreq(0,chan[i].note+chan[i].std.arp.val); } } chan[i].freqChanged=true; } else { - if (chan[i].std.arpMode && chan[i].std.finishedArp) { + if (chan[i].std.arp.mode && chan[i].std.arp.finished) { chan[i].baseFreq=calcNoteFreq(0,chan[i].note); chan[i].freqChanged=true; } } - if (chan[i].std.hadDuty) { - rWriteLo(i,3,chan[i].std.duty); + if (chan[i].std.duty.had) { + rWriteLo(i,3,chan[i].std.duty.val); } - if (chan[i].std.hadWave) { - rWriteHi(i,3,chan[i].std.wave); + if (chan[i].std.wave.had) { + rWriteHi(i,3,chan[i].std.wave.val); } if (chan[i].freqChanged) { chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,8); @@ -193,21 +193,21 @@ void DivPlatformVERA::tick() { } // PCM chan[16].std.next(); - if (chan[16].std.hadVol) { - chan[16].outVol=MAX(chan[16].vol+MIN(chan[16].std.vol/4,15)-15,0); + if (chan[16].std.vol.had) { + chan[16].outVol=MAX(chan[16].vol+MIN(chan[16].std.vol.val/4,15)-15,0); rWritePCMVol(chan[16].outVol&15); } - if (chan[16].std.hadArp) { + if (chan[16].std.arp.had) { if (!chan[16].inPorta) { - if (chan[16].std.arpMode) { - chan[16].baseFreq=calcNoteFreq(16,chan[16].std.arp); + if (chan[16].std.arp.mode) { + chan[16].baseFreq=calcNoteFreq(16,chan[16].std.arp.val); } else { - chan[16].baseFreq=calcNoteFreq(16,chan[16].note+chan[16].std.arp); + chan[16].baseFreq=calcNoteFreq(16,chan[16].note+chan[16].std.arp.val); } } chan[16].freqChanged=true; } else { - if (chan[16].std.arpMode && chan[16].std.finishedArp) { + if (chan[16].std.arp.mode && chan[16].std.arp.finished) { chan[16].baseFreq=calcNoteFreq(16,chan[16].note); chan[16].freqChanged=true; } @@ -311,7 +311,7 @@ int DivPlatformVERA::dispatch(DivCommand c) { break; } case DIV_CMD_LEGATO: - chan[c.chan].baseFreq=calcNoteFreq(c.chan,c.value+((chan[c.chan].std.willArp && !chan[c.chan].std.arpMode)?(chan[c.chan].std.arp):(0))); + chan[c.chan].baseFreq=calcNoteFreq(c.chan,c.value+((chan[c.chan].std.arp.will && !chan[c.chan].std.arp.mode)?(chan[c.chan].std.arp.val):(0))); chan[c.chan].freqChanged=true; chan[c.chan].note=c.value; break; diff --git a/src/engine/platform/vic20.cpp b/src/engine/platform/vic20.cpp index 7fe13e96..b45fecfc 100644 --- a/src/engine/platform/vic20.cpp +++ b/src/engine/platform/vic20.cpp @@ -94,28 +94,28 @@ void DivPlatformVIC20::writeOutVol(int ch) { void DivPlatformVIC20::tick() { for (int i=0; i<4; i++) { chan[i].std.next(); - if (chan[i].std.hadVol) { - int env=chan[i].std.vol; + if (chan[i].std.vol.had) { + int env=chan[i].std.vol.val; calcAndWriteOutVol(i,env); } - if (chan[i].std.hadArp) { + if (chan[i].std.arp.had) { if (!chan[i].inPorta) { - if (chan[i].std.arpMode) { - chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp); + if (chan[i].std.arp.mode) { + chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val); } else { - chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp); + chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp.val); } } chan[i].freqChanged=true; } else { - if (chan[i].std.arpMode && chan[i].std.finishedArp) { + if (chan[i].std.arp.mode && chan[i].std.arp.finished) { chan[i].baseFreq=NOTE_PERIODIC(chan[i].note); chan[i].freqChanged=true; } } - if (chan[i].std.hadWave) { - if (chan[i].wave!=chan[i].std.wave) { - chan[i].wave=chan[i].std.wave&0x0f; + if (chan[i].std.wave.had) { + if (chan[i].wave!=chan[i].std.wave.val) { + chan[i].wave=chan[i].std.wave.val&0x0f; chan[i].keyOn=true; } } @@ -183,7 +183,7 @@ int DivPlatformVIC20::dispatch(DivCommand c) { case DIV_CMD_VOLUME: if (chan[c.chan].vol!=c.value) { chan[c.chan].vol=c.value; - if (!chan[c.chan].std.hadVol) { + if (!chan[c.chan].std.vol.had) { calcAndWriteOutVol(c.chan,15); } } @@ -223,7 +223,7 @@ int DivPlatformVIC20::dispatch(DivCommand c) { break; } case DIV_CMD_LEGATO: - chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+((chan[c.chan].std.willArp && !chan[c.chan].std.arpMode)?(chan[c.chan].std.arp):(0))); + chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+((chan[c.chan].std.arp.will && !chan[c.chan].std.arp.mode)?(chan[c.chan].std.arp.val):(0))); chan[c.chan].freqChanged=true; chan[c.chan].note=c.value; break; diff --git a/src/engine/platform/vrc6.cpp b/src/engine/platform/vrc6.cpp index c89df338..31694a62 100644 --- a/src/engine/platform/vrc6.cpp +++ b/src/engine/platform/vrc6.cpp @@ -140,16 +140,16 @@ void DivPlatformVRC6::tick() { // 16 for pulse; 14 for saw int CHIP_DIVIDER=(i==2)?14:16; chan[i].std.next(); - if (chan[i].std.hadVol) { + if (chan[i].std.vol.had) { if (i==2) { // sawtooth - chan[i].outVol=((chan[i].vol&63)*MIN(63,chan[i].std.vol))/63; + chan[i].outVol=((chan[i].vol&63)*MIN(63,chan[i].std.vol.val))/63; if (chan[i].outVol<0) chan[i].outVol=0; if (chan[i].outVol>63) chan[i].outVol=63; if (!isMuted[i]) { chWrite(i,0,chan[i].outVol); } } else { // pulse - chan[i].outVol=((chan[i].vol&15)*MIN(15,chan[i].std.vol))/15; + chan[i].outVol=((chan[i].vol&15)*MIN(15,chan[i].std.vol.val))/15; if (chan[i].outVol<0) chan[i].outVol=0; if (chan[i].outVol>15) chan[i].outVol=15; if ((!isMuted[i]) && (!chan[i].pcm)) { @@ -157,23 +157,23 @@ void DivPlatformVRC6::tick() { } } } - if (chan[i].std.hadArp) { + if (chan[i].std.arp.had) { if (!chan[i].inPorta) { - if (chan[i].std.arpMode) { - chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp); + if (chan[i].std.arp.mode) { + chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val); } else { - chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp); + chan[i].baseFreq=NOTE_PERIODIC(chan[i].note+chan[i].std.arp.val); } } chan[i].freqChanged=true; } else { - if (chan[i].std.arpMode && chan[i].std.finishedArp) { + if (chan[i].std.arp.mode && chan[i].std.arp.finished) { chan[i].baseFreq=NOTE_PERIODIC(chan[i].note); chan[i].freqChanged=true; } } - if (chan[i].std.hadDuty) { - chan[i].duty=chan[i].std.duty; + if (chan[i].std.duty.had) { + chan[i].duty=chan[i].std.duty.val; if ((!isMuted[i]) && (i!=2) && (!chan[i].pcm)) { // pulse chWrite(i,0,(chan[i].outVol&0xf)|((chan[i].duty&7)<<4)); } @@ -310,7 +310,7 @@ int DivPlatformVRC6::dispatch(DivCommand c) { case DIV_CMD_VOLUME: if (chan[c.chan].vol!=c.value) { chan[c.chan].vol=c.value; - if (!chan[c.chan].std.hasVol) { + if (!chan[c.chan].std.vol.has) { chan[c.chan].outVol=c.value; } if (!isMuted[c.chan]) { @@ -371,7 +371,7 @@ int DivPlatformVRC6::dispatch(DivCommand c) { } break; case DIV_CMD_LEGATO: - chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+((chan[c.chan].std.willArp && !chan[c.chan].std.arpMode)?(chan[c.chan].std.arp):(0))); + chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+((chan[c.chan].std.arp.will && !chan[c.chan].std.arp.mode)?(chan[c.chan].std.arp.val):(0))); chan[c.chan].freqChanged=true; chan[c.chan].note=c.value; break; diff --git a/src/engine/platform/x1_010.cpp b/src/engine/platform/x1_010.cpp index 68f6db29..124e0ace 100644 --- a/src/engine/platform/x1_010.cpp +++ b/src/engine/platform/x1_010.cpp @@ -339,41 +339,41 @@ void DivPlatformX1_010::updateEnvelope(int ch) { void DivPlatformX1_010::tick() { for (int i=0; i<16; i++) { chan[i].std.next(); - if (chan[i].std.hadVol) { - signed char macroVol=((chan[i].vol&15)*MIN(chan[i].furnacePCM?64:15,chan[i].std.vol))/(chan[i].furnacePCM?64:15); + if (chan[i].std.vol.had) { + signed char macroVol=((chan[i].vol&15)*MIN(chan[i].furnacePCM?64:15,chan[i].std.vol.val))/(chan[i].furnacePCM?64:15); if ((!isMuted[i]) && (macroVol!=chan[i].outVol)) { chan[i].outVol=macroVol; chan[i].envChanged=true; } } if ((!chan[i].pcm) || chan[i].furnacePCM) { - if (chan[i].std.hadArp) { + if (chan[i].std.arp.had) { if (!chan[i].inPorta) { - if (chan[i].std.arpMode) { - chan[i].baseFreq=NoteX1_010(i,chan[i].std.arp); + if (chan[i].std.arp.mode) { + chan[i].baseFreq=NoteX1_010(i,chan[i].std.arp.val); } else { - chan[i].baseFreq=NoteX1_010(i,chan[i].note+chan[i].std.arp); + chan[i].baseFreq=NoteX1_010(i,chan[i].note+chan[i].std.arp.val); } } chan[i].freqChanged=true; } else { - if (chan[i].std.arpMode && chan[i].std.finishedArp) { + if (chan[i].std.arp.mode && chan[i].std.arp.finished) { chan[i].baseFreq=NoteX1_010(i,chan[i].note); chan[i].freqChanged=true; } } } - if (chan[i].std.hadWave && !chan[i].pcm) { - if (chan[i].wave!=chan[i].std.wave || chan[i].ws.activeChanged()) { - chan[i].wave=chan[i].std.wave; + if (chan[i].std.wave.had && !chan[i].pcm) { + if (chan[i].wave!=chan[i].std.wave.val || chan[i].ws.activeChanged()) { + chan[i].wave=chan[i].std.wave.val; if (!chan[i].pcm) { chan[i].ws.changeWave1(chan[i].wave); if (!chan[i].keyOff) chan[i].keyOn=true; } } } - if (chan[i].std.hadEx1) { - bool nextEnable=(chan[i].std.ex1&1); + if (chan[i].std.ex1.had) { + bool nextEnable=(chan[i].std.ex1.val&1); if (nextEnable!=(chan[i].env.flag.envEnable)) { chan[i].env.flag.envEnable=nextEnable; if (!chan[i].pcm) { @@ -383,42 +383,42 @@ void DivPlatformX1_010::tick() { refreshControl(i); } } - bool nextOneshot=(chan[i].std.ex1&2); + bool nextOneshot=(chan[i].std.ex1.val&2); if (nextOneshot!=(chan[i].env.flag.envOneshot)) { chan[i].env.flag.envOneshot=nextOneshot; if (!chan[i].pcm) { refreshControl(i); } } - bool nextSplit=(chan[i].std.ex1&4); + bool nextSplit=(chan[i].std.ex1.val&4); if (nextSplit!=(chan[i].env.flag.envSplit)) { chan[i].env.flag.envSplit=nextSplit; if (!isMuted[i] && !chan[i].pcm) { chan[i].envChanged=true; } } - bool nextHinvR=(chan[i].std.ex1&8); + bool nextHinvR=(chan[i].std.ex1.val&8); if (nextHinvR!=(chan[i].env.flag.envHinvR)) { chan[i].env.flag.envHinvR=nextHinvR; if (!isMuted[i] && !chan[i].pcm) { chan[i].envChanged=true; } } - bool nextVinvR=(chan[i].std.ex1&16); + bool nextVinvR=(chan[i].std.ex1.val&16); if (nextVinvR!=(chan[i].env.flag.envVinvR)) { chan[i].env.flag.envVinvR=nextVinvR; if (!isMuted[i] && !chan[i].pcm) { chan[i].envChanged=true; } } - bool nextHinvL=(chan[i].std.ex1&32); + bool nextHinvL=(chan[i].std.ex1.val&32); if (nextHinvL!=(chan[i].env.flag.envHinvL)) { chan[i].env.flag.envHinvL=nextHinvL; if (!isMuted[i] && !chan[i].pcm) { chan[i].envChanged=true; } } - bool nextVinvL=(chan[i].std.ex1&64); + bool nextVinvL=(chan[i].std.ex1.val&64); if (nextVinvL!=(chan[i].env.flag.envVinvL)) { chan[i].env.flag.envVinvL=nextVinvL; if (!isMuted[i] && !chan[i].pcm) { @@ -426,9 +426,9 @@ void DivPlatformX1_010::tick() { } } } - if (chan[i].std.hadEx2) { - if (chan[i].env.shape!=chan[i].std.ex2) { - chan[i].env.shape=chan[i].std.ex2; + if (chan[i].std.ex2.had) { + if (chan[i].env.shape!=chan[i].std.ex2.val) { + chan[i].env.shape=chan[i].std.ex2.val; if (!chan[i].pcm) { if (chan[i].env.flag.envEnable && (!isMuted[i])) { chan[i].envChanged=true; @@ -437,18 +437,18 @@ void DivPlatformX1_010::tick() { } } } - if (chan[i].std.hadEx3) { - chan[i].autoEnvNum=chan[i].std.ex3; + if (chan[i].std.ex3.had) { + chan[i].autoEnvNum=chan[i].std.ex3.val; if (!chan[i].pcm) { chan[i].freqChanged=true; - if (!chan[i].std.willAlg) chan[i].autoEnvDen=1; + if (!chan[i].std.alg.will) chan[i].autoEnvDen=1; } } - if (chan[i].std.hadAlg) { - chan[i].autoEnvDen=chan[i].std.alg; + if (chan[i].std.alg.had) { + chan[i].autoEnvDen=chan[i].std.alg.val; if (!chan[i].pcm) { chan[i].freqChanged=true; - if (!chan[i].std.willEx3) chan[i].autoEnvNum=1; + if (!chan[i].std.ex3.will) chan[i].autoEnvNum=1; } } if (chan[i].active) { @@ -601,7 +601,7 @@ int DivPlatformX1_010::dispatch(DivCommand c) { case DIV_CMD_VOLUME: if (chan[c.chan].vol!=c.value) { chan[c.chan].vol=c.value; - if (!chan[c.chan].std.hasVol) { + if (!chan[c.chan].std.vol.has) { if (chan[c.chan].outVol!=c.value) { chan[c.chan].outVol=c.value; if (!isMuted[c.chan]) { @@ -612,7 +612,7 @@ int DivPlatformX1_010::dispatch(DivCommand c) { } break; case DIV_CMD_GET_VOLUME: - if (chan[c.chan].std.hasVol) { + if (chan[c.chan].std.vol.has) { return chan[c.chan].vol; } return chan[c.chan].outVol; @@ -685,7 +685,7 @@ int DivPlatformX1_010::dispatch(DivCommand c) { } case DIV_CMD_LEGATO: chan[c.chan].note=c.value; - chan[c.chan].baseFreq=NoteX1_010(c.chan,chan[c.chan].note+((chan[c.chan].std.willArp&&!chan[c.chan].std.arpMode)?(chan[c.chan].std.arp):(0))); + chan[c.chan].baseFreq=NoteX1_010(c.chan,chan[c.chan].note+((chan[c.chan].std.arp.will&&!chan[c.chan].std.arp.mode)?(chan[c.chan].std.arp.val):(0))); chan[c.chan].freqChanged=true; break; case DIV_CMD_PRE_PORTA: diff --git a/src/engine/platform/ym2610.cpp b/src/engine/platform/ym2610.cpp index 77c1243b..398d5be4 100644 --- a/src/engine/platform/ym2610.cpp +++ b/src/engine/platform/ym2610.cpp @@ -376,8 +376,8 @@ void DivPlatformYM2610::tick() { if (i==1 && extMode) continue; chan[i].std.next(); - if (chan[i].std.hadVol) { - chan[i].outVol=(chan[i].vol*MIN(127,chan[i].std.vol))/127; + if (chan[i].std.vol.had) { + chan[i].outVol=(chan[i].vol*MIN(127,chan[i].std.vol.val))/127; for (int j=0; j<4; j++) { unsigned short baseAddr=chanOffs[i]|opOffs[j]; DivInstrumentFM::Operator& op=chan[i].state.op[j]; @@ -389,24 +389,24 @@ void DivPlatformYM2610::tick() { } } - if (chan[i].std.hadArp) { + if (chan[i].std.arp.had) { if (!chan[i].inPorta) { - if (chan[i].std.arpMode) { - chan[i].baseFreq=NOTE_FREQUENCY(chan[i].std.arp); + if (chan[i].std.arp.mode) { + chan[i].baseFreq=NOTE_FREQUENCY(chan[i].std.arp.val); } else { - chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note+(signed char)chan[i].std.arp); + chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note+(signed char)chan[i].std.arp.val); } } chan[i].freqChanged=true; } else { - if (chan[i].std.arpMode && chan[i].std.finishedArp) { + if (chan[i].std.arp.mode && chan[i].std.arp.finished) { chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note); chan[i].freqChanged=true; } } - if (chan[i].std.hadAlg) { - chan[i].state.alg=chan[i].std.alg; + if (chan[i].std.alg.had) { + chan[i].state.alg=chan[i].std.alg.val; rWrite(chanOffs[i]+ADDR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3)); if (!parent->song.algMacroBehavior) for (int j=0; j<4; j++) { unsigned short baseAddr=chanOffs[i]|opOffs[j]; @@ -422,68 +422,68 @@ void DivPlatformYM2610::tick() { } } } - if (chan[i].std.hadFb) { - chan[i].state.fb=chan[i].std.fb; + if (chan[i].std.fb.had) { + chan[i].state.fb=chan[i].std.fb.val; rWrite(chanOffs[i]+ADDR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3)); } - if (chan[i].std.hadFms) { - chan[i].state.fms=chan[i].std.fms; + if (chan[i].std.fms.had) { + chan[i].state.fms=chan[i].std.fms.val; rWrite(chanOffs[i]+ADDR_LRAF,(isMuted[i]?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4)); } - if (chan[i].std.hadAms) { - chan[i].state.ams=chan[i].std.ams; + if (chan[i].std.ams.had) { + chan[i].state.ams=chan[i].std.ams.val; rWrite(chanOffs[i]+ADDR_LRAF,(isMuted[i]?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4)); } for (int j=0; j<4; j++) { unsigned short baseAddr=chanOffs[i]|opOffs[j]; DivInstrumentFM::Operator& op=chan[i].state.op[j]; DivMacroInt::IntOp& m=chan[i].std.op[j]; - if (m.hadAm) { - op.am=m.am; + if (m.am.had) { + op.am=m.am.val; rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7)); } - if (m.hadAr) { - op.ar=m.ar; + if (m.ar.had) { + op.ar=m.ar.val; rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6)); } - if (m.hadDr) { - op.dr=m.dr; + if (m.dr.had) { + op.dr=m.dr.val; rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7)); } - if (m.hadMult) { - op.mult=m.mult; + if (m.mult.had) { + op.mult=m.mult.val; rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4)); } - if (m.hadRr) { - op.rr=m.rr; + if (m.rr.had) { + op.rr=m.rr.val; rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4)); } - if (m.hadSl) { - op.sl=m.sl; + if (m.sl.had) { + op.sl=m.sl.val; rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4)); } - if (m.hadTl) { - op.tl=127-m.tl; + if (m.tl.had) { + op.tl=127-m.tl.val; if (isOutput[chan[i].state.alg][j]) { rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); } } - if (m.hadRs) { - op.rs=m.rs; + if (m.rs.had) { + op.rs=m.rs.val; rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6)); } - if (m.hadDt) { - op.dt=m.dt; + if (m.dt.had) { + op.dt=m.dt.val; rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4)); } - if (m.hadD2r) { - op.d2r=m.d2r; + if (m.d2r.had) { + op.d2r=m.d2r.val; rWrite(baseAddr+ADDR_DT2_D2R,op.d2r&31); } - if (m.hadSsg) { - op.ssgEnv=m.ssg; + if (m.ssg.had) { + op.ssgEnv=m.ssg.val; rWrite(baseAddr+ADDR_SSG,op.ssgEnv&15); } } @@ -498,22 +498,22 @@ void DivPlatformYM2610::tick() { if (chan[13].furnacePCM) { chan[13].std.next(); - if (chan[13].std.hadVol) { - chan[13].outVol=(chan[13].vol*MIN(64,chan[13].std.vol))/64; + if (chan[13].std.vol.had) { + chan[13].outVol=(chan[13].vol*MIN(64,chan[13].std.vol.val))/64; immWrite(0x1b,chan[13].outVol); } - if (chan[13].std.hadArp) { + if (chan[13].std.arp.had) { if (!chan[13].inPorta) { - if (chan[13].std.arpMode) { - chan[13].baseFreq=NOTE_ADPCMB(chan[13].std.arp); + if (chan[13].std.arp.mode) { + chan[13].baseFreq=NOTE_ADPCMB(chan[13].std.arp.val); } else { - chan[13].baseFreq=NOTE_ADPCMB(chan[13].note+(signed char)chan[13].std.arp); + chan[13].baseFreq=NOTE_ADPCMB(chan[13].note+(signed char)chan[13].std.arp.val); } } chan[13].freqChanged=true; } else { - if (chan[13].std.arpMode && chan[13].std.finishedArp) { + if (chan[13].std.arp.mode && chan[13].std.arp.finished) { chan[13].baseFreq=NOTE_ADPCMB(chan[13].note); chan[13].freqChanged=true; } @@ -608,7 +608,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) { if (skipRegisterWrites) break; if (chan[c.chan].furnacePCM) { chan[c.chan].std.init(ins); - if (!chan[c.chan].std.willVol) { + if (!chan[c.chan].std.vol.will) { chan[c.chan].outVol=chan[c.chan].vol; immWrite(0x1b,chan[c.chan].outVol); } @@ -685,7 +685,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) { DivInstrument* ins=parent->getIns(chan[c.chan].ins); chan[c.chan].std.init(ins); if (c.chan<4) { - if (!chan[c.chan].std.willVol) { + if (!chan[c.chan].std.vol.will) { chan[c.chan].outVol=chan[c.chan].vol; } } @@ -764,7 +764,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) { break; case DIV_CMD_VOLUME: { chan[c.chan].vol=c.value; - if (!chan[c.chan].std.hasVol) { + if (!chan[c.chan].std.vol.has) { chan[c.chan].outVol=c.value; } if (c.chan>12) { // ADPCM-B diff --git a/src/engine/platform/ym2610b.cpp b/src/engine/platform/ym2610b.cpp index dfd84723..147a7546 100644 --- a/src/engine/platform/ym2610b.cpp +++ b/src/engine/platform/ym2610b.cpp @@ -440,8 +440,8 @@ void DivPlatformYM2610B::tick() { if (i==2 && extMode) continue; chan[i].std.next(); - if (chan[i].std.hadVol) { - chan[i].outVol=(chan[i].vol*MIN(127,chan[i].std.vol))/127; + if (chan[i].std.vol.had) { + chan[i].outVol=(chan[i].vol*MIN(127,chan[i].std.vol.val))/127; for (int j=0; j<4; j++) { unsigned short baseAddr=chanOffs[i]|opOffs[j]; DivInstrumentFM::Operator& op=chan[i].state.op[j]; @@ -453,24 +453,24 @@ void DivPlatformYM2610B::tick() { } } - if (chan[i].std.hadArp) { + if (chan[i].std.arp.had) { if (!chan[i].inPorta) { - if (chan[i].std.arpMode) { - chan[i].baseFreq=NOTE_FREQUENCY(chan[i].std.arp); + if (chan[i].std.arp.mode) { + chan[i].baseFreq=NOTE_FREQUENCY(chan[i].std.arp.val); } else { - chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note+(signed char)chan[i].std.arp); + chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note+(signed char)chan[i].std.arp.val); } } chan[i].freqChanged=true; } else { - if (chan[i].std.arpMode && chan[i].std.finishedArp) { + if (chan[i].std.arp.mode && chan[i].std.arp.finished) { chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note); chan[i].freqChanged=true; } } - if (chan[i].std.hadAlg) { - chan[i].state.alg=chan[i].std.alg; + if (chan[i].std.alg.had) { + chan[i].state.alg=chan[i].std.alg.val; rWrite(chanOffs[i]+ADDR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3)); if (!parent->song.algMacroBehavior) for (int j=0; j<4; j++) { unsigned short baseAddr=chanOffs[i]|opOffs[j]; @@ -486,68 +486,68 @@ void DivPlatformYM2610B::tick() { } } } - if (chan[i].std.hadFb) { - chan[i].state.fb=chan[i].std.fb; + if (chan[i].std.fb.had) { + chan[i].state.fb=chan[i].std.fb.val; rWrite(chanOffs[i]+ADDR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3)); } - if (chan[i].std.hadFms) { - chan[i].state.fms=chan[i].std.fms; + if (chan[i].std.fms.had) { + chan[i].state.fms=chan[i].std.fms.val; rWrite(chanOffs[i]+ADDR_LRAF,(isMuted[i]?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4)); } - if (chan[i].std.hadAms) { - chan[i].state.ams=chan[i].std.ams; + if (chan[i].std.ams.had) { + chan[i].state.ams=chan[i].std.ams.val; rWrite(chanOffs[i]+ADDR_LRAF,(isMuted[i]?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4)); } for (int j=0; j<4; j++) { unsigned short baseAddr=chanOffs[i]|opOffs[j]; DivInstrumentFM::Operator& op=chan[i].state.op[j]; DivMacroInt::IntOp& m=chan[i].std.op[j]; - if (m.hadAm) { - op.am=m.am; + if (m.am.had) { + op.am=m.am.val; rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7)); } - if (m.hadAr) { - op.ar=m.ar; + if (m.ar.had) { + op.ar=m.ar.val; rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6)); } - if (m.hadDr) { - op.dr=m.dr; + if (m.dr.had) { + op.dr=m.dr.val; rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7)); } - if (m.hadMult) { - op.mult=m.mult; + if (m.mult.had) { + op.mult=m.mult.val; rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4)); } - if (m.hadRr) { - op.rr=m.rr; + if (m.rr.had) { + op.rr=m.rr.val; rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4)); } - if (m.hadSl) { - op.sl=m.sl; + if (m.sl.had) { + op.sl=m.sl.val; rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4)); } - if (m.hadTl) { - op.tl=127-m.tl; + if (m.tl.had) { + op.tl=127-m.tl.val; if (isOutput[chan[i].state.alg][j]) { rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); } } - if (m.hadRs) { - op.rs=m.rs; + if (m.rs.had) { + op.rs=m.rs.val; rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6)); } - if (m.hadDt) { - op.dt=m.dt; + if (m.dt.had) { + op.dt=m.dt.val; rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4)); } - if (m.hadD2r) { - op.d2r=m.d2r; + if (m.d2r.had) { + op.d2r=m.d2r.val; rWrite(baseAddr+ADDR_DT2_D2R,op.d2r&31); } - if (m.hadSsg) { - op.ssgEnv=m.ssg; + if (m.ssg.had) { + op.ssgEnv=m.ssg.val; rWrite(baseAddr+ADDR_SSG,op.ssgEnv&15); } } @@ -561,22 +561,22 @@ void DivPlatformYM2610B::tick() { if (chan[15].furnacePCM) { chan[15].std.next(); - if (chan[15].std.hadVol) { - chan[15].outVol=(chan[15].vol*MIN(64,chan[15].std.vol))/64; + if (chan[15].std.vol.had) { + chan[15].outVol=(chan[15].vol*MIN(64,chan[15].std.vol.val))/64; immWrite(0x1b,chan[15].outVol); } - if (chan[15].std.hadArp) { + if (chan[15].std.arp.had) { if (!chan[15].inPorta) { - if (chan[15].std.arpMode) { - chan[15].baseFreq=NOTE_ADPCMB(chan[15].std.arp); + if (chan[15].std.arp.mode) { + chan[15].baseFreq=NOTE_ADPCMB(chan[15].std.arp.val); } else { - chan[15].baseFreq=NOTE_ADPCMB(chan[15].note+(signed char)chan[15].std.arp); + chan[15].baseFreq=NOTE_ADPCMB(chan[15].note+(signed char)chan[15].std.arp.val); } } chan[15].freqChanged=true; } else { - if (chan[15].std.arpMode && chan[15].std.finishedArp) { + if (chan[15].std.arp.mode && chan[15].std.arp.finished) { chan[15].baseFreq=NOTE_ADPCMB(chan[15].note); chan[15].freqChanged=true; } @@ -671,7 +671,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) { if (skipRegisterWrites) break; if (chan[c.chan].furnacePCM) { chan[c.chan].std.init(ins); - if (!chan[c.chan].std.willVol) { + if (!chan[c.chan].std.vol.will) { chan[c.chan].outVol=chan[c.chan].vol; immWrite(0x1b,chan[c.chan].outVol); } @@ -748,7 +748,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) { DivInstrument* ins=parent->getIns(chan[c.chan].ins); chan[c.chan].std.init(ins); if (c.chan<6) { - if (!chan[c.chan].std.willVol) { + if (!chan[c.chan].std.vol.will) { chan[c.chan].outVol=chan[c.chan].vol; } } @@ -827,7 +827,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) { break; case DIV_CMD_VOLUME: { chan[c.chan].vol=c.value; - if (!chan[c.chan].std.hasVol) { + if (!chan[c.chan].std.vol.has) { chan[c.chan].outVol=c.value; } if (c.chan>14) { // ADPCM-B diff --git a/src/engine/safeReader.cpp b/src/engine/safeReader.cpp index 9add1b5a..f27e9044 100644 --- a/src/engine/safeReader.cpp +++ b/src/engine/safeReader.cpp @@ -66,6 +66,42 @@ int SafeReader::read(void* where, size_t count) { return count; } +template +int SafeReader::readByte(T* where, size_t count, unsigned char byte, Endianness endianness) { + if (byte==sizeof(T)) { + return read(where,count*byte); + } else { +#ifdef READ_DEBUG + logD("SR: reading %d x %d bit words at %x\n",count,byte<<3,curSeek); +#endif + if (count==0) return 0; + if (curSeek+(count*byte)>len) throw EndOfFileException(this,len); + int start,end,inc; + switch (endianness) { + case BigEndian: + start=byte-1; + end=-1; + inc=-1; + break; + case LittleEndian: + default: + start=0; + end=byte; + inc=1; + break; + } + for (int c=0; c #include "../ta-utils.h" +enum Endianness { + LittleEndian=0, + BigEndian +}; + class SafeReader; struct EndOfFileException { @@ -46,6 +51,7 @@ class SafeReader { size_t size(); int read(void* where, size_t count); + template int readByte(T* where, size_t count, unsigned char byte=sizeof(T), Endianness endianness=LittleEndian); // these functions may throw EndOfFileException. signed char readC(); diff --git a/src/engine/safeWriter.cpp b/src/engine/safeWriter.cpp index f29800a4..2e8fb7dd 100644 --- a/src/engine/safeWriter.cpp +++ b/src/engine/safeWriter.cpp @@ -73,6 +73,39 @@ int SafeWriter::write(const void* what, size_t count) { return count; } +template +int SafeWriter::writeByte(T* what, size_t count, unsigned char byte, Endianness endianness) { + if (byte==sizeof(T)) { + return write(what,count*byte); + } else { + if (!operative) return 0; + checkSize(count*byte); + int start,end,inc; + switch (endianness) { + case BigEndian: + start=byte-1; + end=-1; + inc=-1; + break; + case LittleEndian: + default: + start=0; + end=byte; + inc=1; + break; + } + for (int c=0; c>(byte<<3))&0xff; + } + } + count*=byte; + if (curSeek>len) len=curSeek; + } + return count; +} + int SafeWriter::writeC(signed char val) { return write(&val,1); } diff --git a/src/engine/safeWriter.h b/src/engine/safeWriter.h index 9072c61d..c4920378 100644 --- a/src/engine/safeWriter.h +++ b/src/engine/safeWriter.h @@ -43,6 +43,7 @@ class SafeWriter { size_t size(); int write(const void* what, size_t count); + template int writeByte(T* what, size_t count, unsigned char byte=sizeof(T), Endianness endianness=LittleEndian); int writeC(signed char val); int writeS(short val); diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 14ca65b4..1f5d9e91 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -176,6 +176,15 @@ const char* dualWSEffects[7]={ "Phase (dual)", }; +const char* macroAbsoluteMode[2]={ + "Relative", + "Absolute", +}; + +const char* macroDummyMode[2]={ + "empty", +}; + String macroHoverNote(int id, float val) { if (val<-60 || val>=120) return "???"; return fmt::sprintf("%d: %s",id,noteNames[(int)val+60]); @@ -924,8 +933,8 @@ void FurnaceGUI::drawFMEnv(unsigned char tl, unsigned char ar, unsigned char dr, ImVec2 posREnd=ImLerp(rect.Min,rect.Max,ImVec2(rrPos,1.0));//release end ImVec2 posSLineHEnd=ImLerp(rect.Min,rect.Max,ImVec2(1.0,(float)((tl/maxTl)+(sl/15.0)-((tl/maxTl)*(sl/15.0))))); //sustain horizontal line end ImVec2 posSLineVEnd=ImLerp(rect.Min,rect.Max,ImVec2(drPos,1.0)); //sustain vertical line end - ImVec2 posDecayRate0Pt=ImLerp(rect.Min,rect.Max,ImVec2(1.0,(tl/maxTl))); //Heght of the peak of AR, forever - ImVec2 posDecay2Rate0Pt=ImLerp(rect.Min,rect.Max,ImVec2(1.0,(float)((tl/maxTl)+(sl/15.0)-((tl/maxTl)*(sl/15.0))))); //Heght of the peak of SR, forever + ImVec2 posDecayRate0Pt=ImLerp(rect.Min,rect.Max,ImVec2(1.0,(tl/maxTl))); //Height of the peak of AR, forever + ImVec2 posDecay2Rate0Pt=ImLerp(rect.Min,rect.Max,ImVec2(1.0,(float)((tl/maxTl)+(sl/15.0)-((tl/maxTl)*(sl/15.0))))); //Height of the peak of SR, forever //dl->Flags=ImDrawListFlags_AntiAliasedLines|ImDrawListFlags_AntiAliasedLinesUseTex; if (ar==0.0) { //if AR = 0, the envelope never starts @@ -963,7 +972,7 @@ void FurnaceGUI::drawFMEnv(unsigned char tl, unsigned char ar, unsigned char dr, #define PARAMETER MARK_MODIFIED; e->notifyInsChange(curIns); -#define NORMAL_MACRO(macro,macroLen,macroLoop,macroRel,macroMin,macroHeight,macroName,displayName,displayHeight,displayLoop,bitfield,bfVal,drawSlider,sliderVal,sliderLow,macroDispMin,bitOff,macroMode,macroColor,mmlStr,macroAMin,macroAMax,hoverFunc,blockMode) \ +#define NORMAL_MACRO(macro,macroMin,macroHeight,macroName,displayName,displayHeight,displayLoop,bitfield,bfVal,drawSlider,sliderVal,sliderLow,macroDispMin,bitOff,macroMode,macroModeMax,displayModeName,macroColor,mmlStr,macroAMin,macroAMax,hoverFunc,blockMode) \ ImGui::TableNextRow(); \ ImGui::TableNextColumn(); \ ImGui::Text("%s",displayName); \ @@ -973,26 +982,41 @@ void FurnaceGUI::drawFMEnv(unsigned char tl, unsigned char ar, unsigned char dr, } \ if (displayLoop) { \ ImGui::SetNextItemWidth(lenAvail); \ - if (ImGui::InputScalar("##IMacroLen_" macroName,ImGuiDataType_U8,¯oLen,&_ONE,&_THREE)) { MARK_MODIFIED \ - if (macroLen>127) macroLen=127; \ + if (ImGui::InputScalar("##IMacroLen_" macroName,ImGuiDataType_U8,¯o.len,&_ONE,&_THREE)) { MARK_MODIFIED \ + if (macro.len>127) macro.len=127; \ } \ - if (macroMode!=NULL) { \ - ImGui::Checkbox("Fixed##IMacroMode_" macroName,macroMode); \ + if (macroMode) { \ + String modeName; \ + if (macro.mode>macroModeMax) { \ + modeName="none selected"; \ + } else { \ + modeName=displayModeName[macro.mode]; \ + } \ + if (ImGui::BeginCombo("Macro Mode",modeName.c_str())) { \ + String id; \ + for (unsigned int i=0; i<=macroModeMax; i++) { \ + id=fmt::sprintf("%d: %s",i,displayModeName[i]); \ + if (ImGui::Selectable(id.c_str(),macro.mode==i)) { PARAMETER \ + macro.mode=i; \ + } \ + } \ + ImGui::EndCombo(); \ + } \ } \ } \ ImGui::TableNextColumn(); \ for (int j=0; j<256; j++) { \ - if (j+macroDragScroll>=macroLen) { \ + if (j+macroDragScroll>=macro.len) { \ asFloat[j]=0; \ asInt[j]=0; \ } else { \ - asFloat[j]=macro[j+macroDragScroll]+macroDispMin; \ - asInt[j]=macro[j+macroDragScroll]+macroDispMin+bitOff; \ + asFloat[j]=macro.val[j+macroDragScroll]+macroDispMin; \ + asInt[j]=macro.val[j+macroDragScroll]+macroDispMin+bitOff; \ } \ - if (j+macroDragScroll>=macroLen || (j+macroDragScroll>macroRel && macroLoop=macro.len || (j+macroDragScroll>macro.rel && macro.loop=macroLoop))|((macroRel!=-1 && (j+macroDragScroll)==macroRel)<<1); \ + loopIndicator[j]=((macro.loop!=-1 && (j+macroDragScroll)>=macro.loop))|((macro.rel!=-1 && (j+macroDragScroll)==macro.rel)<<1); \ } \ } \ ImGui::PushStyleVar(ImGuiStyleVar_FramePadding,ImVec2(0.0f,0.0f)); \ @@ -1000,7 +1024,7 @@ void FurnaceGUI::drawFMEnv(unsigned char tl, unsigned char ar, unsigned char dr, if (bitfield) { \ PlotBitfield("##IMacro_" macroName,asInt,totalFit,0,bfVal,macroHeight,ImVec2(availableWidth,(displayLoop)?(displayHeight*dpiScale):(32.0f*dpiScale))); \ } else { \ - PlotCustom("##IMacro_" macroName,asFloat,totalFit,macroDragScroll,NULL,macroDispMin+macroMin,macroHeight+macroDispMin,ImVec2(availableWidth,(displayLoop)?(displayHeight*dpiScale):(32.0f*dpiScale)),sizeof(float),macroColor,macroLen-macroDragScroll,hoverFunc,blockMode); \ + PlotCustom("##IMacro_" macroName,asFloat,totalFit,macroDragScroll,NULL,macroDispMin+macroMin,macroHeight+macroDispMin,ImVec2(availableWidth,(displayLoop)?(displayHeight*dpiScale):(32.0f*dpiScale)),sizeof(float),macroColor,macro.len-macroDragScroll,hoverFunc,blockMode); \ } \ if (displayLoop && ImGui::IsItemClicked(ImGuiMouseButton_Left)) { \ macroDragStart=ImGui::GetItemRectMin(); \ @@ -1013,7 +1037,7 @@ void FurnaceGUI::drawFMEnv(unsigned char tl, unsigned char ar, unsigned char dr, macroDragInitialValue=false; \ macroDragLen=totalFit; \ macroDragActive=true; \ - macroDragTarget=macro; \ + macroDragTarget=macro.val; \ macroDragChar=false; \ processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y); \ } \ @@ -1022,63 +1046,81 @@ void FurnaceGUI::drawFMEnv(unsigned char tl, unsigned char ar, unsigned char dr, ImGui::SameLine(); \ CWVSliderInt("##IArpMacroPos",ImVec2(20.0f*dpiScale,displayHeight*dpiScale),sliderVal,sliderLow,70); \ } \ - PlotCustom("##IMacroLoop_" macroName,loopIndicator,totalFit,macroDragScroll,NULL,0,2,ImVec2(availableWidth,12.0f*dpiScale),sizeof(float),macroColor,macroLen-macroDragScroll,¯oHoverLoop); \ + PlotCustom("##IMacroLoop_" macroName,loopIndicator,totalFit,macroDragScroll,NULL,0,2,ImVec2(availableWidth,12.0f*dpiScale),sizeof(float),macroColor,macro.len-macroDragScroll,¯oHoverLoop); \ if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) { \ macroLoopDragStart=ImGui::GetItemRectMin(); \ macroLoopDragAreaSize=ImVec2(availableWidth,12.0f*dpiScale); \ macroLoopDragLen=totalFit; \ if (ImGui::IsKeyDown(ImGuiKey_LeftShift) || ImGui::IsKeyDown(ImGuiKey_RightShift)) { \ - macroLoopDragTarget=¯oRel; \ + macroLoopDragTarget=¯o.rel; \ } else { \ - macroLoopDragTarget=¯oLoop; \ + macroLoopDragTarget=¯o.loop; \ } \ macroLoopDragActive=true; \ processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y); \ } \ if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) { \ if (ImGui::IsKeyDown(ImGuiKey_LeftShift) || ImGui::IsKeyDown(ImGuiKey_RightShift)) { \ - macroRel=-1; \ + macro.rel=-1; \ } else { \ - macroLoop=-1; \ + macro.loop=-1; \ } \ } \ ImGui::SetNextItemWidth(availableWidth); \ if (ImGui::InputText("##IMacroMML_" macroName,&mmlStr)) { \ - decodeMMLStr(mmlStr,macro,macroLen,macroLoop,macroAMin,(bitfield)?((1<127) macroLen=127; \ + if (ImGui::InputScalar("##IOPMacro.len_" #op macroName,ImGuiDataType_U8,¯o.len,&_ONE,&_THREE)) { MARK_MODIFIED \ + if (macro.len>127) macro.len=127; \ + } \ + if (macroMode) { \ + String modeName; \ + if (macro.mode>macroModeMax) { \ + modeName="none selected"; \ + } else { \ + modeName=displayModeName[macro.mode]; \ + } \ + if (ImGui::BeginCombo("Macro Mode",modeName.c_str())) { \ + String id; \ + for (unsigned int i=0; i<=macroModeMax; i++) { \ + id=fmt::sprintf("%d: %s",i,displayModeName[i]); \ + if (ImGui::Selectable(id.c_str(),macro.mode==i)) { PARAMETER \ + macro.mode=i; \ + } \ + } \ + ImGui::EndCombo(); \ + } \ } \ } \ ImGui::TableNextColumn(); \ for (int j=0; j<256; j++) { \ - if (j+macroDragScroll>=macroLen) { \ + if (j+macroDragScroll>=macro.len) { \ asFloat[j]=0; \ asInt[j]=0; \ } else { \ - asFloat[j]=macro[j+macroDragScroll]; \ - asInt[j]=macro[j+macroDragScroll]; \ + asFloat[j]=macro.val[j+macroDragScroll]; \ + asInt[j]=macro.val[j+macroDragScroll]; \ } \ - if (j+macroDragScroll>=macroLen || (j+macroDragScroll>macroRel && macroLoop=macro.len || (j+macroDragScroll>macro.rel && macro.loop=macroLoop))|((macroRel!=-1 && (j+macroDragScroll)==macroRel)<<1); \ + loopIndicator[j]=((macro.loop!=-1 && (j+macroDragScroll)>=macro.loop))|((macro.rel!=-1 && (j+macroDragScroll)==macro.rel)<<1); \ } \ } \ ImGui::PushStyleVar(ImGuiStyleVar_FramePadding,ImVec2(0.0f,0.0f)); \ @@ -1086,7 +1128,7 @@ void FurnaceGUI::drawFMEnv(unsigned char tl, unsigned char ar, unsigned char dr, if (bitfield) { \ PlotBitfield("##IOPMacro_" #op macroName,asInt,totalFit,0,bfVal,macroHeight,ImVec2(availableWidth,displayLoop?(displayHeight*dpiScale):(24*dpiScale))); \ } else { \ - PlotCustom("##IOPMacro_" #op macroName,asFloat,totalFit,macroDragScroll,NULL,0,macroHeight,ImVec2(availableWidth,displayLoop?(displayHeight*dpiScale):(24*dpiScale)),sizeof(float),uiColors[GUI_COLOR_MACRO_OTHER],macroLen-macroDragScroll); \ + PlotCustom("##IOPMacro_" #op macroName,asFloat,totalFit,macroDragScroll,NULL,0,macroHeight,ImVec2(availableWidth,displayLoop?(displayHeight*dpiScale):(24*dpiScale)),sizeof(float),uiColors[GUI_COLOR_MACRO_OTHER],macro.len-macroDragScroll); \ } \ if (displayLoop && ImGui::IsItemClicked(ImGuiMouseButton_Left)) { \ macroDragStart=ImGui::GetItemRectMin(); \ @@ -1099,37 +1141,37 @@ void FurnaceGUI::drawFMEnv(unsigned char tl, unsigned char ar, unsigned char dr, macroDragInitialValue=false; \ macroDragLen=totalFit; \ macroDragActive=true; \ - macroDragCTarget=macro; \ - macroDragChar=true; \ + macroDragTarget=macro.val; \ + macroDragChar=false; \ processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y); \ } \ if (displayLoop) { \ - PlotCustom("##IOPMacroLoop_" #op macroName,loopIndicator,totalFit,macroDragScroll,NULL,0,2,ImVec2(availableWidth,12.0f*dpiScale),sizeof(float),uiColors[GUI_COLOR_MACRO_OTHER],macroLen-macroDragScroll,¯oHoverLoop); \ + PlotCustom("##IOPMacro.loop_" #op macroName,loopIndicator,totalFit,macroDragScroll,NULL,0,2,ImVec2(availableWidth,12.0f*dpiScale),sizeof(float),uiColors[GUI_COLOR_MACRO_OTHER],macro.len-macroDragScroll,¯oHoverLoop); \ if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) { \ macroLoopDragStart=ImGui::GetItemRectMin(); \ macroLoopDragAreaSize=ImVec2(availableWidth,8.0f*dpiScale); \ macroLoopDragLen=totalFit; \ if (ImGui::IsKeyDown(ImGuiKey_LeftShift) || ImGui::IsKeyDown(ImGuiKey_RightShift)) { \ - macroLoopDragTarget=¯oRel; \ + macroLoopDragTarget=¯o.rel; \ } else { \ - macroLoopDragTarget=¯oLoop; \ + macroLoopDragTarget=¯o.loop; \ } \ macroLoopDragActive=true; \ processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y); \ } \ if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) { \ if (ImGui::IsKeyDown(ImGuiKey_LeftShift) || ImGui::IsKeyDown(ImGuiKey_RightShift)) { \ - macroRel=-1; \ + macro.rel=-1; \ } else { \ - macroLoop=-1; \ + macro.loop=-1; \ } \ } \ ImGui::SetNextItemWidth(availableWidth); \ if (ImGui::InputText("##IOPMacroMML_" macroName,&mmlStr)) { \ - decodeMMLStr(mmlStr,macro,macroLen,macroLoop,0,bitfield?((1<type==DIV_INS_OPLL) { - NORMAL_MACRO(ins->std.algMacro,ins->std.algMacroLen,ins->std.algMacroLoop,ins->std.algMacroRel,0,1,"alg",FM_NAME(FM_SUS),32,ins->std.algMacroOpen,true,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[0],0,1,NULL,false); - NORMAL_MACRO(ins->std.fbMacro,ins->std.fbMacroLen,ins->std.fbMacroLoop,ins->std.fbMacroRel,0,7,"fb",FM_NAME(FM_FB),96,ins->std.fbMacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[1],0,7,NULL,false); - NORMAL_MACRO(ins->std.fmsMacro,ins->std.fmsMacroLen,ins->std.fmsMacroLoop,ins->std.fmsMacroRel,0,1,"fms",FM_NAME(FM_DC),32,ins->std.fmsMacroOpen,true,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[2],0,1,NULL,false); - NORMAL_MACRO(ins->std.amsMacro,ins->std.amsMacroLen,ins->std.amsMacroLoop,ins->std.amsMacroRel,0,1,"ams",FM_NAME(FM_DM),32,ins->std.amsMacroOpen,true,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[3],0,1,NULL,false); + NORMAL_MACRO(ins->std.algMacro,0,1,"alg",FM_NAME(FM_SUS),32,ins->std.algMacro.open,true,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[0],0,1,NULL,false); + NORMAL_MACRO(ins->std.fbMacro,0,7,"fb",FM_NAME(FM_FB),96,ins->std.fbMacro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[1],0,7,NULL,false); + NORMAL_MACRO(ins->std.fmsMacro,0,1,"fms",FM_NAME(FM_DC),32,ins->std.fmsMacro.open,true,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[2],0,1,NULL,false); + NORMAL_MACRO(ins->std.amsMacro,0,1,"ams",FM_NAME(FM_DM),32,ins->std.amsMacro.open,true,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[3],0,1,NULL,false); } else { - NORMAL_MACRO(ins->std.algMacro,ins->std.algMacroLen,ins->std.algMacroLoop,ins->std.algMacroRel,0,7,"alg",FM_NAME(FM_ALG),96,ins->std.algMacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[0],0,7,NULL,false); - NORMAL_MACRO(ins->std.fbMacro,ins->std.fbMacroLen,ins->std.fbMacroLoop,ins->std.fbMacroRel,0,7,"fb",FM_NAME(FM_FB),96,ins->std.fbMacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[1],0,7,NULL,false); + NORMAL_MACRO(ins->std.algMacro,0,7,"alg",FM_NAME(FM_ALG),96,ins->std.algMacro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[0],0,7,NULL,false); + NORMAL_MACRO(ins->std.fbMacro,0,7,"fb",FM_NAME(FM_FB),96,ins->std.fbMacro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[1],0,7,NULL,false); if (ins->type!=DIV_INS_OPL) { - NORMAL_MACRO(ins->std.fmsMacro,ins->std.fmsMacroLen,ins->std.fmsMacroLoop,ins->std.fmsMacroRel,0,7,"fms",FM_NAME(FM_FMS),96,ins->std.fmsMacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[2],0,7,NULL,false); - NORMAL_MACRO(ins->std.amsMacro,ins->std.amsMacroLen,ins->std.amsMacroLoop,ins->std.amsMacroRel,0,3,"ams",FM_NAME(FM_AMS),48,ins->std.amsMacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[3],0,3,NULL,false); + if (ins->type==DIV_INS_OPZ) { + NORMAL_MACRO(ins->std.fmsMacro,0,7,"fms",FM_NAME(FM_FMS),96,ins->std.fmsMacro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[2],0,7,NULL,false); + NORMAL_MACRO(ins->std.fms2Macro,0,7,"fms2",FM_NAME(FM_FMS2),96,ins->std.fms2Macro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[3],0,7,NULL,false); + NORMAL_MACRO(ins->std.amsMacro,0,3,"ams",FM_NAME(FM_AMS),48,ins->std.amsMacro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,3,NULL,false); + NORMAL_MACRO(ins->std.ams2Macro,0,3,"ams2",FM_NAME(FM_AMS2),48,ins->std.ams2Macro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[5],0,3,NULL,false); + } else { + NORMAL_MACRO(ins->std.fmsMacro,0,7,"fms",FM_NAME(FM_FMS),96,ins->std.fmsMacro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[2],0,7,NULL,false); + NORMAL_MACRO(ins->std.amsMacro,0,3,"ams",FM_NAME(FM_AMS),48,ins->std.amsMacro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[3],0,3,NULL,false); + } } } if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ) { - NORMAL_MACRO(ins->std.ex1Macro,ins->std.ex1MacroLen,ins->std.ex1MacroLoop,ins->std.ex1MacroRel,0,127,"ex1","AM Depth",128,ins->std.ex1MacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,127,NULL,false); - NORMAL_MACRO(ins->std.ex2Macro,ins->std.ex2MacroLen,ins->std.ex2MacroLoop,ins->std.ex2MacroRel,0,127,"ex2","PM Depth",128,ins->std.ex2MacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[5],0,127,NULL,false); - NORMAL_MACRO(ins->std.ex3Macro,ins->std.ex3MacroLen,ins->std.ex3MacroLoop,ins->std.ex3MacroRel,0,255,"ex3","LFO Speed",128,ins->std.ex3MacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[6],0,255,NULL,false); - NORMAL_MACRO(ins->std.waveMacro,ins->std.waveMacroLen,ins->std.waveMacroLoop,ins->std.waveMacroRel,0,3,"wave","LFO Shape",48,ins->std.waveMacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_WAVE],mmlString[7],0,3,¯oLFOWaves,false); + NORMAL_MACRO(ins->std.ex1Macro,0,127,"ex1","AM Depth",128,ins->std.ex1Macro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[6],0,127,NULL,false); + NORMAL_MACRO(ins->std.ex2Macro,0,127,"ex2","PM Depth",128,ins->std.ex2Macro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[7],0,127,NULL,false); + NORMAL_MACRO(ins->std.ex3Macro,0,255,"ex3","LFO Speed",128,ins->std.ex3Macro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[8],0,255,NULL,false); + NORMAL_MACRO(ins->std.waveMacro,0,3,"wave","LFO Shape",48,ins->std.waveMacro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_WAVE],mmlString[9],0,3,¯oLFOWaves,false); } MACRO_END; ImGui::EndTabItem(); @@ -2041,45 +2090,45 @@ void FurnaceGUI::drawInsEdit() { int maxArDr=(ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ)?31:15; if (ins->type==DIV_INS_OPL) { - OP_MACRO(ins->std.opMacros[ordi].tlMacro,ins->std.opMacros[ordi].tlMacroLen,ins->std.opMacros[ordi].tlMacroLoop,ins->std.opMacros[ordi].tlMacroRel,maxTl,ordi,"tl",FM_NAME(FM_TL),128,ins->std.opMacros[ordi].tlMacroOpen,false,NULL,mmlString[0]); - OP_MACRO(ins->std.opMacros[ordi].arMacro,ins->std.opMacros[ordi].arMacroLen,ins->std.opMacros[ordi].arMacroLoop,ins->std.opMacros[ordi].arMacroRel,maxArDr,ordi,"ar",FM_NAME(FM_AR),64,ins->std.opMacros[ordi].arMacroOpen,false,NULL,mmlString[1]); - OP_MACRO(ins->std.opMacros[ordi].drMacro,ins->std.opMacros[ordi].drMacroLen,ins->std.opMacros[ordi].drMacroLoop,ins->std.opMacros[ordi].drMacroRel,maxArDr,ordi,"dr",FM_NAME(FM_DR),64,ins->std.opMacros[ordi].drMacroOpen,false,NULL,mmlString[2]); - OP_MACRO(ins->std.opMacros[ordi].slMacro,ins->std.opMacros[ordi].slMacroLen,ins->std.opMacros[ordi].slMacroLoop,ins->std.opMacros[ordi].slMacroRel,15,ordi,"sl",FM_NAME(FM_SL),64,ins->std.opMacros[ordi].slMacroOpen,false,NULL,mmlString[5]); - OP_MACRO(ins->std.opMacros[ordi].rrMacro,ins->std.opMacros[ordi].rrMacroLen,ins->std.opMacros[ordi].rrMacroLoop,ins->std.opMacros[ordi].rrMacroRel,15,ordi,"rr",FM_NAME(FM_RR),64,ins->std.opMacros[ordi].rrMacroOpen,false,NULL,mmlString[4]); - OP_MACRO(ins->std.opMacros[ordi].kslMacro,ins->std.opMacros[ordi].kslMacroLen,ins->std.opMacros[ordi].kslMacroLoop,ins->std.opMacros[ordi].kslMacroRel,3,ordi,"ksl",FM_NAME(FM_KSL),32,ins->std.opMacros[ordi].kslMacroOpen,false,NULL,mmlString[6]); - OP_MACRO(ins->std.opMacros[ordi].multMacro,ins->std.opMacros[ordi].multMacroLen,ins->std.opMacros[ordi].multMacroLoop,ins->std.opMacros[ordi].multMacroRel,15,ordi,"mult",FM_NAME(FM_MULT),64,ins->std.opMacros[ordi].multMacroOpen,false,NULL,mmlString[7]); - OP_MACRO(ins->std.opMacros[ordi].wsMacro,ins->std.opMacros[ordi].wsMacroLen,ins->std.opMacros[ordi].wsMacroLoop,ins->std.opMacros[ordi].wsMacroRel,7,ordi,"ws",FM_NAME(FM_WS),64,ins->std.opMacros[ordi].wsMacroOpen,false,NULL,mmlString[8]); + OP_MACRO(ins->std.opMacros[ordi].tlMacro,maxTl,ordi,"tl",FM_NAME(FM_TL),128,ins->std.opMacros[ordi].tlMacro.open,false,NULL,false,0,macroDummyMode,mmlString[0]); + OP_MACRO(ins->std.opMacros[ordi].arMacro,maxArDr,ordi,"ar",FM_NAME(FM_AR),64,ins->std.opMacros[ordi].arMacro.open,false,NULL,false,0,macroDummyMode,mmlString[1]); + OP_MACRO(ins->std.opMacros[ordi].drMacro,maxArDr,ordi,"dr",FM_NAME(FM_DR),64,ins->std.opMacros[ordi].drMacro.open,false,NULL,false,0,macroDummyMode,mmlString[2]); + OP_MACRO(ins->std.opMacros[ordi].slMacro,15,ordi,"sl",FM_NAME(FM_SL),64,ins->std.opMacros[ordi].slMacro.open,false,NULL,false,0,macroDummyMode,mmlString[5]); + OP_MACRO(ins->std.opMacros[ordi].rrMacro,15,ordi,"rr",FM_NAME(FM_RR),64,ins->std.opMacros[ordi].rrMacro.open,false,NULL,false,0,macroDummyMode,mmlString[4]); + OP_MACRO(ins->std.opMacros[ordi].kslMacro,3,ordi,"ksl",FM_NAME(FM_KSL),32,ins->std.opMacros[ordi].kslMacro.open,false,NULL,false,0,macroDummyMode,mmlString[6]); + OP_MACRO(ins->std.opMacros[ordi].multMacro,15,ordi,"mult",FM_NAME(FM_MULT),64,ins->std.opMacros[ordi].multMacro.open,false,NULL,false,0,macroDummyMode,mmlString[7]); + OP_MACRO(ins->std.opMacros[ordi].wsMacro,7,ordi,"ws",FM_NAME(FM_WS),64,ins->std.opMacros[ordi].wsMacro.open,false,NULL,false,0,macroDummyMode,mmlString[8]); - OP_MACRO(ins->std.opMacros[ordi].amMacro,ins->std.opMacros[ordi].amMacroLen,ins->std.opMacros[ordi].amMacroLoop,ins->std.opMacros[ordi].amMacroRel,1,ordi,"am",FM_NAME(FM_AM),32,ins->std.opMacros[ordi].amMacroOpen,true,NULL,mmlString[9]); - OP_MACRO(ins->std.opMacros[ordi].vibMacro,ins->std.opMacros[ordi].vibMacroLen,ins->std.opMacros[ordi].vibMacroLoop,ins->std.opMacros[ordi].vibMacroRel,1,ordi,"vib",FM_NAME(FM_VIB),32,ins->std.opMacros[ordi].vibMacroOpen,true,NULL,mmlString[10]); - OP_MACRO(ins->std.opMacros[ordi].ksrMacro,ins->std.opMacros[ordi].ksrMacroLen,ins->std.opMacros[ordi].ksrMacroLoop,ins->std.opMacros[ordi].ksrMacroRel,1,ordi,"ksr",FM_NAME(FM_KSR),32,ins->std.opMacros[ordi].ksrMacroOpen,true,NULL,mmlString[11]); - OP_MACRO(ins->std.opMacros[ordi].susMacro,ins->std.opMacros[ordi].susMacroLen,ins->std.opMacros[ordi].susMacroLoop,ins->std.opMacros[ordi].susMacroRel,1,ordi,"sus",FM_NAME(FM_SUS),32,ins->std.opMacros[ordi].susMacroOpen,true,NULL,mmlString[12]); + OP_MACRO(ins->std.opMacros[ordi].amMacro,1,ordi,"am",FM_NAME(FM_AM),32,ins->std.opMacros[ordi].amMacro.open,true,NULL,false,0,macroDummyMode,mmlString[9]); + OP_MACRO(ins->std.opMacros[ordi].vibMacro,1,ordi,"vib",FM_NAME(FM_VIB),32,ins->std.opMacros[ordi].vibMacro.open,true,NULL,false,0,macroDummyMode,mmlString[10]); + OP_MACRO(ins->std.opMacros[ordi].ksrMacro,1,ordi,"ksr",FM_NAME(FM_KSR),32,ins->std.opMacros[ordi].ksrMacro.open,true,NULL,false,0,macroDummyMode,mmlString[11]); + OP_MACRO(ins->std.opMacros[ordi].susMacro,1,ordi,"sus",FM_NAME(FM_SUS),32,ins->std.opMacros[ordi].susMacro.open,true,NULL,false,0,macroDummyMode,mmlString[12]); } else if (ins->type==DIV_INS_OPLL) { - OP_MACRO(ins->std.opMacros[ordi].tlMacro,ins->std.opMacros[ordi].tlMacroLen,ins->std.opMacros[ordi].tlMacroLoop,ins->std.opMacros[ordi].tlMacroRel,maxTl,ordi,"tl",FM_NAME(FM_TL),128,ins->std.opMacros[ordi].tlMacroOpen,false,NULL,mmlString[0]); - OP_MACRO(ins->std.opMacros[ordi].arMacro,ins->std.opMacros[ordi].arMacroLen,ins->std.opMacros[ordi].arMacroLoop,ins->std.opMacros[ordi].arMacroRel,maxArDr,ordi,"ar",FM_NAME(FM_AR),64,ins->std.opMacros[ordi].arMacroOpen,false,NULL,mmlString[1]); - OP_MACRO(ins->std.opMacros[ordi].drMacro,ins->std.opMacros[ordi].drMacroLen,ins->std.opMacros[ordi].drMacroLoop,ins->std.opMacros[ordi].drMacroRel,maxArDr,ordi,"dr",FM_NAME(FM_DR),64,ins->std.opMacros[ordi].drMacroOpen,false,NULL,mmlString[2]); - OP_MACRO(ins->std.opMacros[ordi].slMacro,ins->std.opMacros[ordi].slMacroLen,ins->std.opMacros[ordi].slMacroLoop,ins->std.opMacros[ordi].slMacroRel,15,ordi,"sl",FM_NAME(FM_SL),64,ins->std.opMacros[ordi].slMacroOpen,false,NULL,mmlString[5]); - OP_MACRO(ins->std.opMacros[ordi].rrMacro,ins->std.opMacros[ordi].rrMacroLen,ins->std.opMacros[ordi].rrMacroLoop,ins->std.opMacros[ordi].rrMacroRel,15,ordi,"rr",FM_NAME(FM_RR),64,ins->std.opMacros[ordi].rrMacroOpen,false,NULL,mmlString[4]); - OP_MACRO(ins->std.opMacros[ordi].kslMacro,ins->std.opMacros[ordi].kslMacroLen,ins->std.opMacros[ordi].kslMacroLoop,ins->std.opMacros[ordi].kslMacroRel,3,ordi,"ksl",FM_NAME(FM_KSL),32,ins->std.opMacros[ordi].kslMacroOpen,false,NULL,mmlString[6]); - OP_MACRO(ins->std.opMacros[ordi].multMacro,ins->std.opMacros[ordi].multMacroLen,ins->std.opMacros[ordi].multMacroLoop,ins->std.opMacros[ordi].multMacroRel,15,ordi,"mult",FM_NAME(FM_MULT),64,ins->std.opMacros[ordi].multMacroOpen,false,NULL,mmlString[7]); + OP_MACRO(ins->std.opMacros[ordi].tlMacro,maxTl,ordi,"tl",FM_NAME(FM_TL),128,ins->std.opMacros[ordi].tlMacro.open,false,NULL,false,0,macroDummyMode,mmlString[0]); + OP_MACRO(ins->std.opMacros[ordi].arMacro,maxArDr,ordi,"ar",FM_NAME(FM_AR),64,ins->std.opMacros[ordi].arMacro.open,false,NULL,false,0,macroDummyMode,mmlString[1]); + OP_MACRO(ins->std.opMacros[ordi].drMacro,maxArDr,ordi,"dr",FM_NAME(FM_DR),64,ins->std.opMacros[ordi].drMacro.open,false,NULL,false,0,macroDummyMode,mmlString[2]); + OP_MACRO(ins->std.opMacros[ordi].slMacro,15,ordi,"sl",FM_NAME(FM_SL),64,ins->std.opMacros[ordi].slMacro.open,false,NULL,false,0,macroDummyMode,mmlString[5]); + OP_MACRO(ins->std.opMacros[ordi].rrMacro,15,ordi,"rr",FM_NAME(FM_RR),64,ins->std.opMacros[ordi].rrMacro.open,false,NULL,false,0,macroDummyMode,mmlString[4]); + OP_MACRO(ins->std.opMacros[ordi].kslMacro,3,ordi,"ksl",FM_NAME(FM_KSL),32,ins->std.opMacros[ordi].kslMacro.open,false,NULL,false,0,macroDummyMode,mmlString[6]); + OP_MACRO(ins->std.opMacros[ordi].multMacro,15,ordi,"mult",FM_NAME(FM_MULT),64,ins->std.opMacros[ordi].multMacro.open,false,NULL,false,0,macroDummyMode,mmlString[7]); - OP_MACRO(ins->std.opMacros[ordi].amMacro,ins->std.opMacros[ordi].amMacroLen,ins->std.opMacros[ordi].amMacroLoop,ins->std.opMacros[ordi].amMacroRel,1,ordi,"am",FM_NAME(FM_AM),32,ins->std.opMacros[ordi].amMacroOpen,true,NULL,mmlString[8]); - OP_MACRO(ins->std.opMacros[ordi].vibMacro,ins->std.opMacros[ordi].vibMacroLen,ins->std.opMacros[ordi].vibMacroLoop,ins->std.opMacros[ordi].vibMacroRel,1,ordi,"vib",FM_NAME(FM_VIB),32,ins->std.opMacros[ordi].vibMacroOpen,true,NULL,mmlString[9]); - OP_MACRO(ins->std.opMacros[ordi].ksrMacro,ins->std.opMacros[ordi].ksrMacroLen,ins->std.opMacros[ordi].ksrMacroLoop,ins->std.opMacros[ordi].ksrMacroRel,1,ordi,"ksr",FM_NAME(FM_KSR),32,ins->std.opMacros[ordi].ksrMacroOpen,true,NULL,mmlString[10]); - OP_MACRO(ins->std.opMacros[ordi].egtMacro,ins->std.opMacros[ordi].egtMacroLen,ins->std.opMacros[ordi].egtMacroLoop,ins->std.opMacros[ordi].egtMacroRel,1,ordi,"egt",FM_NAME(FM_EGS),32,ins->std.opMacros[ordi].egtMacroOpen,true,NULL,mmlString[11]); + OP_MACRO(ins->std.opMacros[ordi].amMacro,1,ordi,"am",FM_NAME(FM_AM),32,ins->std.opMacros[ordi].amMacro.open,true,NULL,false,0,macroDummyMode,mmlString[8]); + OP_MACRO(ins->std.opMacros[ordi].vibMacro,1,ordi,"vib",FM_NAME(FM_VIB),32,ins->std.opMacros[ordi].vibMacro.open,true,NULL,false,0,macroDummyMode,mmlString[9]); + OP_MACRO(ins->std.opMacros[ordi].ksrMacro,1,ordi,"ksr",FM_NAME(FM_KSR),32,ins->std.opMacros[ordi].ksrMacro.open,true,NULL,false,0,macroDummyMode,mmlString[10]); + OP_MACRO(ins->std.opMacros[ordi].egtMacro,1,ordi,"egt",FM_NAME(FM_EGS),32,ins->std.opMacros[ordi].egtMacro.open,true,NULL,false,0,macroDummyMode,mmlString[11]); } else { - OP_MACRO(ins->std.opMacros[ordi].tlMacro,ins->std.opMacros[ordi].tlMacroLen,ins->std.opMacros[ordi].tlMacroLoop,ins->std.opMacros[ordi].tlMacroRel,maxTl,ordi,"tl",FM_NAME(FM_TL),128,ins->std.opMacros[ordi].tlMacroOpen,false,NULL,mmlString[0]); - OP_MACRO(ins->std.opMacros[ordi].arMacro,ins->std.opMacros[ordi].arMacroLen,ins->std.opMacros[ordi].arMacroLoop,ins->std.opMacros[ordi].arMacroRel,maxArDr,ordi,"ar",FM_NAME(FM_AR),64,ins->std.opMacros[ordi].arMacroOpen,false,NULL,mmlString[1]); - OP_MACRO(ins->std.opMacros[ordi].drMacro,ins->std.opMacros[ordi].drMacroLen,ins->std.opMacros[ordi].drMacroLoop,ins->std.opMacros[ordi].drMacroRel,maxArDr,ordi,"dr",FM_NAME(FM_DR),64,ins->std.opMacros[ordi].drMacroOpen,false,NULL,mmlString[2]); - OP_MACRO(ins->std.opMacros[ordi].d2rMacro,ins->std.opMacros[ordi].d2rMacroLen,ins->std.opMacros[ordi].d2rMacroLoop,ins->std.opMacros[ordi].d2rMacroRel,31,ordi,"d2r",FM_NAME(FM_D2R),64,ins->std.opMacros[ordi].d2rMacroOpen,false,NULL,mmlString[3]); - OP_MACRO(ins->std.opMacros[ordi].rrMacro,ins->std.opMacros[ordi].rrMacroLen,ins->std.opMacros[ordi].rrMacroLoop,ins->std.opMacros[ordi].rrMacroRel,15,ordi,"rr",FM_NAME(FM_RR),64,ins->std.opMacros[ordi].rrMacroOpen,false,NULL,mmlString[4]); - OP_MACRO(ins->std.opMacros[ordi].slMacro,ins->std.opMacros[ordi].slMacroLen,ins->std.opMacros[ordi].slMacroLoop,ins->std.opMacros[ordi].slMacroRel,15,ordi,"sl",FM_NAME(FM_SL),64,ins->std.opMacros[ordi].slMacroOpen,false,NULL,mmlString[5]); - OP_MACRO(ins->std.opMacros[ordi].rsMacro,ins->std.opMacros[ordi].rsMacroLen,ins->std.opMacros[ordi].rsMacroLoop,ins->std.opMacros[ordi].rsMacroRel,3,ordi,"rs",FM_NAME(FM_RS),32,ins->std.opMacros[ordi].rsMacroOpen,false,NULL,mmlString[6]); - OP_MACRO(ins->std.opMacros[ordi].multMacro,ins->std.opMacros[ordi].multMacroLen,ins->std.opMacros[ordi].multMacroLoop,ins->std.opMacros[ordi].multMacroRel,15,ordi,"mult",FM_NAME(FM_MULT),64,ins->std.opMacros[ordi].multMacroOpen,false,NULL,mmlString[7]); - OP_MACRO(ins->std.opMacros[ordi].dtMacro,ins->std.opMacros[ordi].dtMacroLen,ins->std.opMacros[ordi].dtMacroLoop,ins->std.opMacros[ordi].dtMacroRel,7,ordi,"dt",FM_NAME(FM_DT),64,ins->std.opMacros[ordi].dtMacroOpen,false,NULL,mmlString[8]); - OP_MACRO(ins->std.opMacros[ordi].dt2Macro,ins->std.opMacros[ordi].dt2MacroLen,ins->std.opMacros[ordi].dt2MacroLoop,ins->std.opMacros[ordi].dt2MacroRel,3,ordi,"dt2",FM_NAME(FM_DT2),32,ins->std.opMacros[ordi].dt2MacroOpen,false,NULL,mmlString[9]); - OP_MACRO(ins->std.opMacros[ordi].amMacro,ins->std.opMacros[ordi].amMacroLen,ins->std.opMacros[ordi].amMacroLoop,ins->std.opMacros[ordi].amMacroRel,1,ordi,"am",FM_NAME(FM_AM),32,ins->std.opMacros[ordi].amMacroOpen,true,NULL,mmlString[10]); - OP_MACRO(ins->std.opMacros[ordi].ssgMacro,ins->std.opMacros[ordi].ssgMacroLen,ins->std.opMacros[ordi].ssgMacroLoop,ins->std.opMacros[ordi].ssgMacroRel,4,ordi,"ssg",FM_NAME(FM_SSG),64,ins->std.opMacros[ordi].ssgMacroOpen,true,ssgEnvBits,mmlString[11]); + OP_MACRO(ins->std.opMacros[ordi].tlMacro,maxTl,ordi,"tl",FM_NAME(FM_TL),128,ins->std.opMacros[ordi].tlMacro.open,false,NULL,false,0,macroDummyMode,mmlString[0]); + OP_MACRO(ins->std.opMacros[ordi].arMacro,maxArDr,ordi,"ar",FM_NAME(FM_AR),64,ins->std.opMacros[ordi].arMacro.open,false,NULL,false,0,macroDummyMode,mmlString[1]); + OP_MACRO(ins->std.opMacros[ordi].drMacro,maxArDr,ordi,"dr",FM_NAME(FM_DR),64,ins->std.opMacros[ordi].drMacro.open,false,NULL,false,0,macroDummyMode,mmlString[2]); + OP_MACRO(ins->std.opMacros[ordi].d2rMacro,31,ordi,"d2r",FM_NAME(FM_D2R),64,ins->std.opMacros[ordi].d2rMacro.open,false,NULL,false,0,macroDummyMode,mmlString[3]); + OP_MACRO(ins->std.opMacros[ordi].rrMacro,15,ordi,"rr",FM_NAME(FM_RR),64,ins->std.opMacros[ordi].rrMacro.open,false,NULL,false,0,macroDummyMode,mmlString[4]); + OP_MACRO(ins->std.opMacros[ordi].slMacro,15,ordi,"sl",FM_NAME(FM_SL),64,ins->std.opMacros[ordi].slMacro.open,false,NULL,false,0,macroDummyMode,mmlString[5]); + OP_MACRO(ins->std.opMacros[ordi].rsMacro,3,ordi,"rs",FM_NAME(FM_RS),32,ins->std.opMacros[ordi].rsMacro.open,false,NULL,false,0,macroDummyMode,mmlString[6]); + OP_MACRO(ins->std.opMacros[ordi].multMacro,15,ordi,"mult",FM_NAME(FM_MULT),64,ins->std.opMacros[ordi].multMacro.open,false,NULL,false,0,macroDummyMode,mmlString[7]); + OP_MACRO(ins->std.opMacros[ordi].dtMacro,7,ordi,"dt",FM_NAME(FM_DT),64,ins->std.opMacros[ordi].dtMacro.open,false,NULL,false,0,macroDummyMode,mmlString[8]); + OP_MACRO(ins->std.opMacros[ordi].dt2Macro,3,ordi,"dt2",FM_NAME(FM_DT2),32,ins->std.opMacros[ordi].dt2Macro.open,false,NULL,false,0,macroDummyMode,mmlString[9]); + OP_MACRO(ins->std.opMacros[ordi].amMacro,1,ordi,"am",FM_NAME(FM_AM),32,ins->std.opMacros[ordi].amMacro.open,true,NULL,false,0,macroDummyMode,mmlString[10]); + OP_MACRO(ins->std.opMacros[ordi].ssgMacro,4,ordi,"ssg",FM_NAME(FM_SSG),64,ins->std.opMacros[ordi].ssgMacro.open,true,ssgEnvBits,false,0,macroDummyMode,mmlString[11]); } MACRO_END; ImGui::PopID(); @@ -2182,7 +2231,10 @@ void FurnaceGUI::drawInsEdit() { P(ImGui::Checkbox("Volume Macro is Cutoff Macro",&ins->c64.volIsCutoff)); P(ImGui::Checkbox("Absolute Cutoff Macro",&ins->c64.filterIsAbs)); - P(ImGui::Checkbox("Absolute Duty Macro",&ins->c64.dutyIsAbs)); + bool dutyAbs=ins->std.dutyMacro.mode&1; + if (ImGui::Checkbox("Absolute Duty Macro",&dutyAbs)) { PARAMETER + ins->std.dutyMacro.mode^=1; + } ImGui::EndTabItem(); } if (ins->type==DIV_INS_AMIGA) if (ImGui::BeginTabItem("Amiga/Sample")) { @@ -2328,6 +2380,9 @@ void FurnaceGUI::drawInsEdit() { ins->type==DIV_INS_SWAN || ins->type==DIV_INS_PCE || ins->type==DIV_INS_SCC) { + float asFloat[256]; + int asInt[256]; + float loopIndicator[256]; if (ImGui::BeginTabItem("Wavetable")) { ImGui::Checkbox("Enable synthesizer",&ins->ws.enabled); ImGui::SameLine(); @@ -2422,6 +2477,20 @@ void FurnaceGUI::drawInsEdit() { ImGui::EndTabItem(); } + if (ImGui::BeginTabItem("Wavetable Macros")) { + MACRO_BEGIN(0); + NORMAL_MACRO(ins->std.ws.enabledMacro,0,1,"enabled","Enable",160,ins->std.ws.enabledMacro.open,true,oneBit,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[5],0,1,NULL,false); + NORMAL_MACRO(ins->std.ws.oneShotMacro,0,1,"oneShot","One Shot",160,ins->std.ws.oneShotMacro.open,true,oneBit,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,1,NULL,false); + NORMAL_MACRO(ins->std.ws.globalMacro,0,1,"global","Global",160,ins->std.ws.globalMacro.open,true,oneBit,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[6],0,1,NULL,false); + NORMAL_MACRO(ins->std.ws.effectMacro,0,255,"effect","Effect",160,ins->std.ws.effectMacro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[3],0,255,NULL,false); + NORMAL_MACRO(ins->std.ws.wave1Macro,0,255,"wave1","Wave 1",160,ins->std.ws.wave1Macro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[0],0,255,NULL,false); + NORMAL_MACRO(ins->std.ws.wave2Macro,0,255,"wave2","Wave 2",160,ins->std.ws.wave2Macro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[1],0,255,NULL,false); + NORMAL_MACRO(ins->std.ws.rateDividerMacro,1,7,"rateDivider","Rate",160,ins->std.ws.rateDividerMacro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[2],1,7,NULL,false); + NORMAL_MACRO(ins->std.ws.speedMacro,0,255,"speed","Speed",160,ins->std.ws.speedMacro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[6],0,255,NULL,false); + NORMAL_MACRO(ins->std.ws.param1Macro,1,7,"amount","Amount",160,ins->std.ws.param1Macro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[6],1,7,NULL,false); + MACRO_END; + ImGui::EndTabItem(); + } } if (ImGui::BeginTabItem("Macros")) { float asFloat[256]; @@ -2464,13 +2533,13 @@ void FurnaceGUI::drawInsEdit() { volMax=32; } - bool arpMode=ins->std.arpMacroMode; + bool arpMode=ins->std.arpMacro.mode; const char* dutyLabel="Duty/Noise"; int dutyMax=3; if (ins->type==DIV_INS_C64) { dutyLabel="Duty"; - if (ins->c64.dutyIsAbs) { + if (ins->std.dutyMacro.mode) { dutyMax=4095; } else { dutyMax=24; @@ -2517,7 +2586,7 @@ void FurnaceGUI::drawInsEdit() { dutyLabel="Duty"; dutyMax=7; } - bool dutyIsRel=(ins->type==DIV_INS_C64 && !ins->c64.dutyIsAbs); + bool dutyIsRel=(ins->type==DIV_INS_C64 && !ins->std.dutyMacro.mode); const char* waveLabel="Waveform"; int waveMax=(ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930 || ins->type==DIV_INS_VERA)?3:63; @@ -2571,66 +2640,67 @@ void FurnaceGUI::drawInsEdit() { if (settings.macroView==0) { // modern view MACRO_BEGIN(28*dpiScale); if (volMax>0) { - NORMAL_MACRO(ins->std.volMacro,ins->std.volMacroLen,ins->std.volMacroLoop,ins->std.volMacroRel,volMin,volMax,"vol",volumeLabel,160,ins->std.volMacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_VOLUME],mmlString[0],volMin,volMax,NULL,false); + NORMAL_MACRO(ins->std.volMacro,volMin,volMax,"vol",volumeLabel,160,ins->std.volMacro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_VOLUME],mmlString[0],volMin,volMax,NULL,false); } - NORMAL_MACRO(ins->std.arpMacro,ins->std.arpMacroLen,ins->std.arpMacroLoop,ins->std.arpMacroRel,arpMacroScroll,arpMacroScroll+24,"arp","Arpeggio",160,ins->std.arpMacroOpen,false,NULL,true,&arpMacroScroll,(arpMode?-60:-80),0,0,&ins->std.arpMacroMode,uiColors[GUI_COLOR_MACRO_PITCH],mmlString[1],-92,94,(ins->std.arpMacroMode?(¯oHoverNote):NULL),true); + NORMAL_MACRO(ins->std.arpMacro,arpMacroScroll,arpMacroScroll+24,"arp","Arpeggio",160,ins->std.arpMacro.open,false,NULL,true,&arpMacroScroll,(arpMode?-60:-80),0,0,true,1,macroAbsoluteMode,uiColors[GUI_COLOR_MACRO_PITCH],mmlString[1],-92,94,(ins->std.arpMacro.mode?(¯oHoverNote):NULL),true); if (dutyMax>0) { if (ins->type==DIV_INS_MIKEY) { - NORMAL_MACRO(ins->std.dutyMacro,ins->std.dutyMacroLen,ins->std.dutyMacroLoop,ins->std.dutyMacroRel,0,dutyMax,"duty",dutyLabel,160,ins->std.dutyMacroOpen,true,mikeyFeedbackBits,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[2],0,dutyMax,NULL,false); + NORMAL_MACRO(ins->std.dutyMacro,0,dutyMax,"duty",dutyLabel,160,ins->std.dutyMacro.open,true,mikeyFeedbackBits,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[2],0,dutyMax,NULL,false); + } else if (ins->type==DIV_INS_C64) { + NORMAL_MACRO(ins->std.dutyMacro,0,dutyMax,"duty",dutyLabel,160,ins->std.dutyMacro.open,false,NULL,false,NULL,0,0,0,true,1,macroAbsoluteMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[2],0,dutyMax,NULL,false); + } else { + NORMAL_MACRO(ins->std.dutyMacro,0,dutyMax,"duty",dutyLabel,160,ins->std.dutyMacro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[2],0,dutyMax,NULL,false); } - else { - NORMAL_MACRO(ins->std.dutyMacro,ins->std.dutyMacroLen,ins->std.dutyMacroLoop,ins->std.dutyMacroRel,0,dutyMax,"duty",dutyLabel,160,ins->std.dutyMacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[2],0,dutyMax,NULL,false); - } } if (waveMax>0) { - NORMAL_MACRO(ins->std.waveMacro,ins->std.waveMacroLen,ins->std.waveMacroLoop,ins->std.waveMacroRel,0,waveMax,"wave",waveLabel,(bitMode && ins->type!=DIV_INS_PET)?64:160,ins->std.waveMacroOpen,bitMode,waveNames,false,NULL,0,0,((ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930)?1:0),NULL,uiColors[GUI_COLOR_MACRO_WAVE],mmlString[3],0,waveMax,NULL,false); + NORMAL_MACRO(ins->std.waveMacro,0,waveMax,"wave",waveLabel,(bitMode && ins->type!=DIV_INS_PET)?64:160,ins->std.waveMacro.open,bitMode,waveNames,false,NULL,0,0,((ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930)?1:0),false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_WAVE],mmlString[3],0,waveMax,NULL,false); } if (ex1Max>0) { if (ins->type==DIV_INS_C64) { - NORMAL_MACRO(ins->std.ex1Macro,ins->std.ex1MacroLen,ins->std.ex1MacroLoop,ins->std.ex1MacroRel,0,ex1Max,"ex1","Filter Mode",64,ins->std.ex1MacroOpen,true,filtModeBits,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,ex1Max,NULL,false); + NORMAL_MACRO(ins->std.ex1Macro,0,ex1Max,"ex1","Filter Mode",64,ins->std.ex1Macro.open,true,filtModeBits,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,ex1Max,NULL,false); } else if (ins->type==DIV_INS_SAA1099) { - NORMAL_MACRO(ins->std.ex1Macro,ins->std.ex1MacroLen,ins->std.ex1MacroLoop,ins->std.ex1MacroRel,0,ex1Max,"ex1","Envelope",160,ins->std.ex1MacroOpen,true,saaEnvBits,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,ex1Max,NULL,false); + NORMAL_MACRO(ins->std.ex1Macro,0,ex1Max,"ex1","Envelope",160,ins->std.ex1Macro.open,true,saaEnvBits,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,ex1Max,NULL,false); } else if (ins->type==DIV_INS_X1_010) { - NORMAL_MACRO(ins->std.ex1Macro,ins->std.ex1MacroLen,ins->std.ex1MacroLoop,ins->std.ex1MacroRel,0,ex1Max,"ex1","Envelope Mode",160,ins->std.ex1MacroOpen,true,x1_010EnvBits,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,ex1Max,NULL,false); + NORMAL_MACRO(ins->std.ex1Macro,0,ex1Max,"ex1","Envelope Mode",160,ins->std.ex1Macro.open,true,x1_010EnvBits,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,ex1Max,NULL,false); } else if (ins->type==DIV_INS_N163) { - NORMAL_MACRO(ins->std.ex1Macro,ins->std.ex1MacroLen,ins->std.ex1MacroLoop,ins->std.ex1MacroRel,0,ex1Max,"ex1","Waveform len.",160,ins->std.ex1MacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,ex1Max,NULL,false); + NORMAL_MACRO(ins->std.ex1Macro,0,ex1Max,"ex1","Waveform len.",160,ins->std.ex1Macro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,ex1Max,NULL,false); } else if (ins->type==DIV_INS_FDS) { - NORMAL_MACRO(ins->std.ex1Macro,ins->std.ex1MacroLen,ins->std.ex1MacroLoop,ins->std.ex1MacroRel,0,ex1Max,"ex1","Mod Depth",160,ins->std.ex1MacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,ex1Max,NULL,false); + NORMAL_MACRO(ins->std.ex1Macro,0,ex1Max,"ex1","Mod Depth",160,ins->std.ex1Macro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,ex1Max,NULL,false); } else { - NORMAL_MACRO(ins->std.ex1Macro,ins->std.ex1MacroLen,ins->std.ex1MacroLoop,ins->std.ex1MacroRel,0,ex1Max,"ex1","Duty",160,ins->std.ex1MacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,ex1Max,NULL,false); + NORMAL_MACRO(ins->std.ex1Macro,0,ex1Max,"ex1","Duty",160,ins->std.ex1Macro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,ex1Max,NULL,false); } } if (ex2Max>0) { if (ins->type==DIV_INS_C64) { - NORMAL_MACRO(ins->std.ex2Macro,ins->std.ex2MacroLen,ins->std.ex2MacroLoop,ins->std.ex2MacroRel,0,ex2Max,"ex2","Resonance",64,ins->std.ex2MacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[5],0,ex2Max,NULL,false); + NORMAL_MACRO(ins->std.ex2Macro,0,ex2Max,"ex2","Resonance",64,ins->std.ex2Macro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[5],0,ex2Max,NULL,false); } else if (ins->type==DIV_INS_N163) { - NORMAL_MACRO(ins->std.ex2Macro,ins->std.ex2MacroLen,ins->std.ex2MacroLoop,ins->std.ex2MacroRel,0,ex2Max,"ex2","Waveform update",64,ins->std.ex2MacroOpen,true,n163UpdateBits,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[5],0,ex2Max,NULL,false); + NORMAL_MACRO(ins->std.ex2Macro,0,ex2Max,"ex2","Waveform update",64,ins->std.ex2Macro.open,true,n163UpdateBits,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[5],0,ex2Max,NULL,false); } else if (ins->type==DIV_INS_FDS) { - NORMAL_MACRO(ins->std.ex2Macro,ins->std.ex2MacroLen,ins->std.ex2MacroLoop,ins->std.ex2MacroRel,0,ex2Max,"ex2","Mod Speed",160,ins->std.ex2MacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[5],0,ex2Max,NULL,false); + NORMAL_MACRO(ins->std.ex2Macro,0,ex2Max,"ex2","Mod Speed",160,ins->std.ex2Macro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[5],0,ex2Max,NULL,false); } else { - NORMAL_MACRO(ins->std.ex2Macro,ins->std.ex2MacroLen,ins->std.ex2MacroLoop,ins->std.ex2MacroRel,0,ex2Max,"ex2","Envelope",ex2Bit?64:160,ins->std.ex2MacroOpen,ex2Bit,ayEnvBits,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[5],0,ex2Max,NULL,false); + NORMAL_MACRO(ins->std.ex2Macro,0,ex2Max,"ex2","Envelope",ex2Bit?64:160,ins->std.ex2Macro.open,ex2Bit,ayEnvBits,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[5],0,ex2Max,NULL,false); } } if (ins->type==DIV_INS_C64) { - NORMAL_MACRO(ins->std.ex3Macro,ins->std.ex3MacroLen,ins->std.ex3MacroLoop,ins->std.ex3MacroRel,0,2,"ex3","Special",32,ins->std.ex3MacroOpen,true,c64SpecialBits,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[6],0,2,NULL,false); + NORMAL_MACRO(ins->std.ex3Macro,0,2,"ex3","Special",32,ins->std.ex3Macro.open,true,c64SpecialBits,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[6],0,2,NULL,false); } if (ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930 || ins->type==DIV_INS_X1_010) { - NORMAL_MACRO(ins->std.ex3Macro,ins->std.ex3MacroLen,ins->std.ex3MacroLoop,ins->std.ex3MacroRel,0,15,"ex3","AutoEnv Num",96,ins->std.ex3MacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[6],0,15,NULL,false); - NORMAL_MACRO(ins->std.algMacro,ins->std.algMacroLen,ins->std.algMacroLoop,ins->std.algMacroRel,0,15,"alg","AutoEnv Den",96,ins->std.algMacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[7],0,15,NULL,false); + NORMAL_MACRO(ins->std.ex3Macro,0,15,"ex3","AutoEnv Num",96,ins->std.ex3Macro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[6],0,15,NULL,false); + NORMAL_MACRO(ins->std.algMacro,0,15,"alg","AutoEnv Den",96,ins->std.algMacro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[7],0,15,NULL,false); } if (ins->type==DIV_INS_AY8930) { // oh my i am running out of macros - NORMAL_MACRO(ins->std.fbMacro,ins->std.fbMacroLen,ins->std.fbMacroLoop,ins->std.fbMacroRel,0,8,"fb","Noise AND Mask",96,ins->std.fbMacroOpen,true,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[8],0,8,NULL,false); - NORMAL_MACRO(ins->std.fmsMacro,ins->std.fmsMacroLen,ins->std.fmsMacroLoop,ins->std.fmsMacroRel,0,8,"fms","Noise OR Mask",96,ins->std.fmsMacroOpen,true,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[9],0,8,NULL,false); + NORMAL_MACRO(ins->std.fbMacro,0,8,"fb","Noise AND Mask",96,ins->std.fbMacro.open,true,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[8],0,8,NULL,false); + NORMAL_MACRO(ins->std.fmsMacro,0,8,"fms","Noise OR Mask",96,ins->std.fmsMacro.open,true,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[9],0,8,NULL,false); } if (ins->type==DIV_INS_N163) { - NORMAL_MACRO(ins->std.ex3Macro,ins->std.ex3MacroLen,ins->std.ex3MacroLoop,ins->std.ex3MacroRel,0,255,"ex3","Waveform to Load",160,ins->std.ex3MacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[6],0,255,NULL,false); - NORMAL_MACRO(ins->std.algMacro,ins->std.algMacroLen,ins->std.algMacroLoop,ins->std.algMacroRel,0,255,"alg","Wave pos. to Load",160,ins->std.algMacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[7],0,255,NULL,false); - NORMAL_MACRO(ins->std.fbMacro,ins->std.fbMacroLen,ins->std.fbMacroLoop,ins->std.fbMacroRel,0,252,"fb","Wave len. to Load",160,ins->std.fbMacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[8],0,252,NULL,false); - NORMAL_MACRO(ins->std.fmsMacro,ins->std.fmsMacroLen,ins->std.fmsMacroLoop,ins->std.fmsMacroRel,0,2,"fms","Waveform load",64,ins->std.fmsMacroOpen,true,n163UpdateBits,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[9],0,2,NULL,false); + NORMAL_MACRO(ins->std.ex3Macro,0,255,"ex3","Waveform to Load",160,ins->std.ex3Macro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[6],0,255,NULL,false); + NORMAL_MACRO(ins->std.algMacro,0,255,"alg","Wave pos. to Load",160,ins->std.algMacro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[7],0,255,NULL,false); + NORMAL_MACRO(ins->std.fbMacro,0,252,"fb","Wave len. to Load",160,ins->std.fbMacro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[8],0,252,NULL,false); + NORMAL_MACRO(ins->std.fmsMacro,0,2,"fms","Waveform load",64,ins->std.fmsMacro.open,true,n163UpdateBits,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[9],0,2,NULL,false); } if (ins->type==DIV_INS_FDS) { - NORMAL_MACRO(ins->std.ex3Macro,ins->std.ex3MacroLen,ins->std.ex3MacroLoop,ins->std.ex3MacroRel,0,127,"ex3","Mod Position",160,ins->std.ex3MacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[6],0,2,NULL,false); + NORMAL_MACRO(ins->std.ex3Macro,0,127,"ex3","Mod Position",160,ins->std.ex3Macro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[6],0,2,NULL,false); } MACRO_END; @@ -2646,87 +2716,87 @@ void FurnaceGUI::drawInsEdit() { } else { ImGui::Text("Volume Macro"); } - for (int i=0; istd.volMacroLen; i++) { + for (int i=0; istd.volMacro.len; i++) { if (ins->type==DIV_INS_C64 && ins->c64.volIsCutoff && !ins->c64.filterIsAbs) { - asFloat[i]=ins->std.volMacro[i]-18; + asFloat[i]=ins->std.volMacro.val[i]-18; } else { - asFloat[i]=ins->std.volMacro[i]; + asFloat[i]=ins->std.volMacro.val[i]; } - loopIndicator[i]=(ins->std.volMacroLoop!=-1 && i>=ins->std.volMacroLoop); + loopIndicator[i]=(ins->std.volMacro.loop!=-1 && i>=ins->std.volMacro.loop); } macroDragScroll=0; if (volMax>0) { ImGui::PushStyleVar(ImGuiStyleVar_FramePadding,ImVec2(0.0f,0.0f)); - ImGui::PlotHistogram("##IVolMacro",asFloat,ins->std.volMacroLen,0,NULL,volMin,volMax,ImVec2(400.0f*dpiScale,200.0f*dpiScale)); + ImGui::PlotHistogram("##IVolMacro",asFloat,ins->std.volMacro.len,0,NULL,volMin,volMax,ImVec2(400.0f*dpiScale,200.0f*dpiScale)); if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) { macroDragStart=ImGui::GetItemRectMin(); macroDragAreaSize=ImVec2(400.0f*dpiScale,200.0f*dpiScale); macroDragMin=volMin; macroDragMax=volMax; - macroDragLen=ins->std.volMacroLen; + macroDragLen=ins->std.volMacro.len; macroDragActive=true; - macroDragTarget=ins->std.volMacro; + macroDragTarget=ins->std.volMacro.val; macroDragChar=false; processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y); } - ImGui::PlotHistogram("##IVolMacroLoop",loopIndicator,ins->std.volMacroLen,0,NULL,0,1,ImVec2(400.0f*dpiScale,16.0f*dpiScale)); + ImGui::PlotHistogram("##IVolMacro.loop",loopIndicator,ins->std.volMacro.len,0,NULL,0,1,ImVec2(400.0f*dpiScale,16.0f*dpiScale)); if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) { macroLoopDragStart=ImGui::GetItemRectMin(); macroLoopDragAreaSize=ImVec2(400.0f*dpiScale,16.0f*dpiScale); - macroLoopDragLen=ins->std.volMacroLen; - macroLoopDragTarget=&ins->std.volMacroLoop; + macroLoopDragLen=ins->std.volMacro.len; + macroLoopDragTarget=&ins->std.volMacro.loop; macroLoopDragActive=true; processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y); } if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) { - ins->std.volMacroLoop=-1; + ins->std.volMacro.loop=-1; } ImGui::PopStyleVar(); - if (ImGui::InputScalar("Length##IVolMacroL",ImGuiDataType_U8,&ins->std.volMacroLen,&_ONE,&_THREE)) { - if (ins->std.volMacroLen>127) ins->std.volMacroLen=127; + if (ImGui::InputScalar("Length##IVolMacroL",ImGuiDataType_U8,&ins->std.volMacro.len,&_ONE,&_THREE)) { + if (ins->std.volMacro.len>127) ins->std.volMacro.len=127; } } // arp macro ImGui::Separator(); ImGui::Text("Arpeggio Macro"); - for (int i=0; istd.arpMacroLen; i++) { - asFloat[i]=ins->std.arpMacro[i]; - loopIndicator[i]=(ins->std.arpMacroLoop!=-1 && i>=ins->std.arpMacroLoop); + for (int i=0; istd.arpMacro.len; i++) { + asFloat[i]=ins->std.arpMacro.val[i]; + loopIndicator[i]=(ins->std.arpMacro.loop!=-1 && i>=ins->std.arpMacro.loop); } ImGui::PushStyleVar(ImGuiStyleVar_FramePadding,ImVec2(0.0f,0.0f)); - ImGui::PlotHistogram("##IArpMacro",asFloat,ins->std.arpMacroLen,0,NULL,arpMode?arpMacroScroll:(arpMacroScroll-12),arpMacroScroll+(arpMode?24:12),ImVec2(400.0f*dpiScale,200.0f*dpiScale)); + ImGui::PlotHistogram("##IArpMacro",asFloat,ins->std.arpMacro.len,0,NULL,arpMode?arpMacroScroll:(arpMacroScroll-12),arpMacroScroll+(arpMode?24:12),ImVec2(400.0f*dpiScale,200.0f*dpiScale)); if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) { macroDragStart=ImGui::GetItemRectMin(); macroDragAreaSize=ImVec2(400.0f*dpiScale,200.0f*dpiScale); macroDragMin=arpMacroScroll; macroDragMax=arpMacroScroll+24; - macroDragLen=ins->std.arpMacroLen; + macroDragLen=ins->std.arpMacro.len; macroDragActive=true; - macroDragTarget=ins->std.arpMacro; + macroDragTarget=ins->std.arpMacro.val; macroDragChar=false; processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y); } ImGui::SameLine(); CWVSliderInt("##IArpMacroPos",ImVec2(20.0f*dpiScale,200.0f*dpiScale),&arpMacroScroll,arpMode?0:-80,70); - ImGui::PlotHistogram("##IArpMacroLoop",loopIndicator,ins->std.arpMacroLen,0,NULL,0,1,ImVec2(400.0f*dpiScale,16.0f*dpiScale)); + ImGui::PlotHistogram("##IArpMacro.loop",loopIndicator,ins->std.arpMacro.len,0,NULL,0,1,ImVec2(400.0f*dpiScale,16.0f*dpiScale)); if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) { macroLoopDragStart=ImGui::GetItemRectMin(); macroLoopDragAreaSize=ImVec2(400.0f*dpiScale,16.0f*dpiScale); - macroLoopDragLen=ins->std.arpMacroLen; - macroLoopDragTarget=&ins->std.arpMacroLoop; + macroLoopDragLen=ins->std.arpMacro.len; + macroLoopDragTarget=&ins->std.arpMacro.loop; macroLoopDragActive=true; processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y); } if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) { - ins->std.arpMacroLoop=-1; + ins->std.arpMacro.loop=-1; } ImGui::PopStyleVar(); - if (ImGui::InputScalar("Length##IArpMacroL",ImGuiDataType_U8,&ins->std.arpMacroLen,&_ONE,&_THREE)) { - if (ins->std.arpMacroLen>127) ins->std.arpMacroLen=127; + if (ImGui::InputScalar("Length##IArpMacroL",ImGuiDataType_U8,&ins->std.arpMacro.len,&_ONE,&_THREE)) { + if (ins->std.arpMacro.len>127) ins->std.arpMacro.len=127; } if (ImGui::Checkbox("Fixed",&arpMode)) { - ins->std.arpMacroMode=arpMode; + ins->std.arpMacro.mode=arpMode; if (arpMode) { if (arpMacroScroll<0) arpMacroScroll=0; } @@ -2736,7 +2806,7 @@ void FurnaceGUI::drawInsEdit() { if (dutyMax>0) { ImGui::Separator(); if (ins->type==DIV_INS_C64) { - if (ins->c64.dutyIsAbs) { + if (ins->std.dutyMacro.mode) { ImGui::Text("Duty Macro"); } else { ImGui::Text("Relative Duty Macro"); @@ -2748,39 +2818,39 @@ void FurnaceGUI::drawInsEdit() { ImGui::Text("Duty/Noise Mode Macro"); } } - for (int i=0; istd.dutyMacroLen; i++) { - asFloat[i]=ins->std.dutyMacro[i]-(dutyIsRel?12:0); - loopIndicator[i]=(ins->std.dutyMacroLoop!=-1 && i>=ins->std.dutyMacroLoop); + for (int i=0; istd.dutyMacro.len; i++) { + asFloat[i]=ins->std.dutyMacro.val[i]-(dutyIsRel?12:0); + loopIndicator[i]=(ins->std.dutyMacro.loop!=-1 && i>=ins->std.dutyMacro.loop); } ImGui::PushStyleVar(ImGuiStyleVar_FramePadding,ImVec2(0.0f,0.0f)); - ImGui::PlotHistogram("##IDutyMacro",asFloat,ins->std.dutyMacroLen,0,NULL,dutyIsRel?-12:0,dutyMax-(dutyIsRel?12:0),ImVec2(400.0f*dpiScale,200.0f*dpiScale)); + ImGui::PlotHistogram("##IDutyMacro",asFloat,ins->std.dutyMacro.len,0,NULL,dutyIsRel?-12:0,dutyMax-(dutyIsRel?12:0),ImVec2(400.0f*dpiScale,200.0f*dpiScale)); if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) { macroDragStart=ImGui::GetItemRectMin(); macroDragAreaSize=ImVec2(400.0f*dpiScale,200.0f*dpiScale); macroDragMin=0; macroDragMax=dutyMax; - macroDragLen=ins->std.dutyMacroLen; + macroDragLen=ins->std.dutyMacro.len; macroDragActive=true; - macroDragTarget=ins->std.dutyMacro; + macroDragTarget=ins->std.dutyMacro.val; macroDragChar=false; processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y); } - ImGui::PlotHistogram("##IDutyMacroLoop",loopIndicator,ins->std.dutyMacroLen,0,NULL,0,1,ImVec2(400.0f*dpiScale,16.0f*dpiScale)); + ImGui::PlotHistogram("##IDutyMacro.loop",loopIndicator,ins->std.dutyMacro.len,0,NULL,0,1,ImVec2(400.0f*dpiScale,16.0f*dpiScale)); if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) { macroLoopDragStart=ImGui::GetItemRectMin(); macroLoopDragAreaSize=ImVec2(400.0f*dpiScale,16.0f*dpiScale); - macroLoopDragLen=ins->std.dutyMacroLen; - macroLoopDragTarget=&ins->std.dutyMacroLoop; + macroLoopDragLen=ins->std.dutyMacro.len; + macroLoopDragTarget=&ins->std.dutyMacro.loop; macroLoopDragActive=true; processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y); } if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) { - ins->std.dutyMacroLoop=-1; + ins->std.dutyMacro.loop=-1; } ImGui::PopStyleVar(); - if (ImGui::InputScalar("Length##IDutyMacroL",ImGuiDataType_U8,&ins->std.dutyMacroLen,&_ONE,&_THREE)) { - if (ins->std.dutyMacroLen>127) ins->std.dutyMacroLen=127; + if (ImGui::InputScalar("Length##IDutyMacroL",ImGuiDataType_U8,&ins->std.dutyMacro.len,&_ONE,&_THREE)) { + if (ins->std.dutyMacro.len>127) ins->std.dutyMacro.len=127; } } @@ -2788,24 +2858,24 @@ void FurnaceGUI::drawInsEdit() { if (waveMax>0) { ImGui::Separator(); ImGui::Text("Waveform Macro"); - for (int i=0; istd.waveMacroLen; i++) { - asFloat[i]=ins->std.waveMacro[i]; + for (int i=0; istd.waveMacro.len; i++) { + asFloat[i]=ins->std.waveMacro.val[i]; if (ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930) { - asInt[i]=ins->std.waveMacro[i]+1; + asInt[i]=ins->std.waveMacro.val[i]+1; } else { - asInt[i]=ins->std.waveMacro[i]; + asInt[i]=ins->std.waveMacro.val[i]; } - loopIndicator[i]=(ins->std.waveMacroLoop!=-1 && i>=ins->std.waveMacroLoop); + loopIndicator[i]=(ins->std.waveMacro.loop!=-1 && i>=ins->std.waveMacro.loop); } ImGui::PushStyleVar(ImGuiStyleVar_FramePadding,ImVec2(0.0f,0.0f)); ImVec2 areaSize=ImVec2(400.0f*dpiScale,200.0f*dpiScale); if (ins->type==DIV_INS_C64 || ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930 || ins->type==DIV_INS_SAA1099) { areaSize=ImVec2(400.0f*dpiScale,waveMax*32.0f*dpiScale); - PlotBitfield("##IWaveMacro",asInt,ins->std.waveMacroLen,0,(ins->type==DIV_INS_C64)?c64ShapeBits:ayShapeBits,waveMax,areaSize); + PlotBitfield("##IWaveMacro",asInt,ins->std.waveMacro.len,0,(ins->type==DIV_INS_C64)?c64ShapeBits:ayShapeBits,waveMax,areaSize); bitMode=true; } else { - ImGui::PlotHistogram("##IWaveMacro",asFloat,ins->std.waveMacroLen,0,NULL,0,waveMax,areaSize); + ImGui::PlotHistogram("##IWaveMacro",asFloat,ins->std.waveMacro.len,0,NULL,0,waveMax,areaSize); } if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) { macroDragStart=ImGui::GetItemRectMin(); @@ -2816,27 +2886,27 @@ void FurnaceGUI::drawInsEdit() { macroDragBitMode=bitMode; macroDragInitialValueSet=false; macroDragInitialValue=false; - macroDragLen=ins->std.waveMacroLen; + macroDragLen=ins->std.waveMacro.len; macroDragActive=true; - macroDragTarget=ins->std.waveMacro; + macroDragTarget=ins->std.waveMacro.val; macroDragChar=false; processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y); } - ImGui::PlotHistogram("##IWaveMacroLoop",loopIndicator,ins->std.waveMacroLen,0,NULL,0,1,ImVec2(400.0f*dpiScale,16.0f*dpiScale)); + ImGui::PlotHistogram("##IWaveMacro.loop",loopIndicator,ins->std.waveMacro.len,0,NULL,0,1,ImVec2(400.0f*dpiScale,16.0f*dpiScale)); if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) { macroLoopDragStart=ImGui::GetItemRectMin(); macroLoopDragAreaSize=ImVec2(400.0f*dpiScale,16.0f*dpiScale); - macroLoopDragLen=ins->std.waveMacroLen; - macroLoopDragTarget=&ins->std.waveMacroLoop; + macroLoopDragLen=ins->std.waveMacro.len; + macroLoopDragTarget=&ins->std.waveMacro.loop; macroLoopDragActive=true; processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y); } if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) { - ins->std.waveMacroLoop=-1; + ins->std.waveMacro.loop=-1; } ImGui::PopStyleVar(); - if (ImGui::InputScalar("Length##IWaveMacroL",ImGuiDataType_U8,&ins->std.waveMacroLen,&_ONE,&_THREE)) { - if (ins->std.waveMacroLen>127) ins->std.waveMacroLen=127; + if (ImGui::InputScalar("Length##IWaveMacroL",ImGuiDataType_U8,&ins->std.waveMacro.len,&_ONE,&_THREE)) { + if (ins->std.waveMacro.len>127) ins->std.waveMacro.len=127; } } @@ -2848,39 +2918,39 @@ void FurnaceGUI::drawInsEdit() { } else { ImGui::Text("Extra 1 Macro"); } - for (int i=0; istd.ex1MacroLen; i++) { - asFloat[i]=ins->std.ex1Macro[i]; - loopIndicator[i]=(ins->std.ex1MacroLoop!=-1 && i>=ins->std.ex1MacroLoop); + for (int i=0; istd.ex1Macro.len; i++) { + asFloat[i]=ins->std.ex1Macro.val[i]; + loopIndicator[i]=(ins->std.ex1Macro.loop!=-1 && i>=ins->std.ex1Macro.loop); } ImGui::PushStyleVar(ImGuiStyleVar_FramePadding,ImVec2(0.0f,0.0f)); - ImGui::PlotHistogram("##IEx1Macro",asFloat,ins->std.ex1MacroLen,0,NULL,0,ex1Max,ImVec2(400.0f*dpiScale,200.0f*dpiScale)); + ImGui::PlotHistogram("##IEx1Macro",asFloat,ins->std.ex1Macro.len,0,NULL,0,ex1Max,ImVec2(400.0f*dpiScale,200.0f*dpiScale)); if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) { macroDragStart=ImGui::GetItemRectMin(); macroDragAreaSize=ImVec2(400.0f*dpiScale,200.0f*dpiScale); macroDragMin=0; macroDragMax=ex1Max; - macroDragLen=ins->std.ex1MacroLen; + macroDragLen=ins->std.ex1Macro.len; macroDragActive=true; - macroDragTarget=ins->std.ex1Macro; + macroDragTarget=ins->std.ex1Macro.val; macroDragChar=false; processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y); } - ImGui::PlotHistogram("##IEx1MacroLoop",loopIndicator,ins->std.ex1MacroLen,0,NULL,0,1,ImVec2(400.0f*dpiScale,16.0f*dpiScale)); + ImGui::PlotHistogram("##IEx1Macro.loop",loopIndicator,ins->std.ex1Macro.len,0,NULL,0,1,ImVec2(400.0f*dpiScale,16.0f*dpiScale)); if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) { macroLoopDragStart=ImGui::GetItemRectMin(); macroLoopDragAreaSize=ImVec2(400.0f*dpiScale,16.0f*dpiScale); - macroLoopDragLen=ins->std.ex1MacroLen; - macroLoopDragTarget=&ins->std.ex1MacroLoop; + macroLoopDragLen=ins->std.ex1Macro.len; + macroLoopDragTarget=&ins->std.ex1Macro.loop; macroLoopDragActive=true; processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y); } if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) { - ins->std.ex1MacroLoop=-1; + ins->std.ex1Macro.loop=-1; } ImGui::PopStyleVar(); - if (ImGui::InputScalar("Length##IEx1MacroL",ImGuiDataType_U8,&ins->std.ex1MacroLen,&_ONE,&_THREE)) { - if (ins->std.ex1MacroLen>127) ins->std.ex1MacroLen=127; + if (ImGui::InputScalar("Length##IEx1MacroL",ImGuiDataType_U8,&ins->std.ex1Macro.len,&_ONE,&_THREE)) { + if (ins->std.ex1Macro.len>127) ins->std.ex1Macro.len=127; } } } From 13bdf2d86ddb5b9c82e12d37e39bdc7e64739df4 Mon Sep 17 00:00:00 2001 From: cam900 Date: Sun, 10 Apr 2022 15:16:51 +0900 Subject: [PATCH 38/76] Prepare for FMS2, AMS2 macro for YM2414 --- src/engine/platform/tx81z.cpp | 10 ++++++++++ src/gui/insEdit.cpp | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/engine/platform/tx81z.cpp b/src/engine/platform/tx81z.cpp index 8ae4c688..198968a1 100644 --- a/src/engine/platform/tx81z.cpp +++ b/src/engine/platform/tx81z.cpp @@ -272,10 +272,18 @@ void DivPlatformTX81Z::tick() { chan[i].state.fms=chan[i].std.fms.val; rWrite(chanOffs[i]+ADDR_FMS_AMS,((chan[i].state.fms&7)<<4)|(chan[i].state.ams&3)); } + if (chan[i].std.fms2.had) { + chan[i].state.fms2=chan[i].std.fms2.val; + //rWrite(chanOffs[i]+ADDR_FMS_AMS,0x84|((chan[i].state.fms2&7)<<4)|(chan[i].state.ams2&3)); + } if (chan[i].std.ams.had) { chan[i].state.ams=chan[i].std.ams.val; rWrite(chanOffs[i]+ADDR_FMS_AMS,((chan[i].state.fms&7)<<4)|(chan[i].state.ams&3)); } + if (chan[i].std.ams2.had) { + chan[i].state.ams2=chan[i].std.ams2.val; + //rWrite(chanOffs[i]+ADDR_FMS_AMS,0x84|((chan[i].state.fms2&7)<<4)|(chan[i].state.ams2&3)); + } for (int j=0; j<4; j++) { unsigned short baseAddr=chanOffs[i]|opOffs[j]; DivInstrumentFM::Operator& op=chan[i].state.op[j]; @@ -435,6 +443,7 @@ int DivPlatformTX81Z::dispatch(DivCommand c) { rWrite(chanOffs[c.chan]+ADDR_LR_FB_ALG,(chan[c.chan].state.alg&7)|(chan[c.chan].state.fb<<3)|((chan[c.chan].chVolL&1)<<6)|((chan[c.chan].chVolR&1)<<7)); }*/ rWrite(chanOffs[c.chan]+ADDR_FMS_AMS,((chan[c.chan].state.fms&7)<<4)|(chan[c.chan].state.ams&3)); + //rWrite(chanOffs[c.chan]+ADDR_FMS_AMS,0x84|((chan[c.chan].state.fms2&7)<<4)|(chan[c.chan].state.ams2&3)); } chan[c.chan].insChanged=false; @@ -652,6 +661,7 @@ void DivPlatformTX81Z::forceIns() { rWrite(chanOffs[i]+ADDR_LR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3)|((chan[i].chVolL&1)<<6)|((chan[i].chVolR&1)<<7)); }*/ rWrite(chanOffs[i]+ADDR_FMS_AMS,((chan[i].state.fms&7)<<4)|(chan[i].state.ams&3)); + //rWrite(chanOffs[i]+ADDR_FMS_AMS,0x84|((chan[i].state.fms2&7)<<4)|(chan[i].state.ams2&3)); if (chan[i].active) { chan[i].keyOn=true; chan[i].freqChanged=true; diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 75e0cdd8..67b9ba82 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -32,7 +32,7 @@ const char* ssgEnvTypes[8]={ }; const char* fmParamNames[3][32]={ - {"Algorithm", "Feedback", "LFO > Freq", "LFO > Amp", "Attack", "Decay", "Decay 2", "Release", "Sustain", "Level", "EnvScale", "Multiplier", "Detune", "Detune 2", "SSG-EG", "AM", "AM Depth", "Vibrato Depth", "Sustained", "Sustained", "Level Scaling", "Sustain", "Vibrato", "Waveform", "Key Scale Rate", "OP2 Half Sine", "OP1 Half Sine", "EnvShift", "Reverb", "Fine", "LFO > Freq", "LFO > Amp"}, + {"Algorithm", "Feedback", "LFO > Freq", "LFO > Amp", "Attack", "Decay", "Decay 2", "Release", "Sustain", "Level", "EnvScale", "Multiplier", "Detune", "Detune 2", "SSG-EG", "AM", "AM Depth", "Vibrato Depth", "Sustained", "Sustained", "Level Scaling", "Sustain", "Vibrato", "Waveform", "Key Scale Rate", "OP2 Half Sine", "OP1 Half Sine", "EnvShift", "Reverb", "Fine", "LFO2 > Freq", "LFO2 > Amp"}, {"ALG", "FB", "FMS/PMS", "AMS", "AR", "DR", "SR", "RR", "SL", "TL", "KS", "MULT", "DT", "DT2", "SSG-EG", "AM", "AMD", "FMD", "EGT", "EGT", "KSL", "SUS", "VIB", "WS", "KSR", "DC", "DM", "EGS", "REV", "Fine", "FMS/PMS2", "AMS2"}, {"ALG", "FB", "FMS/PMS", "AMS", "AR", "DR", "D2R", "RR", "SL", "TL", "RS", "MULT", "DT", "DT2", "SSG-EG", "AM", "DAM", "DVB", "EGT", "EGS", "KSL", "SUS", "VIB", "WS", "KSR", "DC", "DM", "EGS", "REV", "Fine", "FMS/PMS2", "AMS2"} }; From eb05310d379cc9fdc1830a325aef1aeac81aae9c Mon Sep 17 00:00:00 2001 From: cam900 Date: Sun, 10 Apr 2022 15:49:26 +0900 Subject: [PATCH 39/76] Fix issue in instrument editor --- src/gui/insEdit.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 67b9ba82..c253940b 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -992,7 +992,7 @@ void FurnaceGUI::drawFMEnv(unsigned char tl, unsigned char ar, unsigned char dr, } else { \ modeName=displayModeName[macro.mode]; \ } \ - if (ImGui::BeginCombo("Macro Mode",modeName.c_str())) { \ + if (ImGui::BeginCombo("Macro Mode##IMacroMode_" macroName,modeName.c_str())) { \ String id; \ for (unsigned int i=0; i<=macroModeMax; i++) { \ id=fmt::sprintf("%d: %s",i,displayModeName[i]); \ @@ -1096,7 +1096,7 @@ void FurnaceGUI::drawFMEnv(unsigned char tl, unsigned char ar, unsigned char dr, } else { \ modeName=displayModeName[macro.mode]; \ } \ - if (ImGui::BeginCombo("Macro Mode",modeName.c_str())) { \ + if (ImGui::BeginCombo("Macro Mode##IOPMacroMode_" macroName,modeName.c_str())) { \ String id; \ for (unsigned int i=0; i<=macroModeMax; i++) { \ id=fmt::sprintf("%d: %s",i,displayModeName[i]); \ From 4b912fd1454def465147cd45f3bfdb141baaadb8 Mon Sep 17 00:00:00 2001 From: cam900 Date: Sun, 10 Apr 2022 15:50:59 +0900 Subject: [PATCH 40/76] Code style --- src/engine/macroInt.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/macroInt.h b/src/engine/macroInt.h index 1bc93943..3ce0c872 100644 --- a/src/engine/macroInt.h +++ b/src/engine/macroInt.h @@ -59,7 +59,7 @@ struct DivMacroExecList { void doMacro(bool released) { macro.doMacro(source, released); } - DivMacroExecList(DivMacroStruct &m, DivInstrumentMacro& s): + DivMacroExecList(DivMacroStruct& m, DivInstrumentMacro& s): macro(m), source(s) {} }; From f42855f170016eae5715f74320949ac73a48b471 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 10 Apr 2022 02:11:36 -0500 Subject: [PATCH 41/76] add 30xx effect to hard reset envelope currently only for 2612! --- src/engine/dispatch.h | 1 + src/engine/platform/arcade.cpp | 3 +++ src/engine/platform/arcade.h | 24 +++++++++++++++++++++-- src/engine/platform/genesis.cpp | 28 +++++++++++++++++++++++---- src/engine/platform/genesis.h | 3 ++- src/engine/platform/tx81z.h | 24 +++++++++++++++++++++-- src/engine/platform/ym2610.h | 3 ++- src/engine/platform/ym2610b.h | 3 ++- src/engine/playback.cpp | 34 +++++++++++++++++++++++++++++++++ src/engine/song.h | 7 +++++-- 10 files changed, 117 insertions(+), 13 deletions(-) diff --git a/src/engine/dispatch.h b/src/engine/dispatch.h index 5a1c2db6..37e36a2b 100644 --- a/src/engine/dispatch.h +++ b/src/engine/dispatch.h @@ -56,6 +56,7 @@ enum DivDispatchCmds { DIV_CMD_SAMPLE_BANK, DIV_CMD_SAMPLE_POS, + DIV_CMD_FM_HARD_RESET, DIV_CMD_FM_LFO, DIV_CMD_FM_LFO_WAVE, DIV_CMD_FM_TL, diff --git a/src/engine/platform/arcade.cpp b/src/engine/platform/arcade.cpp index 7c465a51..e9618f29 100644 --- a/src/engine/platform/arcade.cpp +++ b/src/engine/platform/arcade.cpp @@ -132,6 +132,9 @@ const char* DivPlatformArcade::getEffectName(unsigned char effect) { case 0x1f: return "1Fxx: Set PM depth (0 to 7F)"; break; + case 0x30: + return "30xx: Toggle hard envelope reset on new notes"; + break; } return NULL; } diff --git a/src/engine/platform/arcade.h b/src/engine/platform/arcade.h index a305eefd..a6ec82c9 100644 --- a/src/engine/platform/arcade.h +++ b/src/engine/platform/arcade.h @@ -39,10 +39,30 @@ class DivPlatformArcade: public DivDispatch { int freq, baseFreq, pitch, note; unsigned char ins; signed char konCycles; - bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, portaPause, furnacePCM; + bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, portaPause, furnacePCM, hardReset; int vol, outVol; unsigned char chVolL, chVolR; - Channel(): freqH(0), freqL(0), freq(0), baseFreq(0), pitch(0), note(0), ins(-1), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), inPorta(false), portaPause(false), furnacePCM(false), vol(0), outVol(0), chVolL(127), chVolR(127) {} + Channel(): + freqH(0), + freqL(0), + freq(0), + baseFreq(0), + pitch(0), + note(0), + ins(-1), + active(false), + insChanged(true), + freqChanged(false), + keyOn(false), + keyOff(false), + inPorta(false), + portaPause(false), + furnacePCM(false), + hardReset(false), + vol(0), + outVol(0), + chVolL(127), + chVolR(127) {} }; Channel chan[8]; struct QueuedWrite { diff --git a/src/engine/platform/genesis.cpp b/src/engine/platform/genesis.cpp index 0aff2b43..ba9c0f56 100644 --- a/src/engine/platform/genesis.cpp +++ b/src/engine/platform/genesis.cpp @@ -74,9 +74,9 @@ const char* DivPlatformGenesis::getEffectName(unsigned char effect) { case 0x1d: return "1Dxx: Set attack of operator 4 (0 to 1F)"; break; - case 0x20: - return "20xy: Set PSG noise mode (x: preset freq/ch3 freq; y: thin pulse/noise)"; - break; + case 0x30: + return "30xx: Toggle hard envelope reset on new notes"; + break; } return NULL; } @@ -346,7 +346,25 @@ void DivPlatformGenesis::tick() { } if (chan[i].keyOn || chan[i].keyOff) { + if (chan[i].hardReset && chan[i].keyOn) { + for (int j=0; j<4; j++) { + unsigned short baseAddr=chanOffs[i]|opOffs[j]; + immWrite(baseAddr+ADDR_SL_RR,0x0f); + immWrite(baseAddr+ADDR_TL,0x7f); + oldWrites[baseAddr+ADDR_SL_RR]=-1; + oldWrites[baseAddr+ADDR_TL]=-1; + //rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4)); + } + } immWrite(0x28,0x00|konOffs[i]); + if (chan[i].hardReset && chan[i].keyOn) { + for (int j=0; j<4; j++) { + unsigned short baseAddr=chanOffs[i]|opOffs[j]; + for (int k=0; k<5; k++) { + immWrite(baseAddr+ADDR_SL_RR,0x0f); + } + } + } chan[i].keyOff=false; } } @@ -715,9 +733,11 @@ int DivPlatformGenesis::dispatch(DivCommand c) { unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]]; rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6)); } - break; } + case DIV_CMD_FM_HARD_RESET: + chan[c.chan].hardReset=c.value; + break; case DIV_ALWAYS_SET_VOLUME: return 0; break; diff --git a/src/engine/platform/genesis.h b/src/engine/platform/genesis.h index 095744df..51d98d80 100644 --- a/src/engine/platform/genesis.h +++ b/src/engine/platform/genesis.h @@ -38,7 +38,7 @@ class DivPlatformGenesis: public DivDispatch { unsigned char freqH, freqL; int freq, baseFreq, pitch, note; unsigned char ins; - bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, furnaceDac, inPorta; + bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, furnaceDac, inPorta, hardReset; int vol, outVol; unsigned char pan; Channel(): @@ -57,6 +57,7 @@ class DivPlatformGenesis: public DivDispatch { portaPause(false), furnaceDac(false), inPorta(false), + hardReset(false), vol(0), pan(3) {} }; diff --git a/src/engine/platform/tx81z.h b/src/engine/platform/tx81z.h index b3d00e52..363d5c23 100644 --- a/src/engine/platform/tx81z.h +++ b/src/engine/platform/tx81z.h @@ -38,10 +38,30 @@ class DivPlatformTX81Z: public DivDispatch { int freq, baseFreq, pitch, note; unsigned char ins; signed char konCycles; - bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, portaPause, furnacePCM; + bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, portaPause, furnacePCM, hardReset; int vol, outVol; unsigned char chVolL, chVolR; - Channel(): freqH(0), freqL(0), freq(0), baseFreq(0), pitch(0), note(0), ins(-1), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), inPorta(false), portaPause(false), furnacePCM(false), vol(0), outVol(0), chVolL(127), chVolR(127) {} + Channel(): + freqH(0), + freqL(0), + freq(0), + baseFreq(0), + pitch(0), + note(0), + ins(-1), + active(false), + insChanged(true), + freqChanged(false), + keyOn(false), + keyOff(false), + inPorta(false), + portaPause(false), + furnacePCM(false), + hardReset(false), + vol(0), + outVol(0), + chVolL(127), + chVolR(127) {} }; Channel chan[8]; struct QueuedWrite { diff --git a/src/engine/platform/ym2610.h b/src/engine/platform/ym2610.h index bc70144e..2fd525b0 100644 --- a/src/engine/platform/ym2610.h +++ b/src/engine/platform/ym2610.h @@ -46,7 +46,7 @@ class DivPlatformYM2610: public DivDispatch { int freq, baseFreq, pitch, note; unsigned char ins, psgMode, autoEnvNum, autoEnvDen; signed char konCycles; - bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta, furnacePCM; + bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta, furnacePCM, hardReset; int vol, outVol; int sample; unsigned char pan; @@ -70,6 +70,7 @@ class DivPlatformYM2610: public DivDispatch { portaPause(false), inPorta(false), furnacePCM(false), + hardReset(false), vol(0), outVol(15), sample(-1), diff --git a/src/engine/platform/ym2610b.h b/src/engine/platform/ym2610b.h index 85b9b451..d6b616c5 100644 --- a/src/engine/platform/ym2610b.h +++ b/src/engine/platform/ym2610b.h @@ -38,7 +38,7 @@ class DivPlatformYM2610B: public DivDispatch { int freq, baseFreq, pitch, note; unsigned char ins, psgMode, autoEnvNum, autoEnvDen; signed char konCycles; - bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta, furnacePCM; + bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta, furnacePCM, hardReset; int vol, outVol; int sample; unsigned char pan; @@ -62,6 +62,7 @@ class DivPlatformYM2610B: public DivDispatch { portaPause(false), inPorta(false), furnacePCM(false), + hardReset(false), vol(0), outVol(15), sample(-1), diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index 0118acc4..a9497d66 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -61,6 +61,7 @@ const char* cmdName[DIV_CMD_MAX]={ "SAMPLE_BANK", "SAMPLE_POS", + "FM_HARD_RESET", "FM_LFO", "FM_LFO_WAVE", "FM_TL", @@ -240,6 +241,23 @@ bool DivEngine::perSystemEffect(int ch, unsigned char effect, unsigned char effe case 0x20: // SN noise mode dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_MODE,ch,effectVal)); break; + case 0x30: // toggle hard-reset + dispatchCmd(DivCommand(DIV_CMD_FM_HARD_RESET,ch,effectVal)); + break; + default: + return false; + } + break; + case DIV_SYSTEM_YM2151: + case DIV_SYSTEM_YM2610: + case DIV_SYSTEM_YM2610_EXT: + case DIV_SYSTEM_YM2610B: + case DIV_SYSTEM_YM2610B_EXT: + case DIV_SYSTEM_OPZ: + switch (effect) { + case 0x30: // toggle hard-reset + dispatchCmd(DivCommand(DIV_CMD_FM_HARD_RESET,ch,effectVal)); + break; default: return false; } @@ -340,6 +358,22 @@ bool DivEngine::perSystemEffect(int ch, unsigned char effect, unsigned char effe case 0x18: // drum mode toggle dispatchCmd(DivCommand(DIV_CMD_FM_EXTCH,ch,effectVal)); break; + case 0x30: // toggle hard-reset + dispatchCmd(DivCommand(DIV_CMD_FM_HARD_RESET,ch,effectVal)); + break; + default: + return false; + } + break; + case DIV_SYSTEM_OPLL: + case DIV_SYSTEM_VRC7: + case DIV_SYSTEM_OPL: + case DIV_SYSTEM_OPL2: + case DIV_SYSTEM_OPL3: + switch (effect) { + case 0x30: // toggle hard-reset + dispatchCmd(DivCommand(DIV_CMD_FM_HARD_RESET,ch,effectVal)); + break; default: return false; } diff --git a/src/engine/song.h b/src/engine/song.h index 438c2214..75e5a03e 100644 --- a/src/engine/song.h +++ b/src/engine/song.h @@ -143,12 +143,15 @@ struct DivSong { // - 9: v3.9 // - introduces Genesis system // - introduces system number + // - patterns now stored in current known format // - 7: ??? - // - 5: BETA 3 (?) + // - 5: BETA 3 // - adds arpeggio tick - // - 3: BETA 2 + // - 4: BETA 2 + // - 3: BETA 1 // - possibly the first version that could save // - basic format, no system number, 16 instruments, one speed, YMU759-only + // - patterns were stored in a different format (chars instead of shorts) // - if somebody manages to find a version 2 or even 1 module, please tell me as it will be worth more than a luxury vehicle unsigned short version; bool isDMF; From 570c43e33212a54c1ed3a3d2ff3675c0e4f0e32b Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 10 Apr 2022 02:20:16 -0500 Subject: [PATCH 42/76] GUI: follow cursor when pasting --- src/gui/editing.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gui/editing.cpp b/src/gui/editing.cpp index 9efd436f..034ca441 100644 --- a/src/gui/editing.cpp +++ b/src/gui/editing.cpp @@ -562,6 +562,7 @@ void FurnaceGUI::doPaste(PasteMode mode) { } if (settings.cursorPastePos) { cursor.y=j; + updateScroll(cursor.y); } makeUndo(GUI_UNDO_PATTERN_PASTE); From 55639747ee31d2fae110babc49260d47e3d77982 Mon Sep 17 00:00:00 2001 From: cam900 Date: Sun, 10 Apr 2022 16:32:58 +0900 Subject: [PATCH 43/76] Make GCC happy --- src/gui/insEdit.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index c253940b..b9180022 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -1304,7 +1304,7 @@ void FurnaceGUI::drawInsEdit() { ImGui::Text("Type"); ImGui::TableNextColumn(); - if (ins->type<0 || ins->type>=DIV_INS_MAX) ins->type=DIV_INS_FM; + if (ins->type>=DIV_INS_MAX) ins->type=DIV_INS_FM; int insType=ins->type; ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); if (ImGui::Combo("##Type",&insType,insTypes,DIV_INS_MAX,DIV_INS_MAX)) { From 228822e19efdb848c91475ebb2de21fdfb9af46d Mon Sep 17 00:00:00 2001 From: cam900 Date: Sun, 10 Apr 2022 16:43:32 +0900 Subject: [PATCH 44/76] Fix signed type issue --- src/engine/instrument.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/instrument.cpp b/src/engine/instrument.cpp index ce25d87a..1d8dbe7c 100644 --- a/src/engine/instrument.cpp +++ b/src/engine/instrument.cpp @@ -609,7 +609,7 @@ DivDataErrors DivInstrument::readInsData(SafeReader& reader, short version) { type=(DivInstrumentType)reader.readS(); } if (!istest) { - type=(DivInstrumentType)reader.readC(); + type=(DivInstrumentType)((unsigned char)reader.readC()); } mode=(type==DIV_INS_FM); reader.readC(); From e23dcd6e1bf622e2f2148893534f1024a4077512 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 10 Apr 2022 03:04:31 -0500 Subject: [PATCH 45/76] implement hard reset on OPM/OPZ/OPNB --- src/engine/platform/arcade.cpp | 20 ++++++++++++++++++++ src/engine/platform/tx81z.cpp | 23 +++++++++++++++++++++++ src/engine/platform/ym2610.cpp | 24 ++++++++++++++++++++++++ src/engine/platform/ym2610b.cpp | 24 ++++++++++++++++++++++++ 4 files changed, 91 insertions(+) diff --git a/src/engine/platform/arcade.cpp b/src/engine/platform/arcade.cpp index e9618f29..f570dd6e 100644 --- a/src/engine/platform/arcade.cpp +++ b/src/engine/platform/arcade.cpp @@ -369,7 +369,24 @@ void DivPlatformArcade::tick() { } } if (chan[i].keyOn || chan[i].keyOff) { + if (chan[i].hardReset && chan[i].keyOn) { + for (int j=0; j<4; j++) { + unsigned short baseAddr=chanOffs[i]|opOffs[j]; + immWrite(baseAddr+ADDR_SL_RR,0x0f); + immWrite(baseAddr+ADDR_TL,0x7f); + oldWrites[baseAddr+ADDR_SL_RR]=-1; + oldWrites[baseAddr+ADDR_TL]=-1; + } + } immWrite(0x08,i); + if (chan[i].hardReset && chan[i].keyOn) { + for (int j=0; j<4; j++) { + unsigned short baseAddr=chanOffs[i]|opOffs[j]; + for (int k=0; k<9; k++) { + immWrite(baseAddr+ADDR_SL_RR,0x0f); + } + } + } chan[i].keyOff=false; } } @@ -605,6 +622,9 @@ int DivPlatformArcade::dispatch(DivCommand c) { immWrite(0x19,0x80|pmDepth); break; } + case DIV_CMD_FM_HARD_RESET: + chan[c.chan].hardReset=c.value; + break; case DIV_CMD_STD_NOISE_FREQ: { if (c.chan!=7) break; if (c.value) { diff --git a/src/engine/platform/tx81z.cpp b/src/engine/platform/tx81z.cpp index e9e817cd..aa4cf1f2 100644 --- a/src/engine/platform/tx81z.cpp +++ b/src/engine/platform/tx81z.cpp @@ -137,6 +137,9 @@ const char* DivPlatformTX81Z::getEffectName(unsigned char effect) { case 0x1f: return "1Fxx: Set PM depth (0 to 7F)"; break; + case 0x30: + return "30xx: Toggle hard envelope reset on new notes"; + break; } return NULL; } @@ -330,12 +333,29 @@ void DivPlatformTX81Z::tick() { } } if (chan[i].keyOn || chan[i].keyOff) { + if (chan[i].hardReset && chan[i].keyOn) { + for (int j=0; j<4; j++) { + unsigned short baseAddr=chanOffs[i]|opOffs[j]; + immWrite(baseAddr+ADDR_SL_RR,0x0f); + immWrite(baseAddr+ADDR_TL,0x7f); + oldWrites[baseAddr+ADDR_SL_RR]=-1; + oldWrites[baseAddr+ADDR_TL]=-1; + } + } if (isMuted[i]) { immWrite(chanOffs[i]+ADDR_LR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3)|0x00); } else { //if (chan[i].keyOn) immWrite(0x08,i); immWrite(chanOffs[i]+ADDR_LR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3)|0x00|(chan[i].chVolR<<7)); } + if (chan[i].hardReset && chan[i].keyOn) { + for (int j=0; j<4; j++) { + unsigned short baseAddr=chanOffs[i]|opOffs[j]; + for (int k=0; k<9; k++) { + immWrite(baseAddr+ADDR_SL_RR,0x0f); + } + } + } chan[i].keyOff=false; } } @@ -596,6 +616,9 @@ int DivPlatformTX81Z::dispatch(DivCommand c) { immWrite(0x19,0x80|pmDepth); break; } + case DIV_CMD_FM_HARD_RESET: + chan[c.chan].hardReset=c.value; + break; case DIV_CMD_STD_NOISE_FREQ: { if (c.chan!=7) break; if (c.value) { diff --git a/src/engine/platform/ym2610.cpp b/src/engine/platform/ym2610.cpp index 77c1243b..0994f0e5 100644 --- a/src/engine/platform/ym2610.cpp +++ b/src/engine/platform/ym2610.cpp @@ -309,6 +309,9 @@ const char* DivPlatformYM2610::getEffectName(unsigned char effect) { case 0x29: return "29xy: Set SSG auto-envelope (x: numerator; y: denominator)"; break; + case 0x30: + return "30xx: Toggle hard envelope reset on new notes"; + break; } return NULL; } @@ -489,7 +492,25 @@ void DivPlatformYM2610::tick() { } if (chan[i].keyOn || chan[i].keyOff) { + if (chan[i].hardReset && chan[i].keyOn) { + for (int j=0; j<4; j++) { + unsigned short baseAddr=chanOffs[i]|opOffs[j]; + immWrite(baseAddr+ADDR_SL_RR,0x0f); + immWrite(baseAddr+ADDR_TL,0x7f); + oldWrites[baseAddr+ADDR_SL_RR]=-1; + oldWrites[baseAddr+ADDR_TL]=-1; + //rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4)); + } + } immWrite(0x28,0x00|konOffs[i]); + if (chan[i].hardReset && chan[i].keyOn) { + for (int j=0; j<4; j++) { + unsigned short baseAddr=chanOffs[i]|opOffs[j]; + for (int k=0; k<100; k++) { + immWrite(baseAddr+ADDR_SL_RR,0x0f); + } + } + } chan[i].keyOff=false; } } @@ -930,6 +951,9 @@ int DivPlatformYM2610::dispatch(DivCommand c) { } break; } + case DIV_CMD_FM_HARD_RESET: + chan[c.chan].hardReset=c.value; + break; case DIV_ALWAYS_SET_VOLUME: return 0; break; diff --git a/src/engine/platform/ym2610b.cpp b/src/engine/platform/ym2610b.cpp index dfd84723..7e8c2519 100644 --- a/src/engine/platform/ym2610b.cpp +++ b/src/engine/platform/ym2610b.cpp @@ -373,6 +373,9 @@ const char* DivPlatformYM2610B::getEffectName(unsigned char effect) { case 0x29: return "29xy: Set SSG auto-envelope (x: numerator; y: denominator)"; break; + case 0x30: + return "30xx: Toggle hard envelope reset on new notes"; + break; } return NULL; } @@ -553,7 +556,25 @@ void DivPlatformYM2610B::tick() { } if (chan[i].keyOn || chan[i].keyOff) { + if (chan[i].hardReset && chan[i].keyOn) { + for (int j=0; j<4; j++) { + unsigned short baseAddr=chanOffs[i]|opOffs[j]; + immWrite(baseAddr+ADDR_SL_RR,0x0f); + immWrite(baseAddr+ADDR_TL,0x7f); + oldWrites[baseAddr+ADDR_SL_RR]=-1; + oldWrites[baseAddr+ADDR_TL]=-1; + //rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4)); + } + } immWrite(0x28,0x00|konOffs[i]); + if (chan[i].hardReset && chan[i].keyOn) { + for (int j=0; j<4; j++) { + unsigned short baseAddr=chanOffs[i]|opOffs[j]; + for (int k=0; k<100; k++) { + immWrite(baseAddr+ADDR_SL_RR,0x0f); + } + } + } chan[i].keyOff=false; } } @@ -993,6 +1014,9 @@ int DivPlatformYM2610B::dispatch(DivCommand c) { } break; } + case DIV_CMD_FM_HARD_RESET: + chan[c.chan].hardReset=c.value; + break; case DIV_ALWAYS_SET_VOLUME: return 0; break; From 2e6193706a49240b87e14e74c1aa652c9f56769f Mon Sep 17 00:00:00 2001 From: cam900 Date: Sun, 10 Apr 2022 17:26:50 +0900 Subject: [PATCH 46/76] Fix value fill --- src/engine/instrument.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/engine/instrument.h b/src/engine/instrument.h index 6d79f99f..c22f0a95 100644 --- a/src/engine/instrument.h +++ b/src/engine/instrument.h @@ -163,13 +163,14 @@ struct DivInstrumentMacro { signed char rel; DivInstrumentMacro(String n, int h=~0, bool initOpen=false): name(n), - val{0}, height(h), mode(0), open(initOpen), len(0), loop(-1), - rel(-1) {} + rel(-1) { + memset(val,0,256*sizeof(int)); + } }; struct DivInstrumentSTD { From 518841c17ecd49968622307cf1fb2e62a5d035b5 Mon Sep 17 00:00:00 2001 From: cam900 Date: Sun, 10 Apr 2022 18:36:04 +0900 Subject: [PATCH 47/76] Fix FM layout in "Compact" mode, Prepare for per-operator on/off control on FM (possibly controllable with phase reset macro?) --- src/engine/instrument.h | 1 + src/gui/insEdit.cpp | 27 +++++++++++++++++---------- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/engine/instrument.h b/src/engine/instrument.h index c22f0a95..b292b536 100644 --- a/src/engine/instrument.h +++ b/src/engine/instrument.h @@ -81,6 +81,7 @@ struct DivInstrumentFM { unsigned char am, ar, dr, mult, rr, sl, tl, dt2, rs, dt, d2r, ssgEnv; unsigned char dam, dvb, egt, ksl, sus, vib, ws, ksr; // YMU759/OPL/OPZ Operator(): + enable(false), am(0), ar(0), dr(0), diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index b9180022..94b9fa97 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -109,6 +109,10 @@ enum FMParams { #define FM_NAME(x) fmParamNames[settings.fmNames][x] #define FM_SHORT_NAME(x) fmParamShortNames[settings.fmNames][x] +const char* fmOperatorBits[5]={ + "op1", "op3", "op2", "op4", NULL +}; + const char* c64ShapeBits[5]={ "triangle", "saw", "pulse", "noise", NULL }; @@ -1846,8 +1850,6 @@ void FurnaceGUI::drawInsEdit() { op.am=amOn; } - ImGui::SameLine(); - int maxTl=127; if (ins->type==DIV_INS_OPLL) { if (i==1) { @@ -1867,6 +1869,7 @@ void FurnaceGUI::drawInsEdit() { bool susOn=op.sus; // don't you make fun of this one unsigned char ssgEnv=op.ssgEnv&7; if (ins->type!=DIV_INS_OPL && ins->type!=DIV_INS_OPZ) { + ImGui::SameLine(); if (ImGui::Checkbox((ins->type==DIV_INS_OPLL)?FM_NAME(FM_EGS):"SSG On",&ssgOn)) { PARAMETER op.ssgEnv=(op.ssgEnv&7)|(ssgOn<<3); } @@ -1878,6 +1881,7 @@ void FurnaceGUI::drawInsEdit() { } if (ins->type==DIV_INS_OPL) { + ImGui::SameLine(); if (ImGui::Checkbox(FM_NAME(FM_SUS),&susOn)) { PARAMETER op.sus=susOn; } @@ -1995,14 +1999,16 @@ void FurnaceGUI::drawInsEdit() { ImGui::TableNextColumn(); ImGui::Text("%s",FM_NAME(FM_DT2)); - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (CWSliderScalar("##SSG",ImGuiDataType_U8,&ssgEnv,&_ZERO,&_SEVEN,ssgEnvTypes[ssgEnv])) { PARAMETER - op.ssgEnv=(op.ssgEnv&8)|(ssgEnv&7); - } rightClickable - ImGui::TableNextColumn(); - ImGui::Text("%s",FM_NAME(FM_SSG)); + if (ins->type==DIV_INS_FM) { // OPN only + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (CWSliderScalar("##SSG",ImGuiDataType_U8,&ssgEnv,&_ZERO,&_SEVEN,ssgEnvTypes[ssgEnv])) { PARAMETER + op.ssgEnv=(op.ssgEnv&8)|(ssgEnv&7); + } rightClickable + ImGui::TableNextColumn(); + ImGui::Text("%s",FM_NAME(FM_SSG)); + } } if (ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPZ) { @@ -2066,6 +2072,7 @@ void FurnaceGUI::drawInsEdit() { NORMAL_MACRO(ins->std.ex2Macro,0,127,"ex2","PM Depth",128,ins->std.ex2Macro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[7],0,127,NULL,false); NORMAL_MACRO(ins->std.ex3Macro,0,255,"ex3","LFO Speed",128,ins->std.ex3Macro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[8],0,255,NULL,false); NORMAL_MACRO(ins->std.waveMacro,0,3,"wave","LFO Shape",48,ins->std.waveMacro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_WAVE],mmlString[9],0,3,¯oLFOWaves,false); + NORMAL_MACRO(ins->std.phaseResetMacro,0,4,"phaseReset","Operator On/Off",128,ins->std.phaseResetMacro.open,true,fmOperatorBits,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[10],0,4,NULL,false); } MACRO_END; ImGui::EndTabItem(); From 075ec9b6de94fa66196ff8eaa5452b797a76a123 Mon Sep 17 00:00:00 2001 From: cam900 Date: Sun, 10 Apr 2022 18:38:48 +0900 Subject: [PATCH 48/76] Read and Write this --- src/engine/instrument.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/engine/instrument.cpp b/src/engine/instrument.cpp index 1d8dbe7c..b9046c6f 100644 --- a/src/engine/instrument.cpp +++ b/src/engine/instrument.cpp @@ -70,6 +70,7 @@ void DivInstrument::putInsData(SafeWriter* w) { for (int j=0; j<4; j++) { DivInstrumentFM::Operator& op=fm.op[j]; + w->writeC(op.enable?1:0); w->writeC(op.am); w->writeC(op.ar); w->writeC(op.dr); @@ -631,6 +632,9 @@ DivDataErrors DivInstrument::readInsData(SafeReader& reader, short version) { for (int j=0; j<4; j++) { DivInstrumentFM::Operator& op=fm.op[j]; + if (istest) { + op.enable=reader.readC(); + } op.am=reader.readC(); op.ar=reader.readC(); op.dr=reader.readC(); From 78b88d61ceb2d67a12787d96e4bc608385e6804b Mon Sep 17 00:00:00 2001 From: cam900 Date: Sun, 10 Apr 2022 18:45:55 +0900 Subject: [PATCH 49/76] Fix format breaking --- src/engine/instrument.cpp | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/engine/instrument.cpp b/src/engine/instrument.cpp index b9046c6f..d39e9c69 100644 --- a/src/engine/instrument.cpp +++ b/src/engine/instrument.cpp @@ -70,7 +70,6 @@ void DivInstrument::putInsData(SafeWriter* w) { for (int j=0; j<4; j++) { DivInstrumentFM::Operator& op=fm.op[j]; - w->writeC(op.enable?1:0); w->writeC(op.am); w->writeC(op.ar); w->writeC(op.dr); @@ -566,6 +565,12 @@ void DivInstrument::putInsData(SafeWriter* w) { w->writeC(ws.param2); w->writeC(ws.param3); w->writeC(ws.param4); + + // FM per-operator enable + for (int j=0; j<4; j++) { + DivInstrumentFM::Operator& op=fm.op[j]; + w->writeC(op.enable?1:0); + } } DivDataErrors DivInstrument::readMacroData(DivInstrumentMacro& m, SafeReader& reader, short version) { @@ -632,9 +637,6 @@ DivDataErrors DivInstrument::readInsData(SafeReader& reader, short version) { for (int j=0; j<4; j++) { DivInstrumentFM::Operator& op=fm.op[j]; - if (istest) { - op.enable=reader.readC(); - } op.am=reader.readC(); op.ar=reader.readC(); op.dr=reader.readC(); @@ -1260,6 +1262,14 @@ DivDataErrors DivInstrument::readInsData(SafeReader& reader, short version) { ws.param3=reader.readC(); ws.param4=reader.readC(); } + + // FM per-operator enable + if (istest) { + for (int j=0; j<4; j++) { + DivInstrumentFM::Operator& op=fm.op[j]; + op.enable=reader.readC(); + } + } return DIV_DATA_SUCCESS; } From 9a6127e4c1ede977c2fb03e5f0e2f370c5362639 Mon Sep 17 00:00:00 2001 From: cam900 Date: Sun, 10 Apr 2022 18:47:32 +0900 Subject: [PATCH 50/76] Change macro --- src/gui/insEdit.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 94b9fa97..685160b7 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -2072,7 +2072,7 @@ void FurnaceGUI::drawInsEdit() { NORMAL_MACRO(ins->std.ex2Macro,0,127,"ex2","PM Depth",128,ins->std.ex2Macro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[7],0,127,NULL,false); NORMAL_MACRO(ins->std.ex3Macro,0,255,"ex3","LFO Speed",128,ins->std.ex3Macro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[8],0,255,NULL,false); NORMAL_MACRO(ins->std.waveMacro,0,3,"wave","LFO Shape",48,ins->std.waveMacro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_WAVE],mmlString[9],0,3,¯oLFOWaves,false); - NORMAL_MACRO(ins->std.phaseResetMacro,0,4,"phaseReset","Operator On/Off",128,ins->std.phaseResetMacro.open,true,fmOperatorBits,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[10],0,4,NULL,false); + NORMAL_MACRO(ins->std.ex4Macro,0,4,"ex4","Operator On/Off",128,ins->std.ex4Macro.open,true,fmOperatorBits,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[10],0,4,NULL,false); } MACRO_END; ImGui::EndTabItem(); From e6d74766ca6af5ffc17e1f19030d468716b30f92 Mon Sep 17 00:00:00 2001 From: cam900 Date: Sun, 10 Apr 2022 20:22:49 +0900 Subject: [PATCH 51/76] Add support of N163 demultiplexed output so, there's to way for reduce N163 noises: reduce channel limit and demultiplex * channel limit is runtime changeable and it makes some usable effects with disable demultiplex * demultiplex is used for "non-ear destroyable" emulators, but less hardware accurate. (when LPF and RF filter is not considered) Furnace support both after this, You can choose output behavior via configuration flag. --- src/engine/platform/n163.cpp | 5 ++++- src/engine/platform/n163.h | 1 + src/engine/platform/sound/n163/n163.cpp | 27 +++++++++++++++++++++++-- src/engine/platform/sound/n163/n163.hpp | 4 ++++ src/gui/sysConf.cpp | 5 +++++ 5 files changed, 39 insertions(+), 3 deletions(-) diff --git a/src/engine/platform/n163.cpp b/src/engine/platform/n163.cpp index 2800fad1..a61f95f8 100644 --- a/src/engine/platform/n163.cpp +++ b/src/engine/platform/n163.cpp @@ -156,7 +156,7 @@ const char* DivPlatformN163::getEffectName(unsigned char effect) { void DivPlatformN163::acquire(short* bufL, short* bufR, size_t start, size_t len) { for (size_t i=start; i32767) out=32767; if (out<-32768) out=-32768; bufL[i]=bufR[i]=out; @@ -607,6 +607,7 @@ void DivPlatformN163::reset() { memset(regPool,0,128); n163.set_disable(false); + n163.set_multiplex(multiplex); chanMax=initChanMax; loadWave=-1; loadPos=0; @@ -636,8 +637,10 @@ void DivPlatformN163::setFlags(unsigned int flags) { break; } initChanMax=chanMax=(flags>>4)&7; + multiplex=((flags>>7)&1)?false:true; // not accurate in real hardware chipClock=rate; rate/=15; + n163.set_multiplex(multiplex); rWrite(0x7f,initChanMax<<4); } diff --git a/src/engine/platform/n163.h b/src/engine/platform/n163.h index 4bc5cc63..70f842ad 100644 --- a/src/engine/platform/n163.h +++ b/src/engine/platform/n163.h @@ -75,6 +75,7 @@ class DivPlatformN163: public DivDispatch { unsigned char chanMax; short loadWave, loadPos, loadLen; unsigned char loadMode; + bool multiplex; n163_core n163; unsigned char regPool[128]; diff --git a/src/engine/platform/sound/n163/n163.cpp b/src/engine/platform/sound/n163/n163.cpp index 192189d9..b18f146b 100644 --- a/src/engine/platform/sound/n163/n163.cpp +++ b/src/engine/platform/sound/n163/n163.cpp @@ -58,16 +58,27 @@ Frequency formula: Frequency: Pitch input * ((Input clock * 15 * Number of activated voices) / 65536) + + There's to way for reduce N163 noises: reduce channel limit and demultiplex + - Channel limit is runtime changeable and it makes some usable effects. + - Demultiplex is used for "non-ear destroyable" emulators, but less hardware accurate. (when LPF and RF filter is not considered) + This core is support both, You can choose output behavior + */ #include "n163.hpp" void n163_core::tick() { - m_out = 0; + if (m_multiplex) + m_out = 0; // 0xe000-0xe7ff Disable sound bits (bit 6, bit 0 to 5 are CPU ROM Bank 0x8000-0x9fff select.) if (m_disable) + { + if (!m_multiplex) + m_out = 0; return; + } // tick per each clock const u32 freq = m_ram[m_voice_cycle + 0] | (u32(m_ram[m_voice_cycle + 2]) << 8) | (bitfield(m_ram[m_voice_cycle + 4], 0, 2) << 16); // 18 bit frequency @@ -88,22 +99,34 @@ void n163_core::tick() m_ram[m_voice_cycle + 5] = bitfield(accum, 16, 8); // update voice cycle + bool flush = m_multiplex ? true : false; m_voice_cycle -= 0x8; if (m_voice_cycle < (0x78 - (bitfield(m_ram[0x7f], 4, 3) << 3))) + { + if (!m_multiplex) + flush = true; m_voice_cycle = 0x78; + } // output 4 bit waveform and volume, multiplexed - m_out = wave * volume; + m_acc += wave * volume; + if (flush) + { + m_out = m_acc / (m_multiplex ? 1 : (bitfield(m_ram[0x7f], 4, 3) + 1)); + m_acc = 0; + } } void n163_core::reset() { // reset this chip m_disable = false; + m_multiplex = true; std::fill(std::begin(m_ram), std::end(m_ram), 0); m_voice_cycle = 0x78; m_addr_latch.reset(); m_out = 0; + m_acc = 0; } // accessor diff --git a/src/engine/platform/sound/n163/n163.hpp b/src/engine/platform/sound/n163/n163.hpp index b97de9ae..a3182757 100644 --- a/src/engine/platform/sound/n163/n163.hpp +++ b/src/engine/platform/sound/n163/n163.hpp @@ -48,6 +48,7 @@ public: // register pool u8 reg(u8 addr) { return m_ram[addr & 0x7f]; } + void set_multiplex(bool multiplex = true) { m_multiplex = multiplex; } private: // Address latch @@ -73,6 +74,9 @@ private: u8 m_voice_cycle = 0x78; // Voice cycle for processing addr_latch_t m_addr_latch; // address latch s16 m_out = 0; // output + // demultiplex related + bool m_multiplex = true; // multiplex flag, but less noisy = inaccurate! + s16 m_acc = 0; // accumulated output }; #endif diff --git a/src/gui/sysConf.cpp b/src/gui/sysConf.cpp index 8ecf7c07..5b2aa658 100644 --- a/src/gui/sysConf.cpp +++ b/src/gui/sysConf.cpp @@ -372,6 +372,11 @@ void FurnaceGUI::drawSysConf(int i) { e->setSysFlags(i,(flags & ~(7 << 4)) | (((initialChannelLimit-1) & 7) << 4),restart); updateWindowTitle(); } rightClickable + bool n163Multiplex=flags&128; + if (ImGui::Checkbox("Disable Multiplexed Output",&n163Multiplex)) { + e->setSysFlags(i,(flags&(~128))|(n163Multiplex<<7),restart); + updateWindowTitle(); + } break; } case DIV_SYSTEM_GB: From 86b523a83ebccde32659bfc924ec18625d21ca5d Mon Sep 17 00:00:00 2001 From: cam900 Date: Sun, 10 Apr 2022 20:24:31 +0900 Subject: [PATCH 52/76] Revert unnecessary changes --- src/engine/platform/n163.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/platform/n163.cpp b/src/engine/platform/n163.cpp index a61f95f8..25be01b1 100644 --- a/src/engine/platform/n163.cpp +++ b/src/engine/platform/n163.cpp @@ -156,7 +156,7 @@ const char* DivPlatformN163::getEffectName(unsigned char effect) { void DivPlatformN163::acquire(short* bufL, short* bufR, size_t start, size_t len) { for (size_t i=start; i32767) out=32767; if (out<-32768) out=-32768; bufL[i]=bufR[i]=out; From 62fe2433ce166784f360b156c094fe3908e0012b Mon Sep 17 00:00:00 2001 From: Mahbod-Karamoozian <78406810+MAHBOD-85@users.noreply.github.com> Date: Sun, 10 Apr 2022 18:33:35 +0430 Subject: [PATCH 53/76] Demo Song: YKY demo 100hz update (#336) 800hz was unnecessary --- demos/yky.fur | Bin 17704 -> 34188 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/demos/yky.fur b/demos/yky.fur index 106ed1004b630610b60df810d9676b16f61288d1..fc8188c1901e0cac8905598322040b66f26b6f29 100644 GIT binary patch literal 34188 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 literal 17704 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 From e3650906a008d5ac2a99b4eba4c5a16d1499b426 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 10 Apr 2022 13:49:06 -0500 Subject: [PATCH 54/76] Revert "Demo Song: YKY demo 100hz update (#336)" This reverts commit 62fe2433ce166784f360b156c094fe3908e0012b. --- demos/yky.fur | Bin 34188 -> 17704 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/demos/yky.fur b/demos/yky.fur index fc8188c1901e0cac8905598322040b66f26b6f29..106ed1004b630610b60df810d9676b16f61288d1 100644 GIT binary patch literal 17704 zcmd3NRZyHkv?fmQ5ZnWV;O_2_0KwgLa0_mO2N>Ml-EFYo5NsHNy9R>04Gx>T_wL=Q zecP&i*y{7rU8n!<`o7bDpFVxsJLfb2)!lH>XD>j5Ba{RarCTS-wB9^fM#~_HZv1^(@1pEsE1$bcqgzrly}|e2pRHAzmM4}^#xB1KHc|+-@;A{{8^o4;0d?cSVfdaq z0(#H=aDKfXfWjeBzyC{i0ndHC(S6q&*csTFPDc6ocvkQK8m%(#|8U42@Zy!X(y&gf zVNqrr?|)Mmf9X7T+!Et+AN&L*-5F=><0k=N0R5DX76WXJZL`=PkGbQ4fV)`}|Ho+F z-qxo>_C*oc!+P(7`-HTL_-$;tXLh-Z#VJw##>?DFr5A7Y`DVAD#RO4LtbE`OhDu=N z-t^@8>vMWO@bM0KeQlx_diL9YN_QCH^X>R|l!v&<3==F;H@`H_4xeFnLel28xs1Rn zo;~q-((7;`i!<445Y})PFq?C8)eK6tZVT=09LX@E;sA_C#Eb#wGGOtf&HJu5*Cm{V zn|y$meA4DiJIU-}cki*xythvq^BL!Ad17%}g&+67NU+Kiu%j!V zV83-L2R-yr_cTqkZ(C2S$ zo(@}6K0tK-v3qO+JYqJfUdGfs%IBPy?B)NtKpdDvSrw2*u#vM39KDjgPLfv5wY8E< zW^SywT%+g25?T~7zT~N224@mz*SkJv{^@9iUvJzHUNBr`yIo8oJnLwZ7qWzwP52YG zb$r-g0UXAqI@ENu8XeU${%NfvbXsAJbCEArOIB!)CD_Q@1~wAJJ|<~Y3(Y2HZoeAp zoSm1okDvvPe4^)yc;I34Rp1z!SpN~piBdIQGt%;5@w;IQ5}8h_o0gD{U>%ns$HTWM zHv(ZDT()+^vX2v~;-^LWP>;G_cgZ?&ZnE`%Aj;omlMMA{>n^~|e+@Ia4f}1+LuWT8 z-H|`k#n`5AcKH9^{njpmmd-oKySnK9+AbHsV_|Y=>{*>{u-ubxG0}3W9>{82J(1nD zNMdrBz?scgH{a?$l4ZYI`uaUw_z&;D1{e1A#=RBK%HFcD)lcYmFgofrw}4XVVTYCW zf$sm(Rruh%?AqdT?X3QXx5ozZ^!`k9u8J*E4iWz>lOTwBjlZq0`@e=WBKp&+zM(?D z_Ap(MK9DQA=f)L{-2{N(5$s#(Bdmpuf$c+d$`n(za*918U5+$Kt6jRx36$Nre=5gL0@VkZ5T*X17mv`5%}=k}k}lrVeA zZ9yOu%H3Be)H&gdXV$Wsw2A(^t?IYpM1O$zi%0l(f`7C=d&CZU?R&pa*NJC%z5oaO zHs0c{y~>VP(H7gvUUqM>_8-fxU)svn-}b=gpEsK)7ITm7+k1`-RfHGQU0*)eZ4TTb z8@|CWTDt}eFY!{wZ>@yeS2rFDYZG^RhPGg5VvC)Rc+@xAOP=v~YQp#ovt1lrR%(Y@ zARW52>iaiC(YG|?F-F|#JBG}Pwq568j>OWziZ!=Qd9=Y?$s%?+0S zg;r5Tn**oVTM5bDwJdAB5dzO_^~!$i4~*pGVj;_Hv#+bxzQxlnGkbL;o^Fb3PlEqt z$ZYyw+Qgk6nJKscv%>^urT^Q&Eu}yE{h#Cl(w%vGm^)=?@+!38)zG0aP6}RNp>X$o z-(tzu*w39fhspqOr{}{2o9p?$uA5`$oXJ>;UngvRX(snHT5eqZ7k@LW@M|VZNB>i4 zvyJ%mX@|m{G~=1;a9ifw<#gaQzuWp9%geU>pSJ20Bn6c! zfA6;EQffc5wuW#AjN@HwReVVmOElGb+G;Q*=z_^e$vw(QY5xPqeRJ)@e`_fHbS9EJ zY3W??E^aZ*woa?HGns1ArlXhl__$R{;zVbkZ&9QcsD9{G`m~q!-!`_4L{^<^YVl!K z*s%c@(*Frf^XT;!i?8mBD?0_>J@m#x6W}HSx#8%$Vb;^_vrwnX=gJmrHw*e-(9=^r z-OCG{*NfiH*E=rXPfP|5l80slbp4P80+TIzOa{xtvVutXrOQU#vkBe$b9nc^F>m1D z*?y?RU9%tV20XiG@Nt9AJEuNV4SZ?-g*v1bu2Ma9Yo}qW@GTfku_EFdyYG?ADqAf6 zj{{kyv@o|{H@0CxXp#r?7qhl(+xuO%zs`+kqW*F_DFWm>nQ+{$h{s5aQIp zAhWJW#{Prd``l1#bRH`4Ut)1ycsA>yJ-(dgF_RSxcsBk*ekAL{P ziFd;~!mL>(a%0b>+qsz>?x!Kq`7}4Gm{t(ISVRoRzCfZqagd)yNXxe=W4XZMfu7pW zFJ&mCz1RZvxXSY3$I)f*nkRkdzJ2nMBE%6Fe-Y&83nuNLl}G~P66ewfy@>9oJg3CP zXuTuTIucUcVLd3ko)Yc`;jU@L0dadv!Fny*Y?qutd0!ei{m+K^jSAES^VZGIc2h{bQ;$r{og*uQ@nAQ=_qo!&>2%QM3=+A*)yk7sff`bTR6UmGh`#d$6(eCh$8wB!f zA#OxD=QEo-?fcGlK!ED+m}K(Z3wvw(IiP^fb|xOSLwXq^=%{S>x_{Y;dz$6ai=vu@ zD&5X9#!@P*(bV^P-PbmLDU8!QxXnGlQ}^KW$s$KX*jGG$LzuIgdh7f9_YMg8j(j+9 z_Nzf{4mbO#VI($qg8~+DNO#5GXe%UpDEgK{z@ z*obM=0c9nRoGS%f)PsFSh{Hm`u6J1`SvnKZ_de?xOFSO z5LoF<8SpD}N22Do!}p;~y#wA)vFY%SG4DodgWkv+d=T7LBSiI_9AC3pR29zQPFsx3K<6h5{qlhe!t-&!amuBwD)K=&=!_qL)=#m zCx(SESsS$f!De(hmneQ0j!1UK+G1N**bSWc~;9Vjg z)lca9#OShyd(b|6aG7+$^RaFMt_*#ulP*^sNuY>0La2+FrwUn_Dd^NL#vr5<*UUo6 z9@=oQ5z_OMvtE(-kVfw3M~7sc>(XnKoO6{gc)6);XGv^KgYR|^+LXwD-$pa*ww4T8 z5L>Yqa)`?-i9XL$g8;N@X9rkljxchIfwU5OjYdxXE*DA_Bw(n!fr9p+|Bd z=}G)7La-n4y_l7IHV*Ew)%p7l$2HRfz8_bPEMFUD=Fc7JD$iLg2JIx_?qML!C0xuO zZU-|C=*L%FTWl9eim2FIs3r-*3viX%NAm(WNG^unF{plu&7+T^ zO60i%30F$~;5ZgIBLFoc5PN*-(2O^2IjwP04dJ=l1}5fl`PNZ+*-RKNFl~OqREn&V zd(8F3*Fm)NnsFxYB0%}f1g}!b^Xs$Cq}3kc)X(Y*HmbQx8v=^Nw9|y}snTiTma1D* z7KkGKYb!_r>`B^BfTfSvzKx@xNGKg$AJl4qW0z`HLh}{KILtP3K$leZ{jf^`DyF#N zB$1U?ZQpwm<$L>e)#D2xTczwb50Wkya&h^OZX+#c!yNVGF?u0t?U1^DsEuAt-$6Jr zvk7@7-8z4jmhZcJ@-$vR)S`T;EXsu+xp?S3^+IH*@|Y<*!&)ezf2+ydIRSs%wk;LM zSu*m6Va)N1W(tm)Us``$6u&I|EnpD;)Y-?(> zwJ4}YSdDQt)Pf{$B>YD#Nk%N=M`Wzx0oxuYp8CV^{Tx5?+gZGDfDRPt$ZM8%ju&6> zKCtPx0uL|Lrjsp*Yso^l!#(>~J{@Vu-=GzneRW6kg(mpNRrO-J66kbBYH#Xqm7%+h zC5OqB^p6CuN{(#>-51DLE3gkAB0H_zcIeoDD;Eg-veIaxf^DNbm#r2t*sVV+Mn4E${|5KG{@7UStLmd_Ff`!#)naomjU%RcFmuE|7X%h%jMTOXToSV_rs4>lF+Re5nVk8)nc4G{Jj) z@m$K-`Q|OdI5Wv?5~oiq9q>S5WNJTW_5gx)br*H1tcf!{wQpuNo>JqA;_VFXF~{78;X>c2OlX3 z=;pZq&9nXlwHN5v|B9^m>-Bgu{$UGZ8vnI34Cq#7$*PfYVb@LKG2FK6Z0I@B-cwq} z>no0~e;4^7Ad7c|5`W_4J&~)kpjcF`J;Jtu9~M^hF)eZOj^FO`2=ZygPK0ipA&%{B z^MjcxE#@c!IU)8i`N;_KWjnY2yJAZr;-5 z7LFppIFo6B>#fBbv83Q4HVN&%#9SIs6<-V}yDJYMyoB-v7U12>WPertul z{_aOHZ!Qz(<<#z@1G=!wSoiBk5@~is_P-I28TPB0XKwEEpfR3kOOKTXu+<=G)WZ;+X@$Sa%1xA99-q;a!gMdX<9#ZQ|%lVN?l*(3f> zl;gkj-O85{s!x>-nemwqe(<{YiQt@Hf2i5TeL$g``i88}j&8N9V|vP}u5=vfKkt^{ zU-vq%8{NU@OXm!qd#C(rQL|gH&EJaT(Ek&b;R8pxO-npqod@ejv`HY4V7_OlbGuKe z%#f~oj(_hi*Q&i8#Dw{hP_Mn*9b-^4au?IByY1_HG|_N$U~n>|RUc_+xL}0#IG(be zU#K9XuQhZf;6DW*+P#&5d(yvVbQ7-W?VJLTdkbQ)P$K29Bl7z}C;t@o2KN$ObfHc; zhL`}^S+*#y#>az~=Rr8THoRStBt|H8*cMt2sB&Ec6B!rWB?r)UhkoEhBq=8q-vpOW zmgN2ejqXB>4HjaO=$`f7$ex}mOa!>y6vf|fu8W#op~Gm_eO#_axBHos%NUCQ%g~`R}YcHn1ai0d5L3B^drC;cpfuS8k zG%fVC8^pp<<&H}Wvjgm0Ve4#-ML;R`LK~LsH1QzBOOn^0FD?o9WBZ@GrbQ-%FK7~Lp~j=Q%utPjS>+4OD0S(bE5Pr9MbSOMts|eC z0KyEMqD=)^KAX20^UFWZWM|;upYlOIaua!QbmEvIjtIyDLHrupX2dG9!uH958*u&! z`Pzc60`Y)3%q5Y6+2VVc@r{zxD{=)8&dpKd=8#687cot8=xA7C-&~fZ8a%wbU|U|) zD7`%`Ah$2HQPslBhLPRV-wpC=Dy1kt)HXcg@OGmTxVE}3@`3N&L@HqgAm;Vr-B%`r z;V|&c#8#`c&T!NLZdO8pt>{^`8D4osSdw}jnL$qBG^DuDKlnEYqKDKH`53wgAZt!L zKm2PulEi(alS$Q_#n|*gi8|E0lUeB; zct=(A6Fcp%qU{gV7l1^!y&#HJ8mc@5lN@dECnk*FakyZ}D@7`St>2JfP^F4%A@yM| zuFv+3@nQay`Kj6`4g{!Wbe$f^%PUmH1a)KkfDr+kO(Ug%!dnDojf2o#3aE&xZ_QlP zhAB{k9N~x(;WYfjB};@_5<6+(Bo9BP2ED@kC?3A)Xg5N?7-UhDWGz=od~U^(uZHkD z3fFU3E)G#;{=OAK#FJ<%9w84+!Uyvu(fAyJ=w?l*)QqIrcJR6c_Wg@@xcfNDg<|E( z%tphTUuwcau;{^#*3DeWmqL|RgvMh;&vAl9R$N$A`oGf+VZ+e$B0%E$t zNprJ`4NZWZOT<%7{TxY6O|gRuv*u*4tGHoy9)Ua|ZRvkDDVARb0bHGWPU@v($63E% zb$5Q3ul8hW3WVntL&ePNe@ae@#q-{zBNayxeB>zzAP>~BPd(HAb&ymPh@~&NnKJK! zqGFP?nS3x&%&?X{*2e`dAv#o0<*>&60R)!?rPtKFSNt6oWxgS51iE=@>E7qWqB6(7J zMS>82FmpCn8PqX~g*yNFi0iP(Zkbq8ZLRti_(epZ%KL*)PM&9L*MeDXCk5zpvR9RB z{Rfd2a%NO+S-OK_3AHlPp`(xjBC8T1 zMvWSLDqqBeEK26kX^E``dA2^+21qXRkgUiLL>`K5om<)5g|;h)Y{C$P(>ZBZ61=2< zo>G(Im`95R5#%iZSYm@(h;Rv+4cbcLkQOK>MhK?SrkxpN*&nxSD1oCDbjzp9XE61{ z-xn85K0>|N;o{@tMr~cV^J!5+_Kfa$6xxL-~pX`+tQ< z)qr7LEjX>SVndniqu<5${+cLI@7RA_wc5sw*Nz}p?IPb)9U)*Q6s$SX5f(6&f(7Va z&awrknHx^Vz^;Gro(#UY@0c z4VE-0k37tti}g?rR;fB4tpb&f-@@j@ee?;PmvW=b7Fyu%UAkT|C2&e(CgfgVT+v1O*Fm204>*u8=%)NUerO>nBv( zvVJsu&Va#`ZJM7N;+FWZxK|PNC!SLN*rt42{}^9{GZlfaQ%XcME2Q%ENSk~qLJw15 zIoNgRk3E5h0plv2yuBi)fRBVA>t49j3|ozfRm_`_PpspxfFOz73ds&t!h}+7Qf%h# zyHE=dGTHKZj1OzNSCgdYTo4P+quG86vL#y#xhjL5b3(b=!5scy#uY)9bqNRkB8$2j zbU?Ji$Kcd0HVg|KhT^Y&XO5Rv<#q<<_i2s4lwxwjtq)+rd?=(5DT235k8_Mld|%Bo%*IqT84TuWSNkwlCCgiySf#7}c0|5P1&w1U5y6K@ zO)nI$;hn~@?W!7Rrg9cdI##v4V-OQyqViRJj7v&AUP=Q?cagTJcoG#-$+N#yeLr~r z>^gSF1YRomBGsc^t?13hHqLA!ifJ=ZH2JIDG0(vk;G$>Hue2vQ^~_*tLj|67)hmHr z@7`C2$_CN{J>k+lGF}u$++dOV4JG!MWR($$Y2yWX%vgGA-ni zo@q-K2w#gvk#HQ4Fs)Ig&ol?hEgbdi6cA_Y)<3pf*S1J;m}ruI_`TC4a$jelH;H#I zhOx9<;Y)s{Q)qfJy#mdmS}@K*@S^-spPS4wZL<8SUbJE(E7)SjPtaGFy?ov#+Mk+}3P_K!2_{m|#9`09%W zAWOvlD@1_EBIaYN2l!t6yMben+&z{-t0Xe8P=j(@>pH0`BLln@bP~m<_gU_ip6*J5 zb_U(3=|qonp(-ncb2`==txC==6QIR59=AD7gi&cnBfZ@CxwbU@ww6eB$y2qyW-`dK zk0D zKuYsDke3N#1SS}PG?r1&$Q|j)2QBvrBM>fc9i0(r{`Wf*(i5c3oaYp7S-~_sww6(xg&oKrdB-HC6q)jtHYHG2=)ib!1pf9shM%lj@32A zO~gH|W=h0g*&;TTjl{Tqx3hr!_KNm;OwDfMHq}#pkxOIfTl-#iQdv-C65Hg!spS+W z$XiTV{u6R;nf)WjA!~7LVM(yxELL<+lXfWQr+9p5xvL~^nZ04R_a|gM?7NlB2TUvP zSO9m4p;^2smF6aivL~N`wsl(5Hq_8dz;y^1VI7lorq^qjPwqV5$f$HvKmS=L5A9HtFfegrg4#AeEupuv|Z|Ti#Bb(h>=aup))~ zh2WkD@1H(AFK;uY6k?T8W}g(gYm+fapPc6h%^y=cmadK&^mSY2QVmO5jI;w)yK`24 zIXRspOM26lT`6}8d}3({I!aKG-mDm1Pu=g_Z+llY%sixS1(`VymV8s}#!#20<76L! z_+qt~Ovu$YDUM9KoRXJ$L!N-^VWp1l>T55U(Ye-j^M|}Hm`Faa?D?wquc?>D*m?`bx~-;N8ky(Vg0s z6aM@9{^z!S(u|<_yPr)JYZ`r^H9IR}InE70-+QfAIu%-_(TMWe1|n~O!xmj1v|`9d zOKSG@-C$rR1+Xx;w6uH1H0CHzA?(^*VvxMhB+opL57r|ub9Nf5 zeYM1b9%F-7KGR8v&EV36;4Tvv!Qlq=gnV|SAvZ`R^eXbFR(&b=xsBi0|~J@>E&rTwZx zpIV*a44Om_!u=|`QvFb}JbtKHX-#Em%y2HG3t*<*0^;Xj+wH%DLVgg4KB8Xh1l`N` z{We>()v2wf@;Z!gM)2~7(`jRAA~t1Cl9xVJKK~V;snvJAS_L}72x>ObR>k=EglxG( zaea62CeSdDV}^GyxH4_DCGcHNlXJmLHJgu_$HzJ4EXS<}cPKv|t<-|MAcb zcLJp1`cCY=91+d=>RY?Vo3T515RlwN5fciA#ElMm%@3&J^Au}|*BENa5Ra-^zJ}RN zY^sWg8*ncni@H!=d1H2^#9E7)iDBgJY@o0MZn%b>lMSa8BRuJY9)ncDECH@Ft-2kMa+@3%y(>Hk)8> zT0(dcG7fR=%sf8vA1SKby`dWhLy3RW0H^x}@%pHBy^GIr4>UF{$U8A(zI1KeM3;=v zsxOz5zN1{+s<9c=0aIQDye46=752$;4H9d)Df6n%8U!{e2!4HNO8t;Z;r0rJvSTTZ zdqr?swQRPNt#)yHV1#*;k-irj6P{6g?+r4sTF3fY?QA)5@0JtNa7Xb$_6|~NBTItQ zXd3++{0-&8>*up?=JS2yeX@uLRH>(9CtE(vsGDs?`QQ5Vdb|hO4-a&Hw4jN;hw&2g z%X5}#Tl^vttm?v)#5?1CLjpcoTw71=)q+I1R=vlb)l+*YiaaPEdok?SLm@k;U{cJ2 zJA~^`V5+-cw~UAn7GKD`B<>}2R`LT5u90_t{bo3#LfKz5n-h|45ES+$ZP_a>*z8V- z^6M`TJ+O@zu+gpNQ<;EhAVqa?V?T2Ek|HQeRh3h!5{gtjYw^4L6I|rb3N7mme{A^P z=BZlSZwN}soRrSK1})7bF-`j#p;e#~M4ad#rK&427Z7-h!3F&C{qe!7UH-y|`abTM z*FHU(fSG2pZs>s0g@L&j$IM@`14Y{)4iV=Kfr$&%(@-co$xAhWp8@FcL4*i-BQFfF zR5j{GEhj|n2*v{IvmRum`%v<{(cK{WM9=vvF2_kv71mcT6so4)41uVdKOY*c1z_;_ zy}Rig@&7FXuj_X)L8m43mtnZ?1aqXb;%NQ4ebkz^Pl1hNQsD38M{XkUrX#T`kk}3I z{8MGw9j9j*N$+1*bxxr(evn{eFT9U+&CB1f4gsKSN{^=2(1T{Y_n2mY)_rr^cq`5e zp~%K7tKyU$G`WvlL4_0z_IzV|;_nn=6P2}f=9%gH_)PF+4WOW!S?5 z(rkz7QN+fzaQa0Ztsp(I71}ZQwf)KB2vpqpKsjN2-@m+8p;hPG8`*tV)XRf4AD56t zrnJX2Yq9P1esJ8?>gstGoqw?P9;U}ZP=tcdwLHTwyWqb}%67F`PQ-k-?GP;T4FCRRIY<563v2e*)GZ5UNvY!%0!)l^&kK^ptR7XQ&G#fldkGiFB+lAzTm67}y} z+@e_bUc9CYgHdrhmZaI-yx0>d38xjI?FAxU6Pl|VelE{BNtM-$L|_7Etj(~hY0>WI zt^4%$Tgtf$13OCM+#kWMhf3Fq$G!RJvu>(tT~>;}3rPNnU>ij0W_-H0$>9ajMFu;) zb1T_YkJ9rREL%oY48-AZBk9(W;uk?^KV($flatJ*?b9INS;JP=L-e1v=#X9s;_PaM z_+gD3K$2?TT3G`2a!n#$g_)jmKFE{#5p3yIzO$**jyAN7bv$^YH0_XDDmR*qU4BKY z+3`L73Qe?{s#_0+62lNauOzLVj{vM}jjXG^e>sEOROjE1gV z@S+eik<+KrPec@S*mfx_?ZV4!BKWS``aC3dG^Z7bW6NqK?L3J7hnC>*ygf;S*T2lF?sjrlRA#_nP&M*7%R>b+L|(@nEcB3f z)4-i_O3DSJG#R*eyNIF~x7P+FxSl09LMtTlxRjt05t_+bVU0EuPN)mxe~se) z)R#V^oK{+dc=xu)Hmda6jQ5cEwAKB}bNfZM=GH1pI=5jqZqx6(c2@xko(7!J3&R=m z2W`HheP1Z4c^0zGQmiT>=_A!;@9dQ6VXa+x`iQp!`d&AnB6c%X(OjMJBqH4hW%K#9 zQ}x>q)$lf_tDMj(PGoCa`U>?(%TL3$eKXxRV)|8k9ui(k3xN;Fvl;oBoqP|7J;ET_ zya+b8wj`L@+;(d8G861USh;)(ILMy5nhR;Ka`+w=>hN_|I|lNzQ_8ehALxneB2bna z@U*+!UATTyzq8t$wckt}u>_!7vXdQVoTj$PLfB;uy{h#VJMmO)zz)!^(hkk(klFy! z3haWf8lfc06$38#7ro)<==c#Z#3Gy^zs}u1I$t7UL+(@{KRcxFt?S~lY-D&TTAG?- zSwaI5&kj|3Li9L}Hse}-3NX3Zk2zNfsz@RQ$bFUPZEFOU7&@LloqS(_H08A`lP08& zt>sTZF2)DsaZHynUfh*ENX1-9b|BylbNxFe&JEG~38)X63$EJjsL%nHc9%|}k%abZ zb(Ob3Y1Uo$*3Wc&18>B30oHmaWU%s_ARdi|XL~@xx4L1Y`e)NZbM+eKiljDI$=2Dg zsz(T0X1m<-mbc@p#8D3?-S=^N`%H&-LRP#B;~EZXb@Qkg`PRB?@x2CMbDW}jwdsXW zu{)5{zT~)$hklsOZL+jJJqh)>CV-=CzDZi|6v4-6F7(Dv%)TdRL$S}5`bId8a&zvG z`c(fClCo<00uelz*#SYZMmM+h5IME_-62fO8UbF&J*(J|L@LT(ox7kaEN03z>L}pX zv@J%xV7w}N;ZRBz)f?Vgq45g~+qVEEE$-NR12!MFU%6OY?T$^yzekBIW#Y0bwCE+t zk&xq=Mpo&JMnzL7{jV{6V2)MIy4X&m2sv6SBO~Z@+zG7l{u`*&yyK;B{zBF?RVQkl zP4n^u%?HThBIUZ++~|0q;JZqvnAEbGyI#a=R`=guO`)7{z9%687p@0+Ob^}CLeZtT z-esqRa9;E1S&I|mp(@6~0HNBomq?Lg@`v9KHs2H(7|7^~gl;5r(;Bc|(H&npcYCoR zKX$SnelP)^{vx)7dW!dx6Bl-W8mB3-%Rn%7V)hUJ7Sv9ux$@%`l=^02nMkkBv1wRw zK=*G0NC^}~|B{_L0ZEYeSMb=vs;aeQiv^0`?kV4-)f=JJ93EGnDkQ47VH_5g_yUy@m9OS`ixXSs+#Kt zci)W{a7~V>e(@3fD5li_9-k~v;aGVpgH<)aO5{7#j#}8DEHzalY->AqcbwO@f4DW& z)@Zb3WyrHnDdtmPRYlDd`ZlV5QK*-76#qh?EqZh!HM6EPRc*yodO;hyR9Ch)lv;V6 z7_?2>_aYlU_!d^kj(O%HjzM5WnB?eExz1Aa11Es5#I6!`>QNb*)uELy@{>Mga~-5+ zA4FG&cse5!yB#bddpHujY(0gygEU79Z~ZpJsk#j}Y^NoX=Ame?d*^i=7V=@}Sr{vs zJbv4_Zrf&G;_^KB$_UiTSNT|>HZvGN&bpO$9RzypmCI`(A|C<~<=b7_SmWD>%jLu9 zIn_JxURaU?&Cd;E?dOGAC>eOl&P3pg3sJyj;p=#P^G7*1%?U&pt;k(KYrLxxS zwK@~hxmTaGAk~~Oa|1l*>f!LGMADYYZG`*3pKKsU^b0*&neDLO9J89G*J3uDyH!G= zw>fKtJk(!`ww?)s!U(3FgQ@f-YtswDVO5}~6y-%9EzXi4?@Zpj?3RewG}3AY5S3%Y=zoi$&ETvuEb~2q}Y-8cK1_Y{bUhnK8{%=Cr z#Rhy}c}~XR4ZYGfT+frsKx<-r z#||+9(~^Y0L5(JI!f9jb0`C+W;|^KQy6P&1$oh~^U-_Wsn490%!F{eG!S)??AKDOt!m3GorQTjh+# zT)tK{>r=sxCR^GB0TcKi?0?$|%x2NrL(dB>nRON|dq%rcpTTSMnwPZ_tVtEA=YlP3 ztQP3$RKl|EUXDDL<<#LgU85ULQV8N7q4J!f42cIELrcw+H_bcS$5>^nMj*Yld zw%gCOucsfc4+AfWwO*}sfycJ0FjNo#8LQeeHGXxMtqt%_$eij{eTaY-$ zM}SD?Zlp7|0}FYt2~JN8T<&cux-z z{#|yef$3TDM~d&?GPYfq>AvArLDBy?X@mT)qe<<(AUYPQ{wJ-c6w!XJ088TUu<$5Wfz-VgfsRA>-_v|tl|fG+Wf;Qhcpfx~%L;gBXQIT%Tk zP`WbxQ|V^yUCd@RvA0YIm9_(yvHw@&E3$$&lHAw%@}=(trWX=YK)YAv#(iHGCfd9; zf*kg@FyWr+zHFdbV2iSi88~$QgDi3QI@;Yn=?M?1&(MyKkIHwHrKWhS?})I))fV5uIguRf?tPFhx8jKg*b zNY044V(^r&pB^U@QDOzBEdiJVAZ6FZSu?P+#&a(&hsM$1RJaH6vCk>uTX0kKZdH@T z4In}p>p5XtAci+?ytqvz=g^glw>#-U`^!iB*$yI8iCYDuCJ4<;KGr=@#{a#}t#v0; z_oD5-cA|f$;XLn67268)({d2mf$a1Lk=>j^&7ztoSs(Y2zqvfjuz{@NP>2byDH~m1 zpYoPPwYhqVz>0DvB$O5P2NRfSxF4e)@rckxp7z2bUulT=g9@bxHt-quY`&r>Fcqwu z&oY|2@->jE0sO6eE1Z)VpqNQ*NK0bTmGB^{{pMo*UPl{%X}^oxH1H-UF;4#H^OPg1 z?<5@mdBVaLn$N=(K_+L-%uoJ;wOJC|P-W8@v9?M|H&XSUq_+so)*_(UX&j{*mb;AL z1i=;>fR*p7igC*AFabdDIn~Yucjty^YJU>{jS7K+*dlt{Pk0>C%}%?0ruOw~oHkf- zE0xk_k{-H0^%UACU)I!h&h(jT#y=W-9n-mL@-J1Rg#5zbs=4Fokl;Z4Ozea(7j^f} zdGLTxz(uCB%`*gulTEL6+oPamvfj52f67m+**X_L4P&r=Vc+`DIZ&(Vlh3CW$DzCh zkG&|g>^$74Z7;8Z+ur%!jm)(wS{E@uGoX#BoD%tUMeERCYU&|~V0cb3=jV{vpU*17 zF(72F~mw8a73qUtizD!F5@bemxG~pU4gdPIoFW4 zZ)||FQ@yE4bq?VO+E`U>%D3!t{TlV$)WzEMYj!D(p5g$#%z|07Euc&q{GI%|nOHc1 zB^_YnXf7^23g_wW!mL*-FL1%*&k^%b_|A%rsMM?k`bkpTa~mS-@g_X`8d0Jsa>-aad_m=C^X!Y%p=e1r9i`9yorxJlO{Ed{O%=sZg$wb`|xAHv8Bpz9U zsDiUlvQMZ{%EuiX{Li;tXahbPZgKd9p?sIJ$R>rh=MlWi9SH-Ar^ikm>fd#RS zN57D21fg7TlhF=ngpiS)o2|03nunipQHRZGf8%?+w&;TAE5T#_dlceegK*)AnPs)9 zL+stJ+Jnl5yC+=42&Fz{W4L{Cn2nU6eYl*dILosOJ+y=0_9oZO2_N!Q@QHfsQh0Xl ztiKmJIQYHAs*ubRuk?oG>G^daubk^l)Mv*_Kon&U5wE)1iEj3T?*9ddWuEX?EQ`4m z@zRJ!@NBMHo=hXO{e9C#r^24#IWl}4PqL=ySqVme;2?rdaEHjD8(u!9cSm_ej8eNI{)ctmyXLv&rY1AQ<@BUk+ zlh|D=AHn_`Y5$8;`2Gabtm@3ZSEGePkIfb^1rR`Z_AU>L{91 zUJemG91E^X=)C6%uVQkLJfy*<7O=q8Vs9cyPKrAhfM; zpSKGAf}z|$UHcS${+Gt;JiYj>_+)$eE7{##;Qzh6RRWzaG~PDxrrlIty#C)wTjP1& zW1vRfqlwL$#@o8aTddzv@Bat#hV}jEZR9*~`|_|8Vf*)ZzB^LNbQC z?k8a5ziOC#bleMwzH4pr%=+${^~OhmdP%rJx@zM2EM_H?{pq!BW-VXEPbCZ1^;U{Z zF7EM!87qG4vj@BG$gg{Qm=LFUHc=SlPz-qGM}2wQ37HU=qz*F*=ZJ>!qe!=-Q+vEE zD!(FP{#z>iul|2}r&l{~Ojd5Py`C7uO?wfVNiSB!Q30|E;r8b$v%sF0&gUKw>Ha@GI)*SGckgKKU+Vd9>4e^|XZvK&*C|pN&&~}U@Q*lUdhccf>gwsb zsdWFs4!6Aa`FmfT-Jg*(w*!u60()NQ8IYdB{v_D-m3!TvGUrQk(}-NYD#3kQj~~+5 z#F=dVH~;+e=b09hlLyqB2mBqlH59JZgjr-|!FWbMxDPHjKLrl=AGXQ<2S!m^C z97b=M*AC*Fm;2(q?x#dvuO!iNROzq$T>tc>epJ7&8-GsYlWxE1Z9Eh|2b=$#)Ig{H z7|uanuHFz3Ggb^s_Hfz#@`jAyayk5V#47f-zG(HT*!FV1@$))g{T=Mh&QiWGxtwBF zwu5ADjJG!*{1Uqn_;V5?w=~1~?Qq7pne1)2G+yy7y!4GAoa2E?@KT%zqWC|NpZTgN zk5F#^7F%-H-ApR}5O#8zys5G&cKbZ@hkpHjLzYsU;??NU1m{_0y-oaF`93G{AJBeh z)=Hh{y+^y!Lv z|Isk=K4j)!x^m8fDeQRaRW4#u>mA#R1~5T=5VY)fmli4W`}dm(`KIMTlVaVN<33wfd12AHfxVi?F$qy!!G~iwWZbMWyL4(4-T?m7+X{Q0T(4t5%GZcUD1Eb_?-(1Eii`h_(^opO@ELh(s2|KIF9wMm>Q337Q4*O;9Y z0XiX|=>HLj19$wb5D4J>+AnQ}T=@BiQXC@c(tqjG|2ioIb4?0irq7E_konzT=<(C_ zKi~1ww@*! zkMNL+=?vgWxX;)0`@UJ+kEFcsPt)F?vi(BCx6u8E)3gt#ZJ!!{>H1Fxzf1qc?SG-~ zCnyBpdlbUtDN4yYoIF%z`h=(M``&XuJOe=!Ki}#M5r$%(!ryy$t6h!%tM7YMfIb)c zytjXs{v;X(eLa@(Nq*|E#@3xDLnX}0fn5PdKNMrKd?EPPl_Nnd%)3%=<{ex-X z&zvWIGu{5v_MfVK+8EKKLdY;vubCcp-@ET`iT9HNVH?c$Yteyn-@ES@>;0ra*aoBh iT6Cb?_wM_}dOs-;Q@g=$0HECW?)$}h|NjAXG%()c=lrbz literal 34188 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 From c13358d96f38c8b0b61e959a905a30cdf5ee03b0 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 10 Apr 2022 15:31:32 -0500 Subject: [PATCH 55/76] part 1 --- src/engine/engine.h | 4 ++-- src/engine/instrument.h | 7 ------- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/src/engine/engine.h b/src/engine/engine.h index dd9bf25c..89f6ff73 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -42,8 +42,8 @@ #define BUSY_BEGIN_SOFT softLocked=true; isBusy.lock(); #define BUSY_END isBusy.unlock(); softLocked=false; -#define DIV_VERSION "dev80" -#define DIV_ENGINE_VERSION (80/*Test*/|0x80) +#define DIV_VERSION "dev81" +#define DIV_ENGINE_VERSION 81 // for imports #define DIV_VERSION_MOD 0xff01 diff --git a/src/engine/instrument.h b/src/engine/instrument.h index b292b536..e12da09d 100644 --- a/src/engine/instrument.h +++ b/src/engine/instrument.h @@ -417,13 +417,6 @@ struct DivInstrument { */ void putInsData(SafeWriter* w); - /** - * save the macro to a SafeWriter. - * @param m the macro. - * @param w the SafeWriter in question. - */ - void putMacroData(DivInstrumentMacro m, SafeWriter* w); - /** * read instrument data in .fui format. * @param reader the reader. From 51207e58ad8627aa6201a0bbf0a722fb1be25f20 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 10 Apr 2022 16:52:03 -0500 Subject: [PATCH 56/76] part 2 - finally --- src/engine/fileOps.cpp | 3 - src/engine/instrument.cpp | 863 ++++++++++------------------------ src/engine/instrument.h | 51 +- src/engine/macroInt.cpp | 53 +-- src/engine/macroInt.h | 26 +- src/engine/platform/tx81z.cpp | 8 - src/gui/insEdit.cpp | 44 +- 7 files changed, 283 insertions(+), 765 deletions(-) diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index 63cc1536..eb5e31e4 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -307,12 +307,9 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { if (!ins->mode) { ins->type=DIV_INS_AY; } - ins->std.dutyMacro.height=31; - ins->std.waveMacro.height=7; } if (ds.system[0]==DIV_SYSTEM_PCE) { ins->type=DIV_INS_PCE; - ins->std.volMacro.height=31; } if ((ds.system[0]==DIV_SYSTEM_SMS_OPLL || ds.system[0]==DIV_SYSTEM_NES_VRC7) && ins->type==DIV_INS_FM) { ins->type=DIV_INS_OPLL; diff --git a/src/engine/instrument.cpp b/src/engine/instrument.cpp index d39e9c69..8f87e460 100644 --- a/src/engine/instrument.cpp +++ b/src/engine/instrument.cpp @@ -23,37 +23,13 @@ #include "../ta-log.h" #include "../fileutils.h" -void DivInstrument::putMacroData(DivInstrumentMacro m, SafeWriter* w) { - w->write("MACR",4); - w->writeI(0); - - w->writeS(DIV_ENGINE_VERSION); - - w->writeS(type); - w->writeC(0); - - w->writeString(m.name,false); - - w->writeI(m.len); - w->writeI(m.loop); - w->writeI(m.rel); - w->writeI(m.mode); - w->writeC(m.open); - for (int v=0; vwriteI(m.val[v]); - w->writeI(0); // reserved - w->writeI(0); // reserved - } -} - void DivInstrument::putInsData(SafeWriter* w) { w->write("INST",4); w->writeI(0); w->writeS(DIV_ENGINE_VERSION); - w->writeS(type); - //w->writeC(type); + w->writeC(type); w->writeC(0); w->writeString(name,false); @@ -125,7 +101,7 @@ void DivInstrument::putInsData(SafeWriter* w) { w->writeC(c64.hp); w->writeC(c64.ch3off); w->writeS(c64.cut); - //w->writeC(std.dutyMacro.mode); + w->writeC(c64.dutyIsAbs); w->writeC(c64.filterIsAbs); // Amiga @@ -135,66 +111,6 @@ void DivInstrument::putInsData(SafeWriter* w) { } // standard - putMacroData(std.volMacro,w); - putMacroData(std.arpMacro,w); - putMacroData(std.dutyMacro,w); - putMacroData(std.waveMacro,w); - putMacroData(std.pitchMacro,w); - putMacroData(std.ex1Macro,w); - putMacroData(std.ex2Macro,w); - putMacroData(std.ex3Macro,w); - putMacroData(std.algMacro,w); - putMacroData(std.fbMacro,w); - putMacroData(std.fmsMacro,w); - putMacroData(std.fms2Macro,w); - putMacroData(std.amsMacro,w); - putMacroData(std.ams2Macro,w); - putMacroData(std.panLMacro,w); - putMacroData(std.panRMacro,w); - putMacroData(std.phaseResetMacro,w); - putMacroData(std.ex4Macro,w); - putMacroData(std.ex5Macro,w); - putMacroData(std.ex6Macro,w); - putMacroData(std.ex7Macro,w); - putMacroData(std.ex8Macro,w); - // FM macros - for (int i=0; i<4; i++) { - DivInstrumentSTD::OpMacro& op=std.opMacros[i]; - putMacroData(op.amMacro,w); - putMacroData(op.arMacro,w); - putMacroData(op.drMacro,w); - putMacroData(op.multMacro,w); - putMacroData(op.rrMacro,w); - putMacroData(op.slMacro,w); - putMacroData(op.tlMacro,w); - putMacroData(op.dt2Macro,w); - putMacroData(op.rsMacro,w); - putMacroData(op.dtMacro,w); - putMacroData(op.d2rMacro,w); - putMacroData(op.ssgMacro,w); - putMacroData(op.damMacro,w); - putMacroData(op.dvbMacro,w); - putMacroData(op.egtMacro,w); - putMacroData(op.kslMacro,w); - putMacroData(op.susMacro,w); - putMacroData(op.vibMacro,w); - putMacroData(op.wsMacro,w); - putMacroData(op.ksrMacro,w); - } - // wavesynth macros - putMacroData(std.ws.wave1Macro,w); - putMacroData(std.ws.wave2Macro,w); - putMacroData(std.ws.rateDividerMacro,w); - putMacroData(std.ws.effectMacro,w); - putMacroData(std.ws.oneShotMacro,w); - putMacroData(std.ws.enabledMacro,w); - putMacroData(std.ws.globalMacro,w); - putMacroData(std.ws.speedMacro,w); - putMacroData(std.ws.param1Macro,w); - putMacroData(std.ws.param2Macro,w); - putMacroData(std.ws.param3Macro,w); - putMacroData(std.ws.param4Macro,w); - /* w->writeI(std.volMacro.len); w->writeI(std.arpMacro.len); w->writeI(std.dutyMacro.len); @@ -454,7 +370,7 @@ void DivInstrument::putInsData(SafeWriter* w) { for (int j=0; jwriteC(op.ksrMacro.val[j]); } - }*/ + } // OPL drum data w->writeC(fm.fixedDrums); @@ -478,7 +394,6 @@ void DivInstrument::putInsData(SafeWriter* w) { w->writeC(0); // reserved // more macros - /* w->writeI(std.panLMacro.len); w->writeI(std.panRMacro.len); w->writeI(std.phaseResetMacro.len); @@ -538,7 +453,7 @@ void DivInstrument::putInsData(SafeWriter* w) { } for (int j=0; jwriteI(std.ex8Macro.val[j]); - }*/ + } // FDS w->writeI(fds.modSpeed); @@ -565,43 +480,9 @@ void DivInstrument::putInsData(SafeWriter* w) { w->writeC(ws.param2); w->writeC(ws.param3); w->writeC(ws.param4); - - // FM per-operator enable - for (int j=0; j<4; j++) { - DivInstrumentFM::Operator& op=fm.op[j]; - w->writeC(op.enable?1:0); - } -} - -DivDataErrors DivInstrument::readMacroData(DivInstrumentMacro& m, SafeReader& reader, short version) { - char magic[4]; - reader.read(magic,4); - if (memcmp(magic,"MACR",4)!=0) { - logE("invalid macro header!\n"); - return DIV_DATA_INVALID_HEADER; - } - reader.readI(); - - reader.readS(); // format version. ignored. - /*type=(DivInstrumentType)*/reader.readS(); // instrument type - reader.readC(); - m.name=reader.readString(); - - m.len=reader.readI(); - m.loop=reader.readI(); - m.rel=reader.readI(); - m.mode=reader.readI(); - m.open=reader.readC(); - for (int v=0; v=17) { + std.pitchMacro.len=reader.readI(); + std.ex1Macro.len=reader.readI(); + std.ex2Macro.len=reader.readI(); + std.ex3Macro.len=reader.readI(); + } + std.volMacro.loop=reader.readI(); + std.arpMacro.loop=reader.readI(); + std.dutyMacro.loop=reader.readI(); + std.waveMacro.loop=reader.readI(); + if (version>=17) { + std.pitchMacro.loop=reader.readI(); + std.ex1Macro.loop=reader.readI(); + std.ex2Macro.loop=reader.readI(); + std.ex3Macro.loop=reader.readI(); + } + std.arpMacro.mode=reader.readC(); + // these 3 were macro heights before but they are not used anymore + int oldVolHeight=reader.readC(); + int oldDutyHeight=reader.readC(); + reader.readC(); // oldWaveHeight + reader.read(std.volMacro.val,4*std.volMacro.len); + reader.read(std.arpMacro.val,4*std.arpMacro.len); + reader.read(std.dutyMacro.val,4*std.dutyMacro.len); + reader.read(std.waveMacro.val,4*std.waveMacro.len); + if (version<31) { + if (!std.arpMacro.mode) for (int j=0; j=17) { - std.pitchMacro.len=reader.readI(); - std.ex1Macro.len=reader.readI(); - std.ex2Macro.len=reader.readI(); - std.ex3Macro.len=reader.readI(); - } - std.volMacro.loop=reader.readI(); - std.arpMacro.loop=reader.readI(); - std.dutyMacro.loop=reader.readI(); - std.waveMacro.loop=reader.readI(); - if (version>=17) { - std.pitchMacro.loop=reader.readI(); - std.ex1Macro.loop=reader.readI(); - std.ex2Macro.loop=reader.readI(); - std.ex3Macro.loop=reader.readI(); - } - std.arpMacro.mode=reader.readC(); - std.volMacro.height=reader.readC(); - std.dutyMacro.height=reader.readC(); - std.waveMacro.height=reader.readC(); - if (std.volMacro.height==0) std.volMacro.height=15; - if (std.dutyMacro.height==0) std.dutyMacro.height=3; - if (std.waveMacro.height==0) std.waveMacro.height=63; - reader.read(std.volMacro.val,4*std.volMacro.len); - reader.read(std.arpMacro.val,4*std.arpMacro.len); - reader.read(std.dutyMacro.val,4*std.dutyMacro.len); - reader.read(std.waveMacro.val,4*std.waveMacro.len); - if (version<31) { - if (!std.arpMacro.mode) for (int j=0; j=17) { + reader.read(std.pitchMacro.val,4*std.pitchMacro.len); + reader.read(std.ex1Macro.val,4*std.ex1Macro.len); + reader.read(std.ex2Macro.val,4*std.ex2Macro.len); + reader.read(std.ex3Macro.val,4*std.ex3Macro.len); + } else { + if (type==DIV_INS_STD) { + if (oldVolHeight==31) { + type=DIV_INS_PCE; + } + if (oldDutyHeight==31) { + type=DIV_INS_AY; } } - if (version>=17) { - reader.read(std.pitchMacro.val,4*std.pitchMacro.len); - reader.read(std.ex1Macro.val,4*std.ex1Macro.len); - reader.read(std.ex2Macro.val,4*std.ex2Macro.len); - reader.read(std.ex3Macro.val,4*std.ex3Macro.len); - } else { - if (type==DIV_INS_STD) { - if (std.volMacro.height==31) { - type=DIV_INS_PCE; - } - if (std.dutyMacro.height==31) { - type=DIV_INS_AY; - } - } + } + + // FM macros + if (version>=29) { + std.algMacro.len=reader.readI(); + std.fbMacro.len=reader.readI(); + std.fmsMacro.len=reader.readI(); + std.amsMacro.len=reader.readI(); + std.algMacro.loop=reader.readI(); + std.fbMacro.loop=reader.readI(); + std.fmsMacro.loop=reader.readI(); + std.amsMacro.loop=reader.readI(); + std.volMacro.open=reader.readC(); + std.arpMacro.open=reader.readC(); + std.dutyMacro.open=reader.readC(); + std.waveMacro.open=reader.readC(); + std.pitchMacro.open=reader.readC(); + std.ex1Macro.open=reader.readC(); + std.ex2Macro.open=reader.readC(); + std.ex3Macro.open=reader.readC(); + std.algMacro.open=reader.readC(); + std.fbMacro.open=reader.readC(); + std.fmsMacro.open=reader.readC(); + std.amsMacro.open=reader.readC(); + + reader.read(std.algMacro.val,4*std.algMacro.len); + reader.read(std.fbMacro.val,4*std.fbMacro.len); + reader.read(std.fmsMacro.val,4*std.fmsMacro.len); + reader.read(std.amsMacro.val,4*std.amsMacro.len); + + for (int i=0; i<4; i++) { + DivInstrumentSTD::OpMacro& op=std.opMacros[i]; + + op.amMacro.len=reader.readI(); + op.arMacro.len=reader.readI(); + op.drMacro.len=reader.readI(); + op.multMacro.len=reader.readI(); + op.rrMacro.len=reader.readI(); + op.slMacro.len=reader.readI(); + op.tlMacro.len=reader.readI(); + op.dt2Macro.len=reader.readI(); + op.rsMacro.len=reader.readI(); + op.dtMacro.len=reader.readI(); + op.d2rMacro.len=reader.readI(); + op.ssgMacro.len=reader.readI(); + + op.amMacro.loop=reader.readI(); + op.arMacro.loop=reader.readI(); + op.drMacro.loop=reader.readI(); + op.multMacro.loop=reader.readI(); + op.rrMacro.loop=reader.readI(); + op.slMacro.loop=reader.readI(); + op.tlMacro.loop=reader.readI(); + op.dt2Macro.loop=reader.readI(); + op.rsMacro.loop=reader.readI(); + op.dtMacro.loop=reader.readI(); + op.d2rMacro.loop=reader.readI(); + op.ssgMacro.loop=reader.readI(); + + op.amMacro.open=reader.readC(); + op.arMacro.open=reader.readC(); + op.drMacro.open=reader.readC(); + op.multMacro.open=reader.readC(); + op.rrMacro.open=reader.readC(); + op.slMacro.open=reader.readC(); + op.tlMacro.open=reader.readC(); + op.dt2Macro.open=reader.readC(); + op.rsMacro.open=reader.readC(); + op.dtMacro.open=reader.readC(); + op.d2rMacro.open=reader.readC(); + op.ssgMacro.open=reader.readC(); } - // FM macros - if (version>=29) { - std.algMacro.len=reader.readI(); - std.fbMacro.len=reader.readI(); - std.fmsMacro.len=reader.readI(); - std.amsMacro.len=reader.readI(); - std.algMacro.loop=reader.readI(); - std.fbMacro.loop=reader.readI(); - std.fmsMacro.loop=reader.readI(); - std.amsMacro.loop=reader.readI(); - std.volMacro.open=reader.readC(); - std.arpMacro.open=reader.readC(); - std.dutyMacro.open=reader.readC(); - std.waveMacro.open=reader.readC(); - std.pitchMacro.open=reader.readC(); - std.ex1Macro.open=reader.readC(); - std.ex2Macro.open=reader.readC(); - std.ex3Macro.open=reader.readC(); - std.algMacro.open=reader.readC(); - std.fbMacro.open=reader.readC(); - std.fmsMacro.open=reader.readC(); - std.amsMacro.open=reader.readC(); + for (int i=0; i<4; i++) { + DivInstrumentSTD::OpMacro& op=std.opMacros[i]; + reader.read(op.amMacro.val,op.amMacro.len); + reader.read(op.arMacro.val,op.arMacro.len); + reader.read(op.drMacro.val,op.drMacro.len); + reader.read(op.multMacro.val,op.multMacro.len); + reader.read(op.rrMacro.val,op.rrMacro.len); + reader.read(op.slMacro.val,op.slMacro.len); + reader.read(op.tlMacro.val,op.tlMacro.len); + reader.read(op.dt2Macro.val,op.dt2Macro.len); + reader.read(op.rsMacro.val,op.rsMacro.len); + reader.read(op.dtMacro.val,op.dtMacro.len); + reader.read(op.d2rMacro.val,op.d2rMacro.len); + reader.read(op.ssgMacro.val,op.ssgMacro.len); + } + } - reader.read(std.algMacro.val,4*std.algMacro.len); - reader.read(std.fbMacro.val,4*std.fbMacro.len); - reader.read(std.fmsMacro.val,4*std.fmsMacro.len); - reader.read(std.amsMacro.val,4*std.amsMacro.len); + // release points + if (version>=44) { + std.volMacro.rel=reader.readI(); + std.arpMacro.rel=reader.readI(); + std.dutyMacro.rel=reader.readI(); + std.waveMacro.rel=reader.readI(); + std.pitchMacro.rel=reader.readI(); + std.ex1Macro.rel=reader.readI(); + std.ex2Macro.rel=reader.readI(); + std.ex3Macro.rel=reader.readI(); + std.algMacro.rel=reader.readI(); + std.fbMacro.rel=reader.readI(); + std.fmsMacro.rel=reader.readI(); + std.amsMacro.rel=reader.readI(); - for (int i=0; i<4; i++) { - DivInstrumentSTD::OpMacro& op=std.opMacros[i]; + for (int i=0; i<4; i++) { + DivInstrumentSTD::OpMacro& op=std.opMacros[i]; - op.amMacro.len=reader.readI(); - op.arMacro.len=reader.readI(); - op.drMacro.len=reader.readI(); - op.multMacro.len=reader.readI(); - op.rrMacro.len=reader.readI(); - op.slMacro.len=reader.readI(); - op.tlMacro.len=reader.readI(); - op.dt2Macro.len=reader.readI(); - op.rsMacro.len=reader.readI(); - op.dtMacro.len=reader.readI(); - op.d2rMacro.len=reader.readI(); - op.ssgMacro.len=reader.readI(); + op.amMacro.rel=reader.readI(); + op.arMacro.rel=reader.readI(); + op.drMacro.rel=reader.readI(); + op.multMacro.rel=reader.readI(); + op.rrMacro.rel=reader.readI(); + op.slMacro.rel=reader.readI(); + op.tlMacro.rel=reader.readI(); + op.dt2Macro.rel=reader.readI(); + op.rsMacro.rel=reader.readI(); + op.dtMacro.rel=reader.readI(); + op.d2rMacro.rel=reader.readI(); + op.ssgMacro.rel=reader.readI(); + } + } - op.amMacro.loop=reader.readI(); - op.arMacro.loop=reader.readI(); - op.drMacro.loop=reader.readI(); - op.multMacro.loop=reader.readI(); - op.rrMacro.loop=reader.readI(); - op.slMacro.loop=reader.readI(); - op.tlMacro.loop=reader.readI(); - op.dt2Macro.loop=reader.readI(); - op.rsMacro.loop=reader.readI(); - op.dtMacro.loop=reader.readI(); - op.d2rMacro.loop=reader.readI(); - op.ssgMacro.loop=reader.readI(); + // extended op macros + if (version>=61) { + for (int i=0; i<4; i++) { + DivInstrumentSTD::OpMacro& op=std.opMacros[i]; - op.amMacro.open=reader.readC(); - op.arMacro.open=reader.readC(); - op.drMacro.open=reader.readC(); - op.multMacro.open=reader.readC(); - op.rrMacro.open=reader.readC(); - op.slMacro.open=reader.readC(); - op.tlMacro.open=reader.readC(); - op.dt2Macro.open=reader.readC(); - op.rsMacro.open=reader.readC(); - op.dtMacro.open=reader.readC(); - op.d2rMacro.open=reader.readC(); - op.ssgMacro.open=reader.readC(); - } + op.damMacro.len=reader.readI(); + op.dvbMacro.len=reader.readI(); + op.egtMacro.len=reader.readI(); + op.kslMacro.len=reader.readI(); + op.susMacro.len=reader.readI(); + op.vibMacro.len=reader.readI(); + op.wsMacro.len=reader.readI(); + op.ksrMacro.len=reader.readI(); - for (int i=0; i<4; i++) { - DivInstrumentSTD::OpMacro& op=std.opMacros[i]; - for (int l=0; l=44) { - std.volMacro.rel=reader.readI(); - std.arpMacro.rel=reader.readI(); - std.dutyMacro.rel=reader.readI(); - std.waveMacro.rel=reader.readI(); - std.pitchMacro.rel=reader.readI(); - std.ex1Macro.rel=reader.readI(); - std.ex2Macro.rel=reader.readI(); - std.ex3Macro.rel=reader.readI(); - std.algMacro.rel=reader.readI(); - std.fbMacro.rel=reader.readI(); - std.fmsMacro.rel=reader.readI(); - std.amsMacro.rel=reader.readI(); - - for (int i=0; i<4; i++) { - DivInstrumentSTD::OpMacro& op=std.opMacros[i]; - - op.amMacro.rel=reader.readI(); - op.arMacro.rel=reader.readI(); - op.drMacro.rel=reader.readI(); - op.multMacro.rel=reader.readI(); - op.rrMacro.rel=reader.readI(); - op.slMacro.rel=reader.readI(); - op.tlMacro.rel=reader.readI(); - op.dt2Macro.rel=reader.readI(); - op.rsMacro.rel=reader.readI(); - op.dtMacro.rel=reader.readI(); - op.d2rMacro.rel=reader.readI(); - op.ssgMacro.rel=reader.readI(); - } - } - - // extended op macros - if (version>=61) { - for (int i=0; i<4; i++) { - DivInstrumentSTD::OpMacro& op=std.opMacros[i]; - - op.damMacro.len=reader.readI(); - op.dvbMacro.len=reader.readI(); - op.egtMacro.len=reader.readI(); - op.kslMacro.len=reader.readI(); - op.susMacro.len=reader.readI(); - op.vibMacro.len=reader.readI(); - op.wsMacro.len=reader.readI(); - op.ksrMacro.len=reader.readI(); - - op.damMacro.loop=reader.readI(); - op.dvbMacro.loop=reader.readI(); - op.egtMacro.loop=reader.readI(); - op.kslMacro.loop=reader.readI(); - op.susMacro.loop=reader.readI(); - op.vibMacro.loop=reader.readI(); - op.wsMacro.loop=reader.readI(); - op.ksrMacro.loop=reader.readI(); - - op.damMacro.rel=reader.readI(); - op.dvbMacro.rel=reader.readI(); - op.egtMacro.rel=reader.readI(); - op.kslMacro.rel=reader.readI(); - op.susMacro.rel=reader.readI(); - op.vibMacro.rel=reader.readI(); - op.wsMacro.rel=reader.readI(); - op.ksrMacro.rel=reader.readI(); - - op.damMacro.open=reader.readC(); - op.dvbMacro.open=reader.readC(); - op.egtMacro.open=reader.readC(); - op.kslMacro.open=reader.readC(); - op.susMacro.open=reader.readC(); - op.vibMacro.open=reader.readC(); - op.wsMacro.open=reader.readC(); - op.ksrMacro.open=reader.readC(); - } - - for (int i=0; i<4; i++) { - DivInstrumentSTD::OpMacro& op=std.opMacros[i]; - for (int l=0; l=76) { - std.panLMacro.len=reader.readI(); - std.panRMacro.len=reader.readI(); - std.phaseResetMacro.len=reader.readI(); - std.ex4Macro.len=reader.readI(); - std.ex5Macro.len=reader.readI(); - std.ex6Macro.len=reader.readI(); - std.ex7Macro.len=reader.readI(); - std.ex8Macro.len=reader.readI(); + if (version>=76) { + std.panLMacro.len=reader.readI(); + std.panRMacro.len=reader.readI(); + std.phaseResetMacro.len=reader.readI(); + std.ex4Macro.len=reader.readI(); + std.ex5Macro.len=reader.readI(); + std.ex6Macro.len=reader.readI(); + std.ex7Macro.len=reader.readI(); + std.ex8Macro.len=reader.readI(); - std.panLMacro.loop=reader.readI(); - std.panRMacro.loop=reader.readI(); - std.phaseResetMacro.loop=reader.readI(); - std.ex4Macro.loop=reader.readI(); - std.ex5Macro.loop=reader.readI(); - std.ex6Macro.loop=reader.readI(); - std.ex7Macro.loop=reader.readI(); - std.ex8Macro.loop=reader.readI(); + std.panLMacro.loop=reader.readI(); + std.panRMacro.loop=reader.readI(); + std.phaseResetMacro.loop=reader.readI(); + std.ex4Macro.loop=reader.readI(); + std.ex5Macro.loop=reader.readI(); + std.ex6Macro.loop=reader.readI(); + std.ex7Macro.loop=reader.readI(); + std.ex8Macro.loop=reader.readI(); - std.panLMacro.rel=reader.readI(); - std.panRMacro.rel=reader.readI(); - std.phaseResetMacro.rel=reader.readI(); - std.ex4Macro.rel=reader.readI(); - std.ex5Macro.rel=reader.readI(); - std.ex6Macro.rel=reader.readI(); - std.ex7Macro.rel=reader.readI(); - std.ex8Macro.rel=reader.readI(); + std.panLMacro.rel=reader.readI(); + std.panRMacro.rel=reader.readI(); + std.phaseResetMacro.rel=reader.readI(); + std.ex4Macro.rel=reader.readI(); + std.ex5Macro.rel=reader.readI(); + std.ex6Macro.rel=reader.readI(); + std.ex7Macro.rel=reader.readI(); + std.ex8Macro.rel=reader.readI(); - std.panLMacro.open=reader.readC(); - std.panRMacro.open=reader.readC(); - std.phaseResetMacro.open=reader.readC(); - std.ex4Macro.open=reader.readC(); - std.ex5Macro.open=reader.readC(); - std.ex6Macro.open=reader.readC(); - std.ex7Macro.open=reader.readC(); - std.ex8Macro.open=reader.readC(); + std.panLMacro.open=reader.readC(); + std.panRMacro.open=reader.readC(); + std.phaseResetMacro.open=reader.readC(); + std.ex4Macro.open=reader.readC(); + std.ex5Macro.open=reader.readC(); + std.ex6Macro.open=reader.readC(); + std.ex7Macro.open=reader.readC(); + std.ex8Macro.open=reader.readC(); - reader.read(std.panLMacro.val,4*std.panLMacro.len); - reader.read(std.panRMacro.val,4*std.panRMacro.len); - reader.read(std.phaseResetMacro.val,4*std.phaseResetMacro.len); - reader.read(std.ex4Macro.val,4*std.ex4Macro.len); - reader.read(std.ex5Macro.val,4*std.ex5Macro.len); - reader.read(std.ex6Macro.val,4*std.ex6Macro.len); - reader.read(std.ex7Macro.val,4*std.ex7Macro.len); - reader.read(std.ex8Macro.val,4*std.ex8Macro.len); - } + reader.read(std.panLMacro.val,4*std.panLMacro.len); + reader.read(std.panRMacro.val,4*std.panRMacro.len); + reader.read(std.phaseResetMacro.val,4*std.phaseResetMacro.len); + reader.read(std.ex4Macro.val,4*std.ex4Macro.len); + reader.read(std.ex5Macro.val,4*std.ex5Macro.len); + reader.read(std.ex6Macro.val,4*std.ex6Macro.len); + reader.read(std.ex7Macro.val,4*std.ex7Macro.len); + reader.read(std.ex8Macro.val,4*std.ex8Macro.len); } // FDS @@ -1262,14 +921,6 @@ DivDataErrors DivInstrument::readInsData(SafeReader& reader, short version) { ws.param3=reader.readC(); ws.param4=reader.readC(); } - - // FM per-operator enable - if (istest) { - for (int j=0; j<4; j++) { - DivInstrumentFM::Operator& op=fm.op[j]; - op.enable=reader.readC(); - } - } return DIV_DATA_SUCCESS; } diff --git a/src/engine/instrument.h b/src/engine/instrument.h index e12da09d..605241c7 100644 --- a/src/engine/instrument.h +++ b/src/engine/instrument.h @@ -26,7 +26,7 @@ // NOTICE! // before adding new instrument types to this struct, please ask me first. // absolutely zero support granted to conflicting formats. -enum DivInstrumentType : unsigned short { +enum DivInstrumentType: unsigned short { DIV_INS_STD=0, DIV_INS_FM=1, DIV_INS_GB=2, @@ -81,7 +81,7 @@ struct DivInstrumentFM { unsigned char am, ar, dr, mult, rr, sl, tl, dt2, rs, dt, d2r, ssgEnv; unsigned char dam, dvb, egt, ksl, sus, vib, ws, ksr; // YMU759/OPL/OPZ Operator(): - enable(false), + enable(true), am(0), ar(0), dr(0), @@ -156,22 +156,20 @@ struct DivInstrumentFM { struct DivInstrumentMacro { String name; int val[256]; - int height; unsigned int mode; bool open; unsigned char len; signed char loop; signed char rel; - DivInstrumentMacro(String n, int h=~0, bool initOpen=false): + DivInstrumentMacro(String n, bool initOpen=false): name(n), - height(h), mode(0), open(initOpen), len(0), loop(-1), rel(-1) { memset(val,0,256*sizeof(int)); - } + } }; struct DivInstrumentSTD { @@ -186,9 +184,7 @@ struct DivInstrumentSTD { DivInstrumentMacro algMacro; DivInstrumentMacro fbMacro; DivInstrumentMacro fmsMacro; - DivInstrumentMacro fms2Macro; DivInstrumentMacro amsMacro; - DivInstrumentMacro ams2Macro; DivInstrumentMacro panLMacro; DivInstrumentMacro panRMacro; DivInstrumentMacro phaseResetMacro; @@ -222,36 +218,16 @@ struct DivInstrumentSTD { DivInstrumentMacro ksrMacro; OpMacro(): amMacro("am"), arMacro("ar"), drMacro("dr"), multMacro("mult"), - rrMacro("rr"), slMacro("sl"), tlMacro("tl",~0,true), dt2Macro("dt2"), + rrMacro("rr"), slMacro("sl"), tlMacro("tl",true), dt2Macro("dt2"), rsMacro("rs"), dtMacro("dt"), d2rMacro("d2r"), ssgMacro("ssg"), damMacro("dam"), dvbMacro("dvb"), egtMacro("egt"), kslMacro("ksl"), susMacro("sus"), vibMacro("vib"), wsMacro("ws"), ksrMacro("ksr") {} } opMacros[4]; - struct WaveSynthMacro { - DivInstrumentMacro wave1Macro, wave2Macro; - DivInstrumentMacro rateDividerMacro; - DivInstrumentMacro effectMacro; - DivInstrumentMacro oneShotMacro, enabledMacro, globalMacro; - DivInstrumentMacro speedMacro, param1Macro, param2Macro, param3Macro, param4Macro; - WaveSynthMacro(): - wave1Macro("wave1"), - wave2Macro("wave2"), - rateDividerMacro("rateDivider"), - effectMacro("effect"), - oneShotMacro("oneShot"), - enabledMacro("enabled"), - globalMacro("global"), - speedMacro("speed"), - param1Macro("param1"), - param2Macro("param2"), - param3Macro("param3"), - param4Macro("param4") {} - } ws; DivInstrumentSTD(): - volMacro("vol",15,true), + volMacro("vol",true), arpMacro("arp"), - dutyMacro("duty",3), - waveMacro("wave",63), + dutyMacro("duty"), + waveMacro("wave"), pitchMacro("pitch"), ex1Macro("ex1"), ex2Macro("ex2"), @@ -259,9 +235,7 @@ struct DivInstrumentSTD { algMacro("alg"), fbMacro("fb"), fmsMacro("fms"), - fms2Macro("fms2"), amsMacro("ams"), - ams2Macro("ams2"), panLMacro("panL"), panRMacro("panR"), phaseResetMacro("phaseReset"), @@ -425,15 +399,6 @@ struct DivInstrument { */ DivDataErrors readInsData(SafeReader& reader, short version); - /** - * read macro data in .fui format. - * @param m the macro. - * @param reader the reader. - * @param version the format version. - * @return a DivDataErrors. - */ - DivDataErrors readMacroData(DivInstrumentMacro& m, SafeReader& reader, short version); - /** * save this instrument to a file. * @param path file path. diff --git a/src/engine/macroInt.cpp b/src/engine/macroInt.cpp index aafeedbc..489a6fab 100644 --- a/src/engine/macroInt.cpp +++ b/src/engine/macroInt.cpp @@ -45,10 +45,10 @@ void DivMacroStruct::doMacro(DivInstrumentMacro& source, bool released) { } } -// CPU hell void DivMacroInt::next() { if (ins==NULL) return; - // Run macros + // run macros + // TODO: potentially get rid of list to avoid allocations if (!macroList.empty()) { for (std::list::iterator iter = macroList.begin(); iter!= macroList.end(); iter++) { iter->doMacro(released); @@ -63,6 +63,7 @@ void DivMacroInt::release() { void DivMacroInt::init(DivInstrument* which) { ins=which; // initialize + // TODO: potentially get rid of list to avoid allocations while (!macroList.empty()) { macroList.front().init(); macroList.pop_front(); @@ -106,17 +107,10 @@ void DivMacroInt::init(DivInstrument* which) { if (ins->std.fmsMacro.len>0) { macroList.push_back(DivMacroExecList(fms,ins->std.fmsMacro)); } - if (ins->std.fms2Macro.len>0) { - macroList.push_back(DivMacroExecList(fms2,ins->std.fms2Macro)); - } if (ins->std.amsMacro.len>0) { macroList.push_back(DivMacroExecList(ams,ins->std.amsMacro)); } - if (ins->std.ams2Macro.len>0) { - macroList.push_back(DivMacroExecList(ams2,ins->std.ams2Macro)); - } - // TODO: other macros if (ins->std.panLMacro.len>0) { macroList.push_back(DivMacroExecList(panL,ins->std.panLMacro)); } @@ -209,46 +203,9 @@ void DivMacroInt::init(DivInstrument* which) { } } - // prepare wavesynth macros - if (ins->std.ws.wave1Macro.len>0) { - macroList.push_back(DivMacroExecList(ws.wave1,ins->std.ws.wave1Macro)); - } - if (ins->std.ws.wave2Macro.len>0) { - macroList.push_back(DivMacroExecList(ws.wave2,ins->std.ws.wave2Macro)); - } - if (ins->std.ws.rateDividerMacro.len>0) { - macroList.push_back(DivMacroExecList(ws.rateDivider,ins->std.ws.rateDividerMacro)); - } - if (ins->std.ws.effectMacro.len>0) { - macroList.push_back(DivMacroExecList(ws.effect,ins->std.ws.effectMacro)); - } - if (ins->std.ws.oneShotMacro.len>0) { - macroList.push_back(DivMacroExecList(ws.oneShot,ins->std.ws.oneShotMacro)); - } - if (ins->std.ws.enabledMacro.len>0) { - macroList.push_back(DivMacroExecList(ws.enabled,ins->std.ws.enabledMacro)); - } - if (ins->std.ws.globalMacro.len>0) { - macroList.push_back(DivMacroExecList(ws.global,ins->std.ws.globalMacro)); - } - if (ins->std.ws.speedMacro.len>0) { - macroList.push_back(DivMacroExecList(ws.speed,ins->std.ws.speedMacro)); - } - if (ins->std.ws.param1Macro.len>0) { - macroList.push_back(DivMacroExecList(ws.param1,ins->std.ws.param1Macro)); - } - if (ins->std.ws.param2Macro.len>0) { - macroList.push_back(DivMacroExecList(ws.param2,ins->std.ws.param2Macro)); - } - if (ins->std.ws.param3Macro.len>0) { - macroList.push_back(DivMacroExecList(ws.param3,ins->std.ws.param3Macro)); - } - if (ins->std.ws.param4Macro.len>0) { - macroList.push_back(DivMacroExecList(ws.param4,ins->std.ws.param4Macro)); - } if (!macroList.empty()) { - for (std::list::iterator iter = macroList.begin(); iter!= macroList.end(); iter++) { - iter->prepare(); + for (std::list::iterator iter = macroList.begin(); iter!= macroList.end(); iter++) { + iter->prepare(); } } } diff --git a/src/engine/macroInt.h b/src/engine/macroInt.h index 3ce0c872..2480d743 100644 --- a/src/engine/macroInt.h +++ b/src/engine/macroInt.h @@ -73,7 +73,7 @@ class DivMacroInt { DivMacroStruct vol; DivMacroStruct arp; DivMacroStruct duty, wave, pitch, ex1, ex2, ex3; - DivMacroStruct alg, fb, fms, fms2, ams, ams2; + DivMacroStruct alg, fb, fms, ams; DivMacroStruct panL, panR, phaseReset, ex4, ex5, ex6, ex7, ex8; // FM operator macro @@ -105,28 +105,6 @@ class DivMacroInt { ws(), ksr() {} } op[4]; - - // wavesynth macro - struct IntWS { - DivMacroStruct wave1, wave2; - DivMacroStruct rateDivider; - DivMacroStruct effect; - DivMacroStruct oneShot, enabled, global; - DivMacroStruct speed, param1, param2, param3, param4; - IntWS(): - wave1(), - wave2(), - rateDivider(), - effect(), - oneShot(), - enabled(), - global(), - speed(), - param1(), - param2(), - param3(), - param4() {} - } ws; /** * trigger macro release. @@ -165,9 +143,7 @@ class DivMacroInt { alg(), fb(), fms(), - fms2(), ams(), - ams2(), panL(), panR(), phaseReset(), diff --git a/src/engine/platform/tx81z.cpp b/src/engine/platform/tx81z.cpp index 76c9d24b..7ea634b2 100644 --- a/src/engine/platform/tx81z.cpp +++ b/src/engine/platform/tx81z.cpp @@ -275,18 +275,10 @@ void DivPlatformTX81Z::tick() { chan[i].state.fms=chan[i].std.fms.val; rWrite(chanOffs[i]+ADDR_FMS_AMS,((chan[i].state.fms&7)<<4)|(chan[i].state.ams&3)); } - if (chan[i].std.fms2.had) { - chan[i].state.fms2=chan[i].std.fms2.val; - //rWrite(chanOffs[i]+ADDR_FMS_AMS,0x84|((chan[i].state.fms2&7)<<4)|(chan[i].state.ams2&3)); - } if (chan[i].std.ams.had) { chan[i].state.ams=chan[i].std.ams.val; rWrite(chanOffs[i]+ADDR_FMS_AMS,((chan[i].state.fms&7)<<4)|(chan[i].state.ams&3)); } - if (chan[i].std.ams2.had) { - chan[i].state.ams2=chan[i].std.ams2.val; - //rWrite(chanOffs[i]+ADDR_FMS_AMS,0x84|((chan[i].state.fms2&7)<<4)|(chan[i].state.ams2&3)); - } for (int j=0; j<4; j++) { unsigned short baseAddr=chanOffs[i]|opOffs[j]; DivInstrumentFM::Operator& op=chan[i].state.op[j]; diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 685160b7..3e141612 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -110,7 +110,7 @@ enum FMParams { #define FM_SHORT_NAME(x) fmParamShortNames[settings.fmNames][x] const char* fmOperatorBits[5]={ - "op1", "op3", "op2", "op4", NULL + "op1", "op2", "op3", "op4", NULL }; const char* c64ShapeBits[5]={ @@ -182,11 +182,12 @@ const char* dualWSEffects[7]={ const char* macroAbsoluteMode[2]={ "Relative", - "Absolute", + "Absolute" }; const char* macroDummyMode[2]={ - "empty", + "Bug", + "Bug" }; String macroHoverNote(int id, float val) { @@ -996,7 +997,7 @@ void FurnaceGUI::drawFMEnv(unsigned char tl, unsigned char ar, unsigned char dr, } else { \ modeName=displayModeName[macro.mode]; \ } \ - if (ImGui::BeginCombo("Macro Mode##IMacroMode_" macroName,modeName.c_str())) { \ + if (ImGui::BeginCombo("TODO: Improve##IMacroMode_" macroName,modeName.c_str())) { \ String id; \ for (unsigned int i=0; i<=macroModeMax; i++) { \ id=fmt::sprintf("%d: %s",i,displayModeName[i]); \ @@ -1100,7 +1101,7 @@ void FurnaceGUI::drawFMEnv(unsigned char tl, unsigned char ar, unsigned char dr, } else { \ modeName=displayModeName[macro.mode]; \ } \ - if (ImGui::BeginCombo("Macro Mode##IOPMacroMode_" macroName,modeName.c_str())) { \ + if (ImGui::BeginCombo("TODO: Improve##IOPMacroMode_" macroName,modeName.c_str())) { \ String id; \ for (unsigned int i=0; i<=macroModeMax; i++) { \ id=fmt::sprintf("%d: %s",i,displayModeName[i]); \ @@ -2056,10 +2057,9 @@ void FurnaceGUI::drawInsEdit() { NORMAL_MACRO(ins->std.fbMacro,0,7,"fb",FM_NAME(FM_FB),96,ins->std.fbMacro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[1],0,7,NULL,false); if (ins->type!=DIV_INS_OPL) { if (ins->type==DIV_INS_OPZ) { + // TODO: FMS2/AMS2 macros NORMAL_MACRO(ins->std.fmsMacro,0,7,"fms",FM_NAME(FM_FMS),96,ins->std.fmsMacro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[2],0,7,NULL,false); - NORMAL_MACRO(ins->std.fms2Macro,0,7,"fms2",FM_NAME(FM_FMS2),96,ins->std.fms2Macro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[3],0,7,NULL,false); NORMAL_MACRO(ins->std.amsMacro,0,3,"ams",FM_NAME(FM_AMS),48,ins->std.amsMacro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,3,NULL,false); - NORMAL_MACRO(ins->std.ams2Macro,0,3,"ams2",FM_NAME(FM_AMS2),48,ins->std.ams2Macro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[5],0,3,NULL,false); } else { NORMAL_MACRO(ins->std.fmsMacro,0,7,"fms",FM_NAME(FM_FMS),96,ins->std.fmsMacro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[2],0,7,NULL,false); NORMAL_MACRO(ins->std.amsMacro,0,3,"ams",FM_NAME(FM_AMS),48,ins->std.amsMacro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[3],0,3,NULL,false); @@ -2072,7 +2072,7 @@ void FurnaceGUI::drawInsEdit() { NORMAL_MACRO(ins->std.ex2Macro,0,127,"ex2","PM Depth",128,ins->std.ex2Macro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[7],0,127,NULL,false); NORMAL_MACRO(ins->std.ex3Macro,0,255,"ex3","LFO Speed",128,ins->std.ex3Macro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[8],0,255,NULL,false); NORMAL_MACRO(ins->std.waveMacro,0,3,"wave","LFO Shape",48,ins->std.waveMacro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_WAVE],mmlString[9],0,3,¯oLFOWaves,false); - NORMAL_MACRO(ins->std.ex4Macro,0,4,"ex4","Operator On/Off",128,ins->std.ex4Macro.open,true,fmOperatorBits,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[10],0,4,NULL,false); + NORMAL_MACRO(ins->std.ex4Macro,0,4,"ex4","OpMask",128,ins->std.ex4Macro.open,true,fmOperatorBits,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[10],0,4,NULL,false); } MACRO_END; ImGui::EndTabItem(); @@ -2238,10 +2238,7 @@ void FurnaceGUI::drawInsEdit() { P(ImGui::Checkbox("Volume Macro is Cutoff Macro",&ins->c64.volIsCutoff)); P(ImGui::Checkbox("Absolute Cutoff Macro",&ins->c64.filterIsAbs)); - bool dutyAbs=ins->std.dutyMacro.mode&1; - if (ImGui::Checkbox("Absolute Duty Macro",&dutyAbs)) { PARAMETER - ins->std.dutyMacro.mode^=1; - } + P(ImGui::Checkbox("Absolute Duty Macro",&ins->c64.dutyIsAbs)); ImGui::EndTabItem(); } if (ins->type==DIV_INS_AMIGA) if (ImGui::BeginTabItem("Amiga/Sample")) { @@ -2387,9 +2384,6 @@ void FurnaceGUI::drawInsEdit() { ins->type==DIV_INS_SWAN || ins->type==DIV_INS_PCE || ins->type==DIV_INS_SCC) { - float asFloat[256]; - int asInt[256]; - float loopIndicator[256]; if (ImGui::BeginTabItem("Wavetable")) { ImGui::Checkbox("Enable synthesizer",&ins->ws.enabled); ImGui::SameLine(); @@ -2484,20 +2478,6 @@ void FurnaceGUI::drawInsEdit() { ImGui::EndTabItem(); } - if (ImGui::BeginTabItem("Wavetable Macros")) { - MACRO_BEGIN(0); - NORMAL_MACRO(ins->std.ws.enabledMacro,0,1,"enabled","Enable",160,ins->std.ws.enabledMacro.open,true,oneBit,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[5],0,1,NULL,false); - NORMAL_MACRO(ins->std.ws.oneShotMacro,0,1,"oneShot","One Shot",160,ins->std.ws.oneShotMacro.open,true,oneBit,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,1,NULL,false); - NORMAL_MACRO(ins->std.ws.globalMacro,0,1,"global","Global",160,ins->std.ws.globalMacro.open,true,oneBit,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[6],0,1,NULL,false); - NORMAL_MACRO(ins->std.ws.effectMacro,0,255,"effect","Effect",160,ins->std.ws.effectMacro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[3],0,255,NULL,false); - NORMAL_MACRO(ins->std.ws.wave1Macro,0,255,"wave1","Wave 1",160,ins->std.ws.wave1Macro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[0],0,255,NULL,false); - NORMAL_MACRO(ins->std.ws.wave2Macro,0,255,"wave2","Wave 2",160,ins->std.ws.wave2Macro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[1],0,255,NULL,false); - NORMAL_MACRO(ins->std.ws.rateDividerMacro,1,7,"rateDivider","Rate",160,ins->std.ws.rateDividerMacro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[2],1,7,NULL,false); - NORMAL_MACRO(ins->std.ws.speedMacro,0,255,"speed","Speed",160,ins->std.ws.speedMacro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[6],0,255,NULL,false); - NORMAL_MACRO(ins->std.ws.param1Macro,1,7,"amount","Amount",160,ins->std.ws.param1Macro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[6],1,7,NULL,false); - MACRO_END; - ImGui::EndTabItem(); - } } if (ImGui::BeginTabItem("Macros")) { float asFloat[256]; @@ -2546,7 +2526,7 @@ void FurnaceGUI::drawInsEdit() { int dutyMax=3; if (ins->type==DIV_INS_C64) { dutyLabel="Duty"; - if (ins->std.dutyMacro.mode) { + if (ins->c64.dutyIsAbs) { dutyMax=4095; } else { dutyMax=24; @@ -2593,7 +2573,7 @@ void FurnaceGUI::drawInsEdit() { dutyLabel="Duty"; dutyMax=7; } - bool dutyIsRel=(ins->type==DIV_INS_C64 && !ins->std.dutyMacro.mode); + bool dutyIsRel=(ins->type==DIV_INS_C64 && !ins->c64.dutyIsAbs); const char* waveLabel="Waveform"; int waveMax=(ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930 || ins->type==DIV_INS_VERA)?3:63; @@ -2813,7 +2793,7 @@ void FurnaceGUI::drawInsEdit() { if (dutyMax>0) { ImGui::Separator(); if (ins->type==DIV_INS_C64) { - if (ins->std.dutyMacro.mode) { + if (ins->c64.dutyIsAbs) { ImGui::Text("Duty Macro"); } else { ImGui::Text("Relative Duty Macro"); From 51761bc6dfc3ef238464f590218977446268eb52 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 10 Apr 2022 16:53:43 -0500 Subject: [PATCH 57/76] part 3 - C64 mishap --- src/engine/platform/c64.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/platform/c64.cpp b/src/engine/platform/c64.cpp index 736ed437..b7521f03 100644 --- a/src/engine/platform/c64.cpp +++ b/src/engine/platform/c64.cpp @@ -158,7 +158,7 @@ void DivPlatformC64::tick() { } if (chan[i].std.duty.had) { DivInstrument* ins=parent->getIns(chan[i].ins); - if (ins->std.dutyMacro.mode) { + if (ins->c64.dutyIsAbs) { chan[i].duty=chan[i].std.duty.val; } else { chan[i].duty-=((signed char)chan[i].std.duty.val-12)*4; From 5f526f4b6e41994ce9bdfb993d7f74f6b997be29 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 10 Apr 2022 17:24:41 -0500 Subject: [PATCH 58/76] add playSub time log --- src/engine/engine.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 5288b839..fbafb668 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -764,6 +764,7 @@ void DivEngine::getCommandStream(std::vector& where) { } void DivEngine::playSub(bool preserveDrift, int goalRow) { + std::chrono::high_resolution_clock::time_point timeStart=std::chrono::high_resolution_clock::now(); for (int i=0; isetSkipRegisterWrites(false); reset(); if (preserveDrift && curOrder==0) return; @@ -822,6 +823,8 @@ void DivEngine::playSub(bool preserveDrift, int goalRow) { } skipping=false; cmdStream.clear(); + std::chrono::high_resolution_clock::time_point timeEnd=std::chrono::high_resolution_clock::now(); + logV("playSub() tool %dµs\n",std::chrono::duration_cast(timeEnd-timeStart).count()); } /* From 4ae13c15e60eb71c6ab243766997f2b2ff91ac35 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 10 Apr 2022 18:07:30 -0500 Subject: [PATCH 59/76] get rid of --- src/engine/macroInt.cpp | 107 +++++++++++++++++++++------------------- src/engine/macroInt.h | 29 +++-------- 2 files changed, 63 insertions(+), 73 deletions(-) diff --git a/src/engine/macroInt.cpp b/src/engine/macroInt.cpp index 489a6fab..21ca93a1 100644 --- a/src/engine/macroInt.cpp +++ b/src/engine/macroInt.cpp @@ -21,7 +21,9 @@ #include "instrument.h" void DivMacroStruct::doMacro(DivInstrumentMacro& source, bool released) { - if (finished) finished=false; + if (finished) { + finished=false; + } if (had!=has) { finished=true; } @@ -49,9 +51,9 @@ void DivMacroInt::next() { if (ins==NULL) return; // run macros // TODO: potentially get rid of list to avoid allocations - if (!macroList.empty()) { - for (std::list::iterator iter = macroList.begin(); iter!= macroList.end(); iter++) { - iter->doMacro(released); + for (size_t i=0; idoMacro(*macroSource[i],released); } } } @@ -60,14 +62,17 @@ void DivMacroInt::release() { released=true; } +#define ADD_MACRO(m,s) \ + macroList[macroListLen]=&m; \ + macroSource[macroListLen++]=&s; + void DivMacroInt::init(DivInstrument* which) { ins=which; // initialize - // TODO: potentially get rid of list to avoid allocations - while (!macroList.empty()) { - macroList.front().init(); - macroList.pop_front(); + for (size_t i=0; iinit(); } + macroListLen=0; released=false; @@ -75,65 +80,65 @@ void DivMacroInt::init(DivInstrument* which) { // prepare common macro if (ins->std.volMacro.len>0) { - macroList.push_back(DivMacroExecList(vol,ins->std.volMacro)); + ADD_MACRO(vol,ins->std.volMacro); } if (ins->std.arpMacro.len>0) { - macroList.push_back(DivMacroExecList(arp,ins->std.arpMacro)); + ADD_MACRO(arp,ins->std.arpMacro); } if (ins->std.dutyMacro.len>0) { - macroList.push_back(DivMacroExecList(duty,ins->std.dutyMacro)); + ADD_MACRO(duty,ins->std.dutyMacro); } if (ins->std.waveMacro.len>0) { - macroList.push_back(DivMacroExecList(wave,ins->std.waveMacro)); + ADD_MACRO(wave,ins->std.waveMacro); } if (ins->std.pitchMacro.len>0) { - macroList.push_back(DivMacroExecList(pitch,ins->std.pitchMacro)); + ADD_MACRO(pitch,ins->std.pitchMacro); } if (ins->std.ex1Macro.len>0) { - macroList.push_back(DivMacroExecList(ex1,ins->std.ex1Macro)); + ADD_MACRO(ex1,ins->std.ex1Macro); } if (ins->std.ex2Macro.len>0) { - macroList.push_back(DivMacroExecList(ex2,ins->std.ex2Macro)); + ADD_MACRO(ex2,ins->std.ex2Macro); } if (ins->std.ex3Macro.len>0) { - macroList.push_back(DivMacroExecList(ex3,ins->std.ex3Macro)); + ADD_MACRO(ex3,ins->std.ex3Macro); } if (ins->std.algMacro.len>0) { - macroList.push_back(DivMacroExecList(alg,ins->std.algMacro)); + ADD_MACRO(alg,ins->std.algMacro); } if (ins->std.fbMacro.len>0) { - macroList.push_back(DivMacroExecList(fb,ins->std.fbMacro)); + ADD_MACRO(fb,ins->std.fbMacro); } if (ins->std.fmsMacro.len>0) { - macroList.push_back(DivMacroExecList(fms,ins->std.fmsMacro)); + ADD_MACRO(fms,ins->std.fmsMacro); } if (ins->std.amsMacro.len>0) { - macroList.push_back(DivMacroExecList(ams,ins->std.amsMacro)); + ADD_MACRO(ams,ins->std.amsMacro); } if (ins->std.panLMacro.len>0) { - macroList.push_back(DivMacroExecList(panL,ins->std.panLMacro)); + ADD_MACRO(panL,ins->std.panLMacro); } if (ins->std.panRMacro.len>0) { - macroList.push_back(DivMacroExecList(panR,ins->std.panRMacro)); + ADD_MACRO(panR,ins->std.panRMacro); } if (ins->std.phaseResetMacro.len>0) { - macroList.push_back(DivMacroExecList(phaseReset,ins->std.phaseResetMacro)); + ADD_MACRO(phaseReset,ins->std.phaseResetMacro); } if (ins->std.ex4Macro.len>0) { - macroList.push_back(DivMacroExecList(ex4,ins->std.ex4Macro)); + ADD_MACRO(ex4,ins->std.ex4Macro); } if (ins->std.ex5Macro.len>0) { - macroList.push_back(DivMacroExecList(ex5,ins->std.ex5Macro)); + ADD_MACRO(ex5,ins->std.ex5Macro); } if (ins->std.ex6Macro.len>0) { - macroList.push_back(DivMacroExecList(ex6,ins->std.ex6Macro)); + ADD_MACRO(ex6,ins->std.ex6Macro); } if (ins->std.ex7Macro.len>0) { - macroList.push_back(DivMacroExecList(ex7,ins->std.ex7Macro)); + ADD_MACRO(ex7,ins->std.ex7Macro); } if (ins->std.ex8Macro.len>0) { - macroList.push_back(DivMacroExecList(ex8,ins->std.ex8Macro)); + ADD_MACRO(ex8,ins->std.ex8Macro); } // prepare FM operator macros @@ -141,72 +146,70 @@ void DivMacroInt::init(DivInstrument* which) { DivInstrumentSTD::OpMacro& m=ins->std.opMacros[i]; IntOp& o=op[i]; if (m.amMacro.len>0) { - macroList.push_back(DivMacroExecList(o.am,m.amMacro)); + ADD_MACRO(o.am,m.amMacro); } if (m.arMacro.len>0) { - macroList.push_back(DivMacroExecList(o.ar,m.arMacro)); + ADD_MACRO(o.ar,m.arMacro); } if (m.drMacro.len>0) { - macroList.push_back(DivMacroExecList(o.dr,m.drMacro)); + ADD_MACRO(o.dr,m.drMacro); } if (m.multMacro.len>0) { - macroList.push_back(DivMacroExecList(o.mult,m.multMacro)); + ADD_MACRO(o.mult,m.multMacro); } if (m.rrMacro.len>0) { - macroList.push_back(DivMacroExecList(o.rr,m.rrMacro)); + ADD_MACRO(o.rr,m.rrMacro); } if (m.slMacro.len>0) { - macroList.push_back(DivMacroExecList(o.sl,m.slMacro)); + ADD_MACRO(o.sl,m.slMacro); } if (m.tlMacro.len>0) { - macroList.push_back(DivMacroExecList(o.tl,m.tlMacro)); + ADD_MACRO(o.tl,m.tlMacro); } if (m.dt2Macro.len>0) { - macroList.push_back(DivMacroExecList(o.dt2,m.dt2Macro)); + ADD_MACRO(o.dt2,m.dt2Macro); } if (m.rsMacro.len>0) { - macroList.push_back(DivMacroExecList(o.rs,m.rsMacro)); + ADD_MACRO(o.rs,m.rsMacro); } if (m.dtMacro.len>0) { - macroList.push_back(DivMacroExecList(o.dt,m.dtMacro)); + ADD_MACRO(o.dt,m.dtMacro); } if (m.d2rMacro.len>0) { - macroList.push_back(DivMacroExecList(o.d2r,m.d2rMacro)); + ADD_MACRO(o.d2r,m.d2rMacro); } if (m.ssgMacro.len>0) { - macroList.push_back(DivMacroExecList(o.ssg,m.ssgMacro)); + ADD_MACRO(o.ssg,m.ssgMacro); } if (m.damMacro.len>0) { - macroList.push_back(DivMacroExecList(o.dam,m.damMacro)); + ADD_MACRO(o.dam,m.damMacro); } if (m.dvbMacro.len>0) { - macroList.push_back(DivMacroExecList(o.dvb,m.dvbMacro)); + ADD_MACRO(o.dvb,m.dvbMacro); } if (m.egtMacro.len>0) { - macroList.push_back(DivMacroExecList(o.egt,m.egtMacro)); + ADD_MACRO(o.egt,m.egtMacro); } if (m.kslMacro.len>0) { - macroList.push_back(DivMacroExecList(o.ksl,m.kslMacro)); + ADD_MACRO(o.ksl,m.kslMacro); } if (m.susMacro.len>0) { - macroList.push_back(DivMacroExecList(o.sus,m.susMacro)); + ADD_MACRO(o.sus,m.susMacro); } if (m.vibMacro.len>0) { - macroList.push_back(DivMacroExecList(o.vib,m.vibMacro)); + ADD_MACRO(o.vib,m.vibMacro); } if (m.wsMacro.len>0) { - macroList.push_back(DivMacroExecList(o.ws,m.wsMacro)); + ADD_MACRO(o.ws,m.wsMacro); } if (m.ksrMacro.len>0) { - macroList.push_back(DivMacroExecList(o.ksr,m.ksrMacro)); + ADD_MACRO(o.ksr,m.ksrMacro); } } - if (!macroList.empty()) { - for (std::list::iterator iter = macroList.begin(); iter!= macroList.end(); iter++) { - iter->prepare(); - } + for (size_t i=0; iprepare(*macroSource[i]); } } diff --git a/src/engine/macroInt.h b/src/engine/macroInt.h index 2480d743..3c26eb65 100644 --- a/src/engine/macroInt.h +++ b/src/engine/macroInt.h @@ -21,7 +21,6 @@ #define _MACROINT_H #include "instrument.h" -#include struct DivMacroStruct { int pos; @@ -47,26 +46,11 @@ struct DivMacroStruct { mode(0) {} }; -struct DivMacroExecList { - DivMacroStruct& macro; - DivInstrumentMacro& source; - void init() { - macro.init(); - } - void prepare() { - macro.prepare(source); - } - void doMacro(bool released) { - macro.doMacro(source, released); - } - DivMacroExecList(DivMacroStruct& m, DivInstrumentMacro& s): - macro(m), - source(s) {} -}; - class DivMacroInt { DivInstrument* ins; - std::list macroList; + DivMacroStruct* macroList[128]; + DivInstrumentMacro* macroSource[128]; + size_t macroListLen; bool released; public: // common macro @@ -130,7 +114,7 @@ class DivMacroInt { DivMacroInt(): ins(NULL), - macroList(), + macroListLen(0), released(false), vol(), arp(), @@ -151,7 +135,10 @@ class DivMacroInt { ex5(), ex6(), ex7(), - ex8() {} + ex8() { + memset(macroList,0,128*sizeof(void*)); + memset(macroSource,0,128*sizeof(void*)); + } }; #endif From fddd05dc1a37858ec724ca058ed9aaa98fa2d3f2 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 10 Apr 2022 22:12:02 -0500 Subject: [PATCH 60/76] improve logging facility we have a log viewer within the program now --- CMakeLists.txt | 1 + src/audio/rtmidi.cpp | 24 ++-- src/audio/sdl.cpp | 8 +- src/engine/config.cpp | 8 +- src/engine/dispatchContainer.cpp | 6 +- src/engine/engine.cpp | 130 +++++++++--------- src/engine/fileOps.cpp | 226 +++++++++++++++---------------- src/engine/fileOpsIns.cpp | 48 +++---- src/engine/filter.cpp | 6 +- src/engine/instrument.cpp | 6 +- src/engine/platform/ay.cpp | 4 +- src/engine/platform/ay8930.cpp | 4 +- src/engine/platform/qsound.cpp | 4 +- src/engine/playback.cpp | 10 +- src/engine/safeReader.cpp | 16 +-- src/engine/sample.cpp | 4 +- src/engine/vgmOps.cpp | 12 +- src/engine/wavetable.cpp | 4 +- src/engine/winStuff.cpp | 6 +- src/gui/doAction.cpp | 3 + src/gui/editing.cpp | 4 +- src/gui/fileDialog.cpp | 6 +- src/gui/gui.cpp | 53 ++++---- src/gui/gui.h | 13 +- src/gui/guiConst.cpp | 7 + src/gui/log.cpp | 71 ++++++++++ src/gui/midiMap.cpp | 30 ++-- src/gui/pattern.cpp | 2 +- src/gui/sampleEdit.cpp | 8 +- src/gui/settings.cpp | 71 +++++----- src/log.cpp | 54 +++++--- src/main.cpp | 39 +++--- src/ta-log.h | 54 +++++++- 33 files changed, 556 insertions(+), 386 deletions(-) create mode 100644 src/gui/log.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index fef510ef..d3b98fc6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -394,6 +394,7 @@ src/gui/doAction.cpp src/gui/editing.cpp src/gui/editControls.cpp src/gui/insEdit.cpp +src/gui/log.cpp src/gui/mixer.cpp src/gui/midiMap.cpp src/gui/newSong.cpp diff --git a/src/audio/rtmidi.cpp b/src/audio/rtmidi.cpp index fcd992be..c4a6f8f9 100644 --- a/src/audio/rtmidi.cpp +++ b/src/audio/rtmidi.cpp @@ -44,18 +44,18 @@ bool TAMidiInRtMidi::gather() { std::vector TAMidiInRtMidi::listDevices() { std::vector ret; - logD("listing devices.\n"); + logD("listing devices."); if (port==NULL) return ret; try { unsigned int count=port->getPortCount(); - logD("got port count.\n"); + logD("got port count."); for (unsigned int i=0; igetPortName(i); if (name!="") ret.push_back(name); } } catch (RtMidiError& e) { - logW("could not get MIDI inputs! %s\n",e.what()); + logW("could not get MIDI inputs! %s",e.what()); } return ret; } @@ -78,10 +78,10 @@ bool TAMidiInRtMidi::openDevice(String name) { } } isOpen=portOpen; - if (!portOpen) logW("could not find MIDI in device...\n"); + if (!portOpen) logW("could not find MIDI in device..."); return portOpen; } catch (RtMidiError& e) { - logW("could not open MIDI in device! %s\n",e.what()); + logW("could not open MIDI in device! %s",e.what()); return false; } return true; @@ -93,7 +93,7 @@ bool TAMidiInRtMidi::closeDevice() { try { port->closePort(); } catch (RtMidiError& e) { - logW("could not close MIDI in device! %s\n",e.what()); + logW("could not close MIDI in device! %s",e.what()); isOpen=false; // still return false; } @@ -106,7 +106,7 @@ bool TAMidiInRtMidi::init() { try { port=new RtMidiIn; } catch (RtMidiError& e) { - logW("could not initialize RtMidi in! %s\n",e.what()); + logW("could not initialize RtMidi in! %s",e.what()); return false; } return true; @@ -176,10 +176,10 @@ bool TAMidiOutRtMidi::openDevice(String name) { } } isOpen=portOpen; - if (!portOpen) logW("could not find MIDI out device...\n"); + if (!portOpen) logW("could not find MIDI out device..."); return portOpen; } catch (RtMidiError& e) { - logW("could not open MIDI out device! %s\n",e.what()); + logW("could not open MIDI out device! %s",e.what()); return false; } return true; @@ -191,7 +191,7 @@ bool TAMidiOutRtMidi::closeDevice() { try { port->closePort(); } catch (RtMidiError& e) { - logW("could not close MIDI out device! %s\n",e.what()); + logW("could not close MIDI out device! %s",e.what()); isOpen=false; // still return false; } @@ -210,7 +210,7 @@ std::vector TAMidiOutRtMidi::listDevices() { if (name!="") ret.push_back(name); } } catch (RtMidiError& e) { - logW("could not get MIDI outputs! %s\n",e.what()); + logW("could not get MIDI outputs! %s",e.what()); } return ret; } @@ -220,7 +220,7 @@ bool TAMidiOutRtMidi::init() { try { port=new RtMidiOut; } catch (RtMidiError& e) { - logW("could not initialize RtMidi out! %s\n",e.what()); + logW("could not initialize RtMidi out! %s",e.what()); return false; } return true; diff --git a/src/audio/sdl.cpp b/src/audio/sdl.cpp index 7fbbceb5..3ef38d4f 100644 --- a/src/audio/sdl.cpp +++ b/src/audio/sdl.cpp @@ -75,7 +75,7 @@ std::vector TAAudioSDL::listAudioDevices() { std::vector ret; if (!audioSysStarted) { if (SDL_Init(SDL_INIT_AUDIO)<0) { - logE("could not initialize SDL to list audio devices\n"); + logE("could not initialize SDL to list audio devices"); } else { audioSysStarted=true; } @@ -96,12 +96,12 @@ std::vector TAAudioSDL::listAudioDevices() { bool TAAudioSDL::init(TAAudioDesc& request, TAAudioDesc& response) { if (initialized) { - logE("audio already initialized\n"); + logE("audio already initialized"); return false; } if (!audioSysStarted) { if (SDL_Init(SDL_INIT_AUDIO)<0) { - logE("could not initialize SDL\n"); + logE("could not initialize SDL"); return false; } audioSysStarted=true; @@ -119,7 +119,7 @@ bool TAAudioSDL::init(TAAudioDesc& request, TAAudioDesc& response) { ai=SDL_OpenAudioDevice(request.deviceName.empty()?NULL:request.deviceName.c_str(),0,&ac,&ar,SDL_AUDIO_ALLOW_FREQUENCY_CHANGE); if (ai==0) { - logE("could not open audio device: %s\n",SDL_GetError()); + logE("could not open audio device: %s",SDL_GetError()); return false; } diff --git a/src/engine/config.cpp b/src/engine/config.cpp index f7444e3c..92866a9f 100644 --- a/src/engine/config.cpp +++ b/src/engine/config.cpp @@ -32,13 +32,13 @@ bool DivEngine::saveConf() { configFile=configPath+String(CONFIG_FILE); FILE* f=ps_fopen(configFile.c_str(),"wb"); if (f==NULL) { - logW("could not write config file! %s\n",strerror(errno)); + logW("could not write config file! %s",strerror(errno)); return false; } for (auto& i: conf) { String toWrite=fmt::sprintf("%s=%s\n",i.first,i.second); if (fwrite(toWrite.c_str(),1,toWrite.size(),f)!=toWrite.size()) { - logW("could not write config file! %s\n",strerror(errno)); + logW("could not write config file! %s",strerror(errno)); fclose(f); return false; } @@ -52,10 +52,10 @@ bool DivEngine::loadConf() { configFile=configPath+String(CONFIG_FILE); FILE* f=ps_fopen(configFile.c_str(),"rb"); if (f==NULL) { - logI("creating default config.\n"); + logI("creating default config."); return saveConf(); } - logI("loading config.\n"); + logI("loading config."); while (!feof(f)) { String key=""; String value=""; diff --git a/src/engine/dispatchContainer.cpp b/src/engine/dispatchContainer.cpp index c89a0fa0..4f4ecf39 100644 --- a/src/engine/dispatchContainer.cpp +++ b/src/engine/dispatchContainer.cpp @@ -148,13 +148,13 @@ void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, do bb[0]=blip_new(32768); if (bb[0]==NULL) { - logE("not enough memory!\n"); + logE("not enough memory!"); return; } bb[1]=blip_new(32768); if (bb[1]==NULL) { - logE("not enough memory!\n"); + logE("not enough memory!"); return; } @@ -312,7 +312,7 @@ void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, do dispatch=new DivPlatformMMC5; break; default: - logW("this system is not supported yet! using dummy platform.\n"); + logW("this system is not supported yet! using dummy platform."); dispatch=new DivPlatformDummy; break; } diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index fbafb668..690ee993 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -193,7 +193,7 @@ void DivEngine::runExportThread() { sf=sf_open(exportPath.c_str(),SFM_WRITE,&si); if (sf==NULL) { - logE("could not open file for writing! (%s)\n",sf_strerror(NULL)); + logE("could not open file for writing! (%s)",sf_strerror(NULL)); exporting=false; return; } @@ -207,7 +207,7 @@ void DivEngine::runExportThread() { deinitAudioBackend(); playSub(false); - logI("rendering to file...\n"); + logI("rendering to file..."); while (playing) { nextBuf(NULL,outBuf,0,2,EXPORT_BUFSIZE); @@ -216,10 +216,10 @@ void DivEngine::runExportThread() { outBuf[2][1+(i<<1)]=MAX(-1.0f,MIN(1.0f,outBuf[1][i])); } if (totalProcessed>EXPORT_BUFSIZE) { - logE("error: total processed is bigger than export bufsize! %d>%d\n",totalProcessed,EXPORT_BUFSIZE); + logE("error: total processed is bigger than export bufsize! %d>%d",totalProcessed,EXPORT_BUFSIZE); } if (sf_writef_float(sf,outBuf[2],totalProcessed)!=(int)totalProcessed) { - logE("error: failed to write entire buffer!\n"); + logE("error: failed to write entire buffer!"); break; } } @@ -229,7 +229,7 @@ void DivEngine::runExportThread() { delete[] outBuf[2]; if (sf_close(sf)!=0) { - logE("could not close audio file!\n"); + logE("could not close audio file!"); } exporting=false; @@ -239,10 +239,10 @@ void DivEngine::runExportThread() { disCont[i].setQuality(lowQuality); } if (!output->setRun(true)) { - logE("error while activating audio!\n"); + logE("error while activating audio!"); } } - logI("done!\n"); + logI("done!"); break; } case DIV_EXPORT_MODE_MANY_SYS: { @@ -262,10 +262,10 @@ void DivEngine::runExportThread() { for (int i=0; iEXPORT_BUFSIZE) { - logE("error: total processed is bigger than export bufsize! (%d) %d>%d\n",i,totalProcessed,EXPORT_BUFSIZE); + logE("error: total processed is bigger than export bufsize! (%d) %d>%d",i,totalProcessed,EXPORT_BUFSIZE); } if (sf_writef_short(sf[i],sysBuf,totalProcessed)!=(int)totalProcessed) { - logE("error: failed to write entire buffer! (%d)\n",i); + logE("error: failed to write entire buffer! (%d)",i); break; } } @@ -311,7 +311,7 @@ void DivEngine::runExportThread() { for (int i=0; isetRun(true)) { - logE("error while activating audio!\n"); + logE("error while activating audio!"); } } - logI("done!\n"); + logI("done!"); break; } case DIV_EXPORT_MODE_MANY_CHAN: { @@ -338,20 +338,20 @@ void DivEngine::runExportThread() { outBuf[2]=new float[EXPORT_BUFSIZE*2]; int loopCount=remainingLoops; - logI("rendering to files...\n"); + logI("rendering to files..."); for (int i=0; iEXPORT_BUFSIZE) { - logE("error: total processed is bigger than export bufsize! %d>%d\n",totalProcessed,EXPORT_BUFSIZE); + logE("error: total processed is bigger than export bufsize! %d>%d",totalProcessed,EXPORT_BUFSIZE); } if (sf_writef_float(sf,outBuf[2],totalProcessed)!=(int)totalProcessed) { - logE("error: failed to write entire buffer!\n"); + logE("error: failed to write entire buffer!"); break; } } if (sf_close(sf)!=0) { - logE("could not close audio file!\n"); + logE("could not close audio file!"); } } exporting=false; @@ -405,10 +405,10 @@ void DivEngine::runExportThread() { disCont[i].setQuality(lowQuality); } if (!output->setRun(true)) { - logE("error while activating audio!\n"); + logE("error while activating audio!"); } } - logI("done!\n"); + logI("done!"); break; } } @@ -479,12 +479,12 @@ void DivEngine::renderSamples() { memPos=(memPos+0xfffff)&0xf00000; } if (memPos>=16777216) { - logW("out of ADPCM-A memory for sample %d!\n",i); + logW("out of ADPCM-A memory for sample %d!",i); break; } if (memPos+paddedLen>=16777216) { memcpy(adpcmAMem+memPos,s->dataA,16777216-memPos); - logW("out of ADPCM-A memory for sample %d!\n",i); + logW("out of ADPCM-A memory for sample %d!",i); } else { memcpy(adpcmAMem+memPos,s->dataA,paddedLen); } @@ -504,12 +504,12 @@ void DivEngine::renderSamples() { memPos=(memPos+0xfffff)&0xf00000; } if (memPos>=16777216) { - logW("out of ADPCM-B memory for sample %d!\n",i); + logW("out of ADPCM-B memory for sample %d!",i); break; } if (memPos+paddedLen>=16777216) { memcpy(adpcmBMem+memPos,s->dataB,16777216-memPos); - logW("out of ADPCM-B memory for sample %d!\n",i); + logW("out of ADPCM-B memory for sample %d!",i); } else { memcpy(adpcmBMem+memPos,s->dataB,paddedLen); } @@ -533,14 +533,14 @@ void DivEngine::renderSamples() { memPos=(memPos+0xffff)&0xff0000; } if (memPos>=16777216) { - logW("out of QSound PCM memory for sample %d!\n",i); + logW("out of QSound PCM memory for sample %d!",i); break; } if (memPos+length>=16777216) { for (unsigned int i=0; i<16777216-(memPos+length); i++) { qsoundMem[(memPos+i)^0x8000]=s->data8[i]; } - logW("out of QSound PCM memory for sample %d!\n",i); + logW("out of QSound PCM memory for sample %d!",i); } else { for (int i=0; idata8[i]; @@ -567,12 +567,12 @@ void DivEngine::renderSamples() { memPos=(memPos+0x1ffff)&0xfe0000; } if (memPos>=1048576) { - logW("out of X1-010 memory for sample %d!\n",i); + logW("out of X1-010 memory for sample %d!",i); break; } if (memPos+paddedLen>=1048576) { memcpy(x1_010Mem+memPos,s->data8,1048576-memPos); - logW("out of X1-010 memory for sample %d!\n",i); + logW("out of X1-010 memory for sample %d!",i); } else { memcpy(x1_010Mem+memPos,s->data8,paddedLen); } @@ -824,7 +824,7 @@ void DivEngine::playSub(bool preserveDrift, int goalRow) { skipping=false; cmdStream.clear(); std::chrono::high_resolution_clock::time_point timeEnd=std::chrono::high_resolution_clock::now(); - logV("playSub() tool %dµs\n",std::chrono::duration_cast(timeEnd-timeStart).count()); + logV("playSub() tool %dµs",std::chrono::duration_cast(timeEnd-timeStart).count()); } /* @@ -1346,7 +1346,7 @@ bool DivEngine::addWaveFromFile(const char* path) { } buf=new unsigned char[len]; if (fread(buf,1,len,f)!=(size_t)len) { - logW("did not read entire wavetable file buffer!\n"); + logW("did not read entire wavetable file buffer!"); delete[] buf; return false; } @@ -1386,22 +1386,22 @@ bool DivEngine::addWaveFromFile(const char* path) { wave->max=(unsigned char)reader.readC(); if (wave->max==255) { // new wavetable format unsigned char waveVersion=reader.readC(); - logI("reading modern .dmw...\n"); - logD("wave version %d\n",waveVersion); + logI("reading modern .dmw..."); + logD("wave version %d",waveVersion); wave->max=reader.readC(); for (int i=0; idata[i]=reader.readI(); } } else if (reader.size()==(size_t)(len+5)) { // read as .dmw - logI("reading .dmw...\n"); + logI("reading .dmw..."); if (len>256) len=256; for (int i=0; idata[i]=(unsigned char)reader.readC(); } } else { // read as binary - logI("reading binary...\n"); + logI("reading binary..."); len=reader.size(); if (len>256) len=256; reader.seek(0,SEEK_SET); @@ -1414,7 +1414,7 @@ bool DivEngine::addWaveFromFile(const char* path) { } catch (EndOfFileException& e) { // read as binary len=reader.size(); - logI("reading binary for being too small...\n"); + logI("reading binary for being too small..."); if (len>256) len=256; reader.seek(0,SEEK_SET); for (int i=0; idata,oldPat->data,256*32*sizeof(short)); - logD("found at %d\n",j); + logD("found at %d",j); didNotFind=false; break; } @@ -1953,7 +1953,7 @@ bool DivEngine::switchMaster() { disCont[i].setQuality(lowQuality); } if (!output->setRun(true)) { - logE("error while activating audio!\n"); + logE("error while activating audio!"); return false; } } else { @@ -2071,9 +2071,9 @@ void DivEngine::quitDispatch() { #define CHECK_CONFIG_DIR_MAC() \ configPath+="/Library/Application Support/Furnace"; \ if (stat(configPath.c_str(),&st)<0) { \ - logI("creating config dir...\n"); \ + logI("creating config dir..."); \ if (mkdir(configPath.c_str(),0755)<0) { \ - logW("could not make config dir! (%s)\n",strerror(errno)); \ + logW("could not make config dir! (%s)",strerror(errno)); \ configPath="."; \ } \ } @@ -2081,18 +2081,18 @@ void DivEngine::quitDispatch() { #define CHECK_CONFIG_DIR() \ configPath+="/.config"; \ if (stat(configPath.c_str(),&st)<0) { \ - logI("creating user config dir...\n"); \ + logI("creating user config dir..."); \ if (mkdir(configPath.c_str(),0755)<0) { \ - logW("could not make user config dir! (%s)\n",strerror(errno)); \ + logW("could not make user config dir! (%s)",strerror(errno)); \ configPath="."; \ } \ } \ if (configPath!=".") { \ configPath+="/furnace"; \ if (stat(configPath.c_str(),&st)<0) { \ - logI("creating config dir...\n"); \ + logI("creating config dir..."); \ if (mkdir(configPath.c_str(),0755)<0) { \ - logW("could not make config dir! (%s)\n",strerror(errno)); \ + logW("could not make config dir! (%s)",strerror(errno)); \ configPath="."; \ } \ } \ @@ -2114,7 +2114,7 @@ bool DivEngine::initAudioBackend() { switch (audioEngine) { case DIV_AUDIO_JACK: #ifndef HAVE_JACK - logE("Furnace was not compiled with JACK support!\n"); + logE("Furnace was not compiled with JACK support!"); setConf("audioEngine","SDL"); saveConf(); output=new TAAudioSDL; @@ -2129,7 +2129,7 @@ bool DivEngine::initAudioBackend() { output=new TAAudio; break; default: - logE("invalid audio engine!\n"); + logE("invalid audio engine!"); return false; } @@ -2147,7 +2147,7 @@ bool DivEngine::initAudioBackend() { output->setCallback(process,this); if (!output->init(want,got)) { - logE("error while initializing audio!\n"); + logE("error while initializing audio!"); delete output; output=NULL; audioEngine=DIV_AUDIO_NULL; @@ -2158,15 +2158,15 @@ bool DivEngine::initAudioBackend() { midiIns=output->midiIn->listDevices(); midiOuts=output->midiOut->listDevices(); } else { - logW("error while initializing MIDI!\n"); + logW("error while initializing MIDI!"); } if (output->midiIn) { String inName=getConfString("midiInDevice",""); if (!inName.empty()) { // try opening device - logI("opening MIDI input.\n"); + logI("opening MIDI input."); if (!output->midiIn->openDevice(inName)) { - logW("could not open MIDI input device!\n"); + logW("could not open MIDI input device!"); } } } @@ -2174,9 +2174,9 @@ bool DivEngine::initAudioBackend() { String outName=getConfString("midiOutDevice",""); if (!outName.empty()) { // try opening device - logI("opening MIDI output.\n"); + logI("opening MIDI output."); if (!output->midiOut->openDevice(outName)) { - logW("could not open MIDI output device!\n"); + logW("could not open MIDI output device!"); } } } @@ -2188,13 +2188,13 @@ bool DivEngine::deinitAudioBackend() { if (output!=NULL) { if (output->midiIn) { if (output->midiIn->isDeviceOpen()) { - logI("closing MIDI input.\n"); + logI("closing MIDI input."); output->midiIn->closeDevice(); } } if (output->midiOut) { if (output->midiOut->isDeviceOpen()) { - logI("closing MIDI output.\n"); + logI("closing MIDI output."); output->midiOut->closeDevice(); } } @@ -2222,7 +2222,7 @@ bool DivEngine::init() { int uid=getuid(); struct passwd* entry=getpwuid(uid); if (entry==NULL) { - logW("unable to determine config directory! (%s)\n",strerror(errno)); + logW("unable to determine config directory! (%s)",strerror(errno)); configPath="."; } else { configPath=entry->pw_dir; @@ -2241,21 +2241,21 @@ bool DivEngine::init() { #endif } #endif - logD("config path: %s\n",configPath.c_str()); + logD("config path: %s",configPath.c_str()); loadConf(); // init the rest of engine bool haveAudio=false; if (!initAudioBackend()) { - logE("no audio output available!\n"); + logE("no audio output available!"); } else { haveAudio=true; } samp_bb=blip_new(32768); if (samp_bb==NULL) { - logE("not enough memory!\n"); + logE("not enough memory!"); return false; } @@ -2290,7 +2290,7 @@ bool DivEngine::init() { return false; } else { if (!output->setRun(true)) { - logE("error while activating!\n"); + logE("error while activating!"); return false; } } @@ -2300,7 +2300,7 @@ bool DivEngine::init() { bool DivEngine::quit() { deinitAudioBackend(); quitDispatch(); - logI("saving config.\n"); + logI("saving config."); saveConf(); active=false; delete[] oscBuf[0]; diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index eb5e31e4..8514d91a 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -62,15 +62,15 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { ds.isDMF=true; if (!reader.seek(16,SEEK_SET)) { - logE("premature end of file!\n"); + logE("premature end of file!"); lastError="incomplete file"; delete[] file; return false; } ds.version=(unsigned char)reader.readC(); - logI("module version %d (0x%.2x)\n",ds.version,ds.version); + logI("module version %d (0x%.2x)",ds.version,ds.version); if (ds.version>0x1a) { - logE("this version is not supported by Furnace yet!\n"); + logE("this version is not supported by Furnace yet!"); lastError="this version is not supported by Furnace yet"; delete[] file; return false; @@ -106,23 +106,23 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { ds.manInfo=reader.readString((unsigned char)reader.readC()); ds.createdDate=reader.readString((unsigned char)reader.readC()); ds.revisionDate=reader.readString((unsigned char)reader.readC()); - logI("%s by %s\n",ds.name.c_str(),ds.author.c_str()); - logI("has YMU-specific data:\n"); - logI("- carrier: %s\n",ds.carrier.c_str()); - logI("- category: %s\n",ds.category.c_str()); - logI("- vendor: %s\n",ds.vendor.c_str()); - logI("- writer: %s\n",ds.writer.c_str()); - logI("- composer: %s\n",ds.composer.c_str()); - logI("- arranger: %s\n",ds.arranger.c_str()); - logI("- copyright: %s\n",ds.copyright.c_str()); - logI("- management group: %s\n",ds.manGroup.c_str()); - logI("- management info: %s\n",ds.manInfo.c_str()); - logI("- created on: %s\n",ds.createdDate.c_str()); - logI("- revision date: %s\n",ds.revisionDate.c_str()); + logI("%s by %s",ds.name.c_str(),ds.author.c_str()); + logI("has YMU-specific data:"); + logI("- carrier: %s",ds.carrier.c_str()); + logI("- category: %s",ds.category.c_str()); + logI("- vendor: %s",ds.vendor.c_str()); + logI("- writer: %s",ds.writer.c_str()); + logI("- composer: %s",ds.composer.c_str()); + logI("- arranger: %s",ds.arranger.c_str()); + logI("- copyright: %s",ds.copyright.c_str()); + logI("- management group: %s",ds.manGroup.c_str()); + logI("- management info: %s",ds.manInfo.c_str()); + logI("- created on: %s",ds.createdDate.c_str()); + logI("- revision date: %s",ds.revisionDate.c_str()); } else { ds.name=reader.readString((unsigned char)reader.readC()); ds.author=reader.readString((unsigned char)reader.readC()); - logI("%s by %s\n",ds.name.c_str(),ds.author.c_str()); + logI("%s by %s",ds.name.c_str(),ds.author.c_str()); } // compatibility flags @@ -164,7 +164,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { ds.tuning=443.23; } - logI("reading module data...\n"); + logI("reading module data..."); if (ds.version>0x0c) { ds.hilightA=reader.readC(); ds.hilightB=reader.readC(); @@ -186,7 +186,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { try { ds.hz=std::stoi(hz); } catch (std::exception& e) { - logW("invalid custom Hz!\n"); + logW("invalid custom Hz!"); ds.hz=60; } } @@ -199,25 +199,25 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { ds.ordersLen=(unsigned char)reader.readC(); if (ds.patLen<0) { - logE("pattern length is negative!\n"); + logE("pattern length is negative!"); lastError="pattern lengrh is negative!"; delete[] file; return false; } if (ds.patLen>256) { - logE("pattern length is too large!\n"); + logE("pattern length is too large!"); lastError="pattern length is too large!"; delete[] file; return false; } if (ds.ordersLen<0) { - logE("song length is negative!\n"); + logE("song length is negative!"); lastError="song length is negative!"; delete[] file; return false; } if (ds.ordersLen>127) { - logE("song is too long!\n"); + logE("song is too long!"); lastError="song is too long!"; delete[] file; return false; @@ -258,12 +258,12 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { addWarning("Yamaha YMU759 emulation is incomplete! please migrate your song to the OPL3 system."); } - logI("reading pattern matrix (%d)...\n",ds.ordersLen); + logI("reading pattern matrix (%d)...",ds.ordersLen); for (int i=0; i0x7f) { - logE("order at %d, %d out of range! (%d)\n",i,j,ds.orders.ord[i][j]); + logE("order at %d, %d out of range! (%d)",i,j,ds.orders.ord[i][j]); lastError=fmt::sprintf("order at %d, %d out of range! (%d)",i,j,ds.orders.ord[i][j]); delete[] file; return false; @@ -279,19 +279,19 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { } else { ds.insLen=16; } - logI("reading instruments (%d)...\n",ds.insLen); + logI("reading instruments (%d)...",ds.insLen); for (int i=0; i0x03) { ins->name=reader.readString((unsigned char)reader.readC()); } - logD("%d name: %s\n",i,ins->name.c_str()); + logD("%d name: %s",i,ins->name.c_str()); if (ds.version<0x0b) { // instruments in ancient versions were all FM or STD. ins->mode=1; } else { unsigned char mode=reader.readC(); - if (mode>1) logW("%d: invalid instrument mode %d!\n",i,mode); + if (mode>1) logW("%d: invalid instrument mode %d!",i,mode); ins->mode=mode; } ins->type=ins->mode?DIV_INS_FM:DIV_INS_STD; @@ -336,7 +336,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { ins->fm.ops=4; } if (ins->fm.ops!=2 && ins->fm.ops!=4) { - logE("invalid op count %d. did we read it wrong?\n",ins->fm.ops); + logE("invalid op count %d. did we read it wrong?",ins->fm.ops); lastError="file is corrupt or unreadable at operators"; delete[] file; return false; @@ -399,7 +399,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { } } - logD("OP%d: AM %d AR %d DAM %d DR %d DVB %d EGT %d KSL %d MULT %d RR %d SL %d SUS %d TL %d VIB %d WS %d RS %d DT %d D2R %d SSG-EG %d\n",j, + logD("OP%d: AM %d AR %d DAM %d DR %d DVB %d EGT %d KSL %d MULT %d RR %d SL %d SUS %d TL %d VIB %d WS %d RS %d DT %d D2R %d SSG-EG %d",j, ins->fm.op[j].am, ins->fm.op[j].ar, ins->fm.op[j].dam, @@ -532,7 +532,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { ins->gb.soundLen=reader.readC(); ins->std.volMacro.open=false; - logD("GB data: vol %d dir %d len %d sl %d\n",ins->gb.envVol,ins->gb.envDir,ins->gb.envLen,ins->gb.soundLen); + logD("GB data: vol %d dir %d len %d sl %d",ins->gb.envVol,ins->gb.envDir,ins->gb.envLen,ins->gb.soundLen); } else if (ds.system[0]==DIV_SYSTEM_GB) { // try to convert macro to envelope if (ins->std.volMacro.len>0) { @@ -553,7 +553,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { if (ds.version>0x0b) { ds.waveLen=(unsigned char)reader.readC(); - logI("reading wavetables (%d)...\n",ds.waveLen); + logI("reading wavetables (%d)...",ds.waveLen); for (int i=0; ilen=(unsigned char)reader.readI(); @@ -564,12 +564,12 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { wave->max=63; } if (wave->len>65) { - logE("invalid wave length %d. are we doing something wrong?\n",wave->len); + logE("invalid wave length %d. are we doing something wrong?",wave->len); lastError="file is corrupt or unreadable at wavetables"; delete[] file; return false; } - logD("%d length %d\n",i,wave->len); + logD("%d length %d",i,wave->len); for (int j=0; jlen; j++) { if (ds.version<0x0e) { wave->data[j]=reader.readC(); @@ -588,7 +588,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { } } - logI("reading patterns (%d channels, %d orders)...\n",getChannelCount(ds.system[0]),ds.ordersLen); + logI("reading patterns (%d channels, %d orders)...",getChannelCount(ds.system[0]),ds.ordersLen); for (int i=0; i4 || chan.effectRows<1) { - logE("invalid effect row count %d. are you sure everything is ok?\n",chan.effectRows); + logE("invalid effect row count %d. are you sure everything is ok?",chan.effectRows); lastError="file is corrupt or unreadable at effect rows"; delete[] file; return false; @@ -629,7 +629,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { pat->data[k][1]+=2; } if (pat->data[k][0]==0 && pat->data[k][1]!=0) { - logD("what? %d:%d:%d note %d octave %d\n",i,j,k,pat->data[k][0],pat->data[k][1]); + logD("what? %d:%d:%d note %d octave %d",i,j,k,pat->data[k][0],pat->data[k][1]); pat->data[k][0]=12; pat->data[k][1]--; } @@ -676,7 +676,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { } ds.sampleLen=(unsigned char)reader.readC(); - logI("reading samples (%d)...\n",ds.sampleLen); + logI("reading samples (%d)...",ds.sampleLen); if (ds.version<0x0b && ds.sampleLen>0) { // TODO what is this for? reader.readC(); } @@ -687,7 +687,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { int vol=50; short* data; if (length<0) { - logE("invalid sample length %d. are we doing something wrong?\n",length); + logE("invalid sample length %d. are we doing something wrong?",length); lastError="file is corrupt or unreadable at samples"; delete[] file; return false; @@ -697,7 +697,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { } else { sample->name=""; } - logD("%d name %s (%d)\n",i,sample->name.c_str(),length); + logD("%d name %s (%d)",i,sample->name.c_str(),length); sample->rate=22050; if (ds.version>=0x0b) { sample->rate=fileToDivRate(reader.readC()); @@ -707,7 +707,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { if (ds.version>0x15) { sample->depth=reader.readC(); if (sample->depth!=8 && sample->depth!=16) { - logW("%d: sample depth is wrong! (%d)\n",i,sample->depth); + logW("%d: sample depth is wrong! (%d)",i,sample->depth); sample->depth=16; } } else { @@ -724,12 +724,12 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { } if (pitch!=5) { - logD("%d: scaling from %d...\n",i,pitch); + logD("%d: scaling from %d...",i,pitch); } // render data if (!sample->init((double)length/samplePitches[pitch])) { - logE("%d: error while initializing sample!\n",i); + logE("%d: error while initializing sample!",i); } unsigned int k=0; @@ -754,7 +754,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { if (reader.tell()DIV_ENGINE_VERSION) { - logW("this module was created with a more recent version of Furnace!\n"); + logW("this module was created with a more recent version of Furnace!"); addWarning("this module was created with a more recent version of Furnace!"); } @@ -903,7 +903,7 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { int infoSeek=reader.readI(); if (!reader.seek(infoSeek,SEEK_SET)) { - logE("couldn't seek to info header at %d!\n",infoSeek); + logE("couldn't seek to info header at %d!",infoSeek); lastError="couldn't seek to info header!"; delete[] file; return false; @@ -912,7 +912,7 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { // read header reader.read(magic,4); if (strcmp(magic,"INFO")!=0) { - logE("invalid info header!\n"); + logE("invalid info header!"); lastError="invalid info header!"; delete[] file; return false; @@ -939,49 +939,49 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { int numberOfPats=reader.readI(); if (ds.patLen<0) { - logE("pattern length is negative!\n"); + logE("pattern length is negative!"); lastError="pattern lengrh is negative!"; delete[] file; return false; } if (ds.patLen>256) { - logE("pattern length is too large!\n"); + logE("pattern length is too large!"); lastError="pattern length is too large!"; delete[] file; return false; } if (ds.ordersLen<0) { - logE("song length is negative!\n"); + logE("song length is negative!"); lastError="song length is negative!"; delete[] file; return false; } if (ds.ordersLen>256) { - logE("song is too long!\n"); + logE("song is too long!"); lastError="song is too long!"; delete[] file; return false; } if (ds.insLen<0 || ds.insLen>256) { - logE("invalid instrument count!\n"); + logE("invalid instrument count!"); lastError="invalid instrument count!"; delete[] file; return false; } if (ds.waveLen<0 || ds.waveLen>256) { - logE("invalid wavetable count!\n"); + logE("invalid wavetable count!"); lastError="invalid wavetable count!"; delete[] file; return false; } if (ds.sampleLen<0 || ds.sampleLen>256) { - logE("invalid sample count!\n"); + logE("invalid sample count!"); lastError="invalid sample count!"; delete[] file; return false; } if (numberOfPats<0) { - logE("invalid pattern count!\n"); + logE("invalid pattern count!"); lastError="invalid pattern count!"; delete[] file; return false; @@ -991,7 +991,7 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { unsigned char sysID=reader.readC(); ds.system[i]=systemFromFileFur(sysID); if (sysID!=0 && systemToFileFur(ds.system[i])==0) { - logE("unrecognized system ID %.2x\n",ds.system[i]); + logE("unrecognized system ID %.2x",ds.system[i]); lastError=fmt::sprintf("unrecognized system ID %.2x!",ds.system[i]); delete[] file; return false; @@ -1004,7 +1004,7 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { } if (tchans>DIV_MAX_CHANS) { tchans=DIV_MAX_CHANS; - logW("too many channels!\n"); + logW("too many channels!"); } // system volume @@ -1061,7 +1061,7 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { ds.name=reader.readString(); ds.author=reader.readString(); - logI("%s by %s\n",ds.name.c_str(),ds.author.c_str()); + logI("%s by %s",ds.name.c_str(),ds.author.c_str()); if (ds.version>=33) { ds.tuning=reader.readF(); @@ -1167,7 +1167,7 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { reader.read(samplePtr,ds.sampleLen*4); for (int i=0; i8) { - logE("channel %d has zero or too many effect columns! (%d)\n",i,ds.pat[i].effectRows); + logE("channel %d has zero or too many effect columns! (%d)",i,ds.pat[i].effectRows); lastError=fmt::sprintf("channel %d has too many effect columns! (%d)",i,ds.pat[i].effectRows); delete[] file; return false; @@ -1242,9 +1242,9 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { // read instruments for (int i=0; iname=reader.readString(); sample->samples=reader.readI(); @@ -1348,12 +1348,12 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { reader.read(data,2*length); if (pitch!=5) { - logD("%d: scaling from %d...\n",i,pitch); + logD("%d: scaling from %d...",i,pitch); } // render data if (sample->depth!=8 && sample->depth!=16) { - logW("%d: sample depth is wrong! (%d)\n",i,sample->depth); + logW("%d: sample depth is wrong! (%d)",i,sample->depth); sample->depth=16; } sample->samples=(double)sample->samples/samplePitches[pitch]; @@ -1383,16 +1383,16 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { // read patterns for (int i: patPtr) { if (!reader.seek(i,SEEK_SET)) { - logE("couldn't seek to pattern in %x!\n",i); + logE("couldn't seek to pattern in %x!",i); lastError=fmt::sprintf("couldn't seek to pattern in %x!",i); ds.unload(); delete[] file; return false; } reader.read(magic,4); - logD("reading pattern in %x...\n",i); + logD("reading pattern in %x...",i); if (strcmp(magic,"PATR")!=0) { - logE("%x: invalid pattern header!\n",i); + logE("%x: invalid pattern header!",i); lastError="invalid pattern header!"; ds.unload(); delete[] file; @@ -1404,17 +1404,17 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { int index=reader.readS(); reader.readI(); - logD("- %d, %d\n",chan,index); + logD("- %d, %d",chan,index); if (chan<0 || chan>=tchans) { - logE("pattern channel out of range!\n",i); + logE("pattern channel out of range!",i); lastError="pattern channel out of range!"; ds.unload(); delete[] file; return false; } if (index<0 || index>255) { - logE("pattern index out of range!\n",i); + logE("pattern index out of range!",i); lastError="pattern index out of range!"; ds.unload(); delete[] file; @@ -1440,7 +1440,7 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { if (reader.tell()='1' && magic[0]<='9') { - logD("detected a FastTracker module\n"); + logD("detected a FastTracker module"); chCount=magic[0]-'0'; } else if (memcmp(magic,"FLT",3)==0 && magic[3]>='1' && magic[3]<='9') { - logD("detected a Fairlight module\n"); + logD("detected a Fairlight module"); chCount=magic[3]-'0'; } else if (memcmp(magic,"TDZ",3)==0 && magic[3]>='1' && magic[3]<='9') { - logD("detected a TakeTracker module\n"); + logD("detected a TakeTracker module"); chCount=magic[3]-'0'; } else if ((memcmp(magic+2,"CH",2)==0 || memcmp(magic+2,"CN",2)==0) && (magic[0]>='1' && magic[0]<='9' && magic[1]>='0' && magic[1]<='9')) { - logD("detected a Fast/TakeTracker module\n"); + logD("detected a Fast/TakeTracker module"); chCount=((magic[0]-'0')*10)+(magic[1]-'0'); } else { // TODO: Soundtracker MOD? @@ -1832,10 +1832,10 @@ bool DivEngine::loadMod(unsigned char* file, size_t len) { } success=true; } catch (EndOfFileException& e) { - //logE("premature end of file!\n"); + //logE("premature end of file!"); lastError="incomplete file"; } catch (InvalidHeaderException& e) { - //logE("invalid info header!\n"); + //logE("invalid info header!"); lastError="invalid info header!"; } return success; @@ -1853,14 +1853,14 @@ bool DivEngine::load(unsigned char* f, size_t slen) { if (memcmp(f,DIV_DMF_MAGIC,16)!=0 && memcmp(f,DIV_FUR_MAGIC,16)!=0) { // try loading as a .mod first before trying to decompress // TODO: move to a different location? - logD("loading as .mod...\n"); + logD("loading as .mod..."); if (loadMod(f,slen)) { delete[] f; return true; } lastError="not a .mod song"; - logD("loading as zlib...\n"); + logD("loading as zlib..."); // try zlib z_stream zl; memset(&zl,0,sizeof(z_stream)); @@ -1875,9 +1875,9 @@ bool DivEngine::load(unsigned char* f, size_t slen) { nextErr=inflateInit(&zl); if (nextErr!=Z_OK) { if (zl.msg==NULL) { - logE("zlib error: unknown! %d\n",nextErr); + logE("zlib error: unknown! %d",nextErr); } else { - logE("zlib error: %s\n",zl.msg); + logE("zlib error: %s",zl.msg); } inflateEnd(&zl); delete[] f; @@ -1894,10 +1894,10 @@ bool DivEngine::load(unsigned char* f, size_t slen) { nextErr=inflate(&zl,Z_SYNC_FLUSH); if (nextErr!=Z_OK && nextErr!=Z_STREAM_END) { if (zl.msg==NULL) { - logE("zlib error: unknown error! %d\n",nextErr); + logE("zlib error: unknown error! %d",nextErr); lastError="unknown decompression error"; } else { - logE("zlib inflate: %s\n",zl.msg); + logE("zlib inflate: %s",zl.msg); lastError=fmt::sprintf("decompression error: %s",zl.msg); } for (InflateBlock* i: blocks) delete i; @@ -1916,10 +1916,10 @@ bool DivEngine::load(unsigned char* f, size_t slen) { nextErr=inflateEnd(&zl); if (nextErr!=Z_OK) { if (zl.msg==NULL) { - logE("zlib end error: unknown error! %d\n",nextErr); + logE("zlib end error: unknown error! %d",nextErr); lastError="unknown decompression finish error"; } else { - logE("zlib end: %s\n",zl.msg); + logE("zlib end: %s",zl.msg); lastError=fmt::sprintf("decompression finish error: %s",zl.msg); } for (InflateBlock* i: blocks) delete i; @@ -1934,7 +1934,7 @@ bool DivEngine::load(unsigned char* f, size_t slen) { finalSize+=i->blockSize; } if (finalSize<1) { - logE("compressed too small!\n"); + logE("compressed too small!"); lastError="file too small"; for (InflateBlock* i: blocks) delete i; blocks.clear(); @@ -1951,7 +1951,7 @@ bool DivEngine::load(unsigned char* f, size_t slen) { len=finalSize; delete[] f; } else { - logD("loading as uncompressed\n"); + logD("loading as uncompressed"); file=(unsigned char*)f; len=slen; } @@ -1960,7 +1960,7 @@ bool DivEngine::load(unsigned char* f, size_t slen) { } else if (memcmp(file,DIV_FUR_MAGIC,16)==0) { return loadFur(file,len); } - logE("not a valid module!\n"); + logE("not a valid module!"); lastError="not a compatible song"; delete[] file; return false; @@ -2227,7 +2227,7 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) { SafeWriter* DivEngine::saveDMF(unsigned char version) { // fail if version is not supported if (version<24 || version>26) { - logE("cannot save in this version!\n"); + logE("cannot save in this version!"); lastError="invalid version to save in! this is a bug!"; return NULL; } @@ -2255,60 +2255,60 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) { } // fail if more than one system if (!isFlat && song.systemLen!=1) { - logE("cannot save multiple systems in this format!\n"); + logE("cannot save multiple systems in this format!"); lastError="multiple systems not possible on .dmf"; return NULL; } // fail if this is an YMU759 song if (song.system[0]==DIV_SYSTEM_YMU759) { - logE("cannot save YMU759 song!\n"); + logE("cannot save YMU759 song!"); lastError="YMU759 song saving is not supported"; return NULL; } // fail if the system is SMS+OPLL and version<25 if (version<25 && song.system[0]==DIV_SYSTEM_SMS && song.system[1]==DIV_SYSTEM_OPLL) { - logE("Master System FM expansion not supported in 1.0/legacy .dmf!\n"); + logE("Master System FM expansion not supported in 1.0/legacy .dmf!"); lastError="Master System FM expansion not supported in 1.0/legacy .dmf!"; return NULL; } // fail if the system is NES+VRC7 and version<25 if (version<25 && song.system[0]==DIV_SYSTEM_NES && song.system[1]==DIV_SYSTEM_VRC7) { - logE("NES + VRC7 not supported in 1.0/legacy .dmf!\n"); + logE("NES + VRC7 not supported in 1.0/legacy .dmf!"); lastError="NES + VRC7 not supported in 1.0/legacy .dmf!"; return NULL; } // fail if the system is FDS and version<25 if (version<25 && song.system[0]==DIV_SYSTEM_NES && song.system[1]==DIV_SYSTEM_FDS) { - logE("FDS not supported in 1.0/legacy .dmf!\n"); + logE("FDS not supported in 1.0/legacy .dmf!"); lastError="FDS not supported in 1.0/legacy .dmf!"; return NULL; } // fail if the system is Furnace-exclusive if (!isFlat && systemToFileDMF(song.system[0])==0) { - logE("cannot save Furnace-exclusive system song!\n"); + logE("cannot save Furnace-exclusive system song!"); lastError="this system is not possible on .dmf"; return NULL; } // fail if values are out of range if (song.ordersLen>127) { - logE("maximum .dmf song length is 127!\n"); + logE("maximum .dmf song length is 127!"); lastError="maximum .dmf song length is 127"; return NULL; } if (song.ins.size()>128) { - logE("maximum number of instruments in .dmf is 128!\n"); + logE("maximum number of instruments in .dmf is 128!"); lastError="maximum number of instruments in .dmf is 128"; return NULL; } if (song.wave.size()>64) { - logE("maximum number of wavetables in .dmf is 64!\n"); + logE("maximum number of wavetables in .dmf is 64!"); lastError="maximum number of wavetables in .dmf is 64"; return NULL; } for (int i=0; i0x7f) { - logE("order %d, %d is out of range (0-127)!\n",song.orders.ord[i][j]); + logE("order %d, %d is out of range (0-127)!",song.orders.ord[i][j]); lastError=fmt::sprintf("order %d, %d is out of range (0-127)",song.orders.ord[i][j]); return NULL; } @@ -2486,7 +2486,7 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) { w->writeC(i->c64.s); w->writeC(i->c64.r); - logW("duty and cutoff precision will be lost!\n"); + logW("duty and cutoff precision will be lost!"); w->writeC((i->c64.duty*100)/4095); w->writeC(i->c64.ringMod); diff --git a/src/engine/fileOpsIns.cpp b/src/engine/fileOpsIns.cpp index 6658eea9..b88da310 100644 --- a/src/engine/fileOpsIns.cpp +++ b/src/engine/fileOpsIns.cpp @@ -41,10 +41,10 @@ void DivEngine::loadDMP(SafeReader& reader, std::vector& ret, St try { reader.seek(0,SEEK_SET); version=reader.readC(); - logD(".dmp version %d\n",version); + logD(".dmp version %d",version); } catch (EndOfFileException& e) { lastError="premature end of file"; - logE("premature end of file!\n"); + logE("premature end of file!"); delete ins; return; } @@ -64,38 +64,38 @@ void DivEngine::loadDMP(SafeReader& reader, std::vector& ret, St switch (sys) { case 1: // YMU759 ins->type=DIV_INS_FM; - logD("instrument type is YMU759\n"); + logD("instrument type is YMU759"); break; case 2: // Genesis ins->type=DIV_INS_FM; - logD("instrument type is Genesis\n"); + logD("instrument type is Genesis"); break; case 3: // SMS ins->type=DIV_INS_STD; - logD("instrument type is SMS\n"); + logD("instrument type is SMS"); break; case 4: // Game Boy ins->type=DIV_INS_GB; - logD("instrument type is Game Boy\n"); + logD("instrument type is Game Boy"); break; case 5: // PC Engine ins->type=DIV_INS_PCE; - logD("instrument type is PC Engine\n"); + logD("instrument type is PC Engine"); break; case 6: // NES ins->type=DIV_INS_STD; - logD("instrument type is NES\n"); + logD("instrument type is NES"); break; case 7: case 0x17: // C64 ins->type=DIV_INS_C64; - logD("instrument type is C64\n"); + logD("instrument type is C64"); break; case 8: // Arcade ins->type=DIV_INS_FM; - logD("instrument type is Arcade\n"); + logD("instrument type is Arcade"); break; default: - logD("instrument type is unknown\n"); + logD("instrument type is unknown"); lastError="unknown instrument type!"; delete ins; return; @@ -103,7 +103,7 @@ void DivEngine::loadDMP(SafeReader& reader, std::vector& ret, St } } catch (EndOfFileException& e) { lastError="premature end of file"; - logE("premature end of file!\n"); + logE("premature end of file!"); delete ins; return; } @@ -113,7 +113,7 @@ void DivEngine::loadDMP(SafeReader& reader, std::vector& ret, St bool mode=true; if (version>1) { mode=reader.readC(); - logD("instrument mode is %d\n",mode); + logD("instrument mode is %d",mode); if (mode==0) { if (version<11) { ins->type=DIV_INS_STD; @@ -126,7 +126,7 @@ void DivEngine::loadDMP(SafeReader& reader, std::vector& ret, St } if (mode) { // FM - logD("reading FM data...\n"); + logD("reading FM data..."); if (version<10) { if (version>1) { // bullcrap! no way to determine the instrument type other than a vague FM/STD! @@ -151,7 +151,7 @@ void DivEngine::loadDMP(SafeReader& reader, std::vector& ret, St if (sys!=1) ins->fm.ams=reader.readC(); for (int j=0; jfm.ops; j++) { - logD("OP%d is at %d\n",j,reader.tell()); + logD("OP%d is at %d",j,reader.tell()); ins->fm.op[j].mult=reader.readC(); ins->fm.op[j].tl=reader.readC(); ins->fm.op[j].ar=reader.readC(); @@ -179,7 +179,7 @@ void DivEngine::loadDMP(SafeReader& reader, std::vector& ret, St } } } else { // STD - logD("reading STD data...\n"); + logD("reading STD data..."); if (ins->type!=DIV_INS_GB) { ins->std.volMacro.len=reader.readC(); if (version>5) { @@ -295,7 +295,7 @@ void DivEngine::loadDMP(SafeReader& reader, std::vector& ret, St } } catch (EndOfFileException& e) { lastError="premature end of file"; - logE("premature end of file!\n"); + logE("premature end of file!"); delete ins; return; } @@ -330,7 +330,7 @@ void DivEngine::loadTFI(SafeReader& reader, std::vector& ret, St } } catch (EndOfFileException& e) { lastError="premature end of file"; - logE("premature end of file!\n"); + logE("premature end of file!"); delete ins; return; } @@ -372,7 +372,7 @@ void DivEngine::loadVGI(SafeReader& reader, std::vector& ret, St } } catch (EndOfFileException& e) { lastError="premature end of file"; - logE("premature end of file!\n"); + logE("premature end of file!"); delete ins; return; } @@ -453,7 +453,7 @@ void DivEngine::loadS3I(SafeReader& reader, std::vector& ret, St }; } catch (EndOfFileException& e) { lastError = "premature end of file"; - logE("premature end of file!\n"); + logE("premature end of file!"); delete ins; return; } @@ -623,7 +623,7 @@ void DivEngine::loadSBI(SafeReader& reader, std::vector& ret, St } catch (EndOfFileException& e) { lastError = "premature end of file"; - logE("premature end of file!\n"); + logE("premature end of file!"); delete ins; return; } @@ -640,7 +640,7 @@ void DivEngine::loadOPM(SafeReader& reader, std::vector& ret, St } catch (EndOfFileException& e) { lastError="premature end of file"; - logE("premature end of file!\n"); + logE("premature end of file!"); return; } } @@ -695,7 +695,7 @@ std::vector DivEngine::instrumentFromFile(const char* path) { } buf=new unsigned char[len]; if (fread(buf,1,len,f)!=(size_t)len) { - logW("did not read entire instrument file buffer!\n"); + logW("did not read entire instrument file buffer!"); lastError="did not read entire instrument file!"; delete[] buf; return ret; @@ -738,7 +738,7 @@ std::vector DivEngine::instrumentFromFile(const char* path) { } } catch (EndOfFileException& e) { lastError="premature end of file"; - logE("premature end of file!\n"); + logE("premature end of file!"); delete ins; delete[] buf; return ret; diff --git a/src/engine/filter.cpp b/src/engine/filter.cpp index 8e0ac02e..8b0e5a2e 100644 --- a/src/engine/filter.cpp +++ b/src/engine/filter.cpp @@ -30,7 +30,7 @@ float* DivFilterTables::sincIntegralTable=NULL; // licensed under same license as this program. float* DivFilterTables::getCubicTable() { if (cubicTable==NULL) { - logD("initializing cubic spline table.\n"); + logD("initializing cubic spline table."); cubicTable=new float[4096]; for (int i=0; i<1024; i++) { @@ -46,7 +46,7 @@ float* DivFilterTables::getCubicTable() { float* DivFilterTables:: getSincTable() { if (sincTable==NULL) { - logD("initializing sinc table.\n"); + logD("initializing sinc table."); sincTable=new float[65536]; sincTable[0]=1.0f; @@ -66,7 +66,7 @@ float* DivFilterTables:: getSincTable() { float* DivFilterTables::getSincIntegralTable() { if (sincIntegralTable==NULL) { - logD("initializing sinc integral table.\n"); + logD("initializing sinc integral table."); sincIntegralTable=new float[65536]; sincIntegralTable[0]=-0.5f; diff --git a/src/engine/instrument.cpp b/src/engine/instrument.cpp index 8f87e460..68896a45 100644 --- a/src/engine/instrument.cpp +++ b/src/engine/instrument.cpp @@ -486,7 +486,7 @@ DivDataErrors DivInstrument::readInsData(SafeReader& reader, short version) { char magic[4]; reader.read(magic,4); if (memcmp(magic,"INST",4)!=0) { - logE("invalid instrument header!\n"); + logE("invalid instrument header!"); return DIV_DATA_INVALID_HEADER; } reader.readI(); @@ -949,12 +949,12 @@ bool DivInstrument::save(const char* path) { FILE* outFile=ps_fopen(path,"wb"); if (outFile==NULL) { - logE("could not save instrument: %s!\n",strerror(errno)); + logE("could not save instrument: %s!",strerror(errno)); w->finish(); return false; } if (fwrite(w->getFinalBuf(),1,w->size(),outFile)!=w->size()) { - logW("did not write entire instrument!\n"); + logW("did not write entire instrument!"); } fclose(outFile); w->finish(); diff --git a/src/engine/platform/ay.cpp b/src/engine/platform/ay.cpp index 30a83812..727a1440 100644 --- a/src/engine/platform/ay.cpp +++ b/src/engine/platform/ay.cpp @@ -431,11 +431,11 @@ int DivPlatformAY8910::dispatch(DivCommand c) { if (c.value) { // port B ioPortB=true; portBVal=c.value2; - logI("AY I/O port B write: %x\n",portBVal); + logI("AY I/O port B write: %x",portBVal); } else { // port A ioPortA=true; portAVal=c.value2; - logI("AY I/O port A write: %x\n",portAVal); + logI("AY I/O port A write: %x",portAVal); } updateOutSel(true); immWrite(14+(c.value?1:0),(c.value?portBVal:portAVal)); diff --git a/src/engine/platform/ay8930.cpp b/src/engine/platform/ay8930.cpp index a470dceb..e9af64fc 100644 --- a/src/engine/platform/ay8930.cpp +++ b/src/engine/platform/ay8930.cpp @@ -456,11 +456,11 @@ int DivPlatformAY8930::dispatch(DivCommand c) { if (c.value) { // port B ioPortB=true; portBVal=c.value2; - logI("AY I/O port B write: %x\n",portBVal); + logI("AY I/O port B write: %x",portBVal); } else { // port A ioPortA=true; portAVal=c.value2; - logI("AY I/O port A write: %x\n",portAVal); + logI("AY I/O port A write: %x",portAVal); } updateOutSel(true); immWrite(14+(c.value?1:0),(c.value?portBVal:portAVal)); diff --git a/src/engine/platform/qsound.cpp b/src/engine/platform/qsound.cpp index a63ca9e5..0fd25ec7 100644 --- a/src/engine/platform/qsound.cpp +++ b/src/engine/platform/qsound.cpp @@ -336,7 +336,7 @@ void DivPlatformQSound::tick() { rWrite(q1_reg_map[Q1V_LOOP][i], qsound_loop); rWrite(q1_reg_map[Q1V_START][i], qsound_addr); rWrite(q1_reg_map[Q1V_PHASE][i], 0x8000); - //logW("ch %d bank=%04x, addr=%04x, end=%04x, loop=%04x!\n",i,qsound_bank,qsound_addr,qsound_end,qsound_loop); + //logV("ch %d bank=%04x, addr=%04x, end=%04x, loop=%04x!",i,qsound_bank,qsound_addr,qsound_end,qsound_loop); // Write sample address. Enable volume if (!chan[i].std.vol.had) { rWrite(q1_reg_map[Q1V_VOL][i], chan[i].vol << 4); @@ -347,7 +347,7 @@ void DivPlatformQSound::tick() { rWrite(q1_reg_map[Q1V_VOL][i], 0); rWrite(q1_reg_map[Q1V_FREQ][i], 0); } else if (chan[i].active) { - //logW("ch %d frequency set to %04x, off=%f, note=%d, %04x!\n",i,chan[i].freq,off,chan[i].note,QS_NOTE_FREQUENCY(chan[i].note)); + //logV("ch %d frequency set to %04x, off=%f, note=%d, %04x!",i,chan[i].freq,off,chan[i].note,QS_NOTE_FREQUENCY(chan[i].note)); rWrite(q1_reg_map[Q1V_FREQ][i], chan[i].freq); } if (chan[i].keyOn) chan[i].keyOn=false; diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index a9497d66..97047b64 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -1660,7 +1660,7 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi if (softLocked) { if (!isBusy.try_lock()) { - logV("audio is soft-locked (%d)\n",softLockCount++); + logV("audio is soft-locked (%d)",softLockCount++); return; } } else { @@ -1712,7 +1712,7 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi } } } - logD("%.2x\n",msg.type); + logD("%.2x",msg.type); output->midiIn->queue.pop(); } @@ -1845,7 +1845,7 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi if (remainingLoops>0) { remainingLoops--; if (!remainingLoops) { - logI("end of song!\n"); + logI("end of song!"); remainingLoops=-1; playing=false; freelance=false; @@ -1881,9 +1881,9 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi return; } - //logD("attempts: %d\n",attempts); + //logD("attempts: %d",attempts); if (attempts>=100) { - logE("hang detected! stopping! at %d seconds %d micro\n",totalSeconds,totalTicks); + logE("hang detected! stopping! at %d seconds %d micro",totalSeconds,totalTicks); freelance=false; playing=false; extValuePresent=false; diff --git a/src/engine/safeReader.cpp b/src/engine/safeReader.cpp index 9add1b5a..7fa66e8b 100644 --- a/src/engine/safeReader.cpp +++ b/src/engine/safeReader.cpp @@ -57,7 +57,7 @@ size_t SafeReader::size() { int SafeReader::read(void* where, size_t count) { #ifdef READ_DEBUG - logD("SR: reading %d bytes at %x\n",count,curSeek); + logD("SR: reading %d bytes at %x",count,curSeek); #endif if (count==0) return 0; if (curSeek+count>len) throw EndOfFileException(this,len); @@ -68,23 +68,23 @@ int SafeReader::read(void* where, size_t count) { signed char SafeReader::readC() { #ifdef READ_DEBUG - logD("SR: reading char %x:\n",curSeek); + logD("SR: reading char %x:",curSeek); #endif if (curSeek+1>len) throw EndOfFileException(this,len); #ifdef READ_DEBUG - logD("SR: %.2x\n",buf[curSeek]); + logD("SR: %.2x",buf[curSeek]); #endif return (signed char)buf[curSeek++]; } short SafeReader::readS() { #ifdef READ_DEBUG - logD("SR: reading short %x:\n",curSeek); + logD("SR: reading short %x:",curSeek); #endif if (curSeek+2>len) throw EndOfFileException(this,len); short ret=*(short*)(&buf[curSeek]); #ifdef READ_DEBUG - logD("SR: %.4x\n",ret); + logD("SR: %.4x",ret); #endif curSeek+=2; return ret; @@ -99,13 +99,13 @@ short SafeReader::readS_BE() { int SafeReader::readI() { #ifdef READ_DEBUG - logD("SR: reading int %x:\n",curSeek); + logD("SR: reading int %x:",curSeek); #endif if (curSeek+4>len) throw EndOfFileException(this,len); int ret=*(int*)(&buf[curSeek]); curSeek+=4; #ifdef READ_DEBUG - logD("SR: %.8x\n",ret); + logD("SR: %.8x",ret); #endif return ret; } @@ -141,7 +141,7 @@ double SafeReader::readD() { String SafeReader::readString(size_t stlen) { String ret; #ifdef READ_DEBUG - logD("SR: reading string len %d at %x\n",stlen,curSeek); + logD("SR: reading string len %d at %x",stlen,curSeek); #endif size_t curPos=0; while (curPosdepth,h->samples); \ samples=h->samples; \ \ - if (h->length!=getCurBufLen()) logW("undo buffer length not equal to current buffer length! %d != %d\n",h->length,getCurBufLen()); \ + if (h->length!=getCurBufLen()) logW("undo buffer length not equal to current buffer length! %d != %d",h->length,getCurBufLen()); \ \ void* buf=getCurBuf(); \ \ diff --git a/src/engine/vgmOps.cpp b/src/engine/vgmOps.cpp index 68df49c5..b2081348 100644 --- a/src/engine/vgmOps.cpp +++ b/src/engine/vgmOps.cpp @@ -415,7 +415,7 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write } if (write.addr>=0xffff0000) { // Furnace special command unsigned char streamID=streamOff+((write.addr&0xff00)>>8); - logD("writing stream command %x:%x with stream ID %d\n",write.addr,write.val,streamID); + logD("writing stream command %x:%x with stream ID %d",write.addr,write.val,streamID); switch (write.addr&0xff) { case 0: // play sample if (write.valoff8=sampleSeek; sampleSeek+=sample->length8; } @@ -1447,7 +1447,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) { if (waitTime>0) { w->writeC(0x61); w->writeS(waitTime); - printf("wait is: %f\n",waitTime); + logV("wait is: %f",waitTime); totalWait-=waitTime; tickCount+=waitTime; } @@ -1561,7 +1561,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) { freelance=false; extValuePresent=false; - logI("%d register writes total.\n",writeCount); + logI("%d register writes total.",writeCount); BUSY_END; return w; diff --git a/src/engine/wavetable.cpp b/src/engine/wavetable.cpp index 5d8c8a1d..db6c33b2 100644 --- a/src/engine/wavetable.cpp +++ b/src/engine/wavetable.cpp @@ -73,12 +73,12 @@ bool DivWavetable::save(const char* path) { FILE* outFile=ps_fopen(path,"wb"); if (outFile==NULL) { - logE("could not save wavetable: %s!\n",strerror(errno)); + logE("could not save wavetable: %s!",strerror(errno)); w->finish(); return false; } if (fwrite(w->getFinalBuf(),1,w->size(),outFile)!=w->size()) { - logW("did not write entire wavetable!\n"); + logW("did not write entire wavetable!"); } fclose(outFile); w->finish(); diff --git a/src/engine/winStuff.cpp b/src/engine/winStuff.cpp index 1830a301..79065e88 100644 --- a/src/engine/winStuff.cpp +++ b/src/engine/winStuff.cpp @@ -33,15 +33,15 @@ String getWinConfigPath() { configPath=path; configPath+=L"\\furnace"; if (!PathIsDirectoryW(configPath.c_str())) { - logI("creating config dir...\n"); + logI("creating config dir..."); int mkdirRet; if ((mkdirRet=SHCreateDirectory(NULL,configPath.c_str()))!=ERROR_SUCCESS) { - logW("could not make config dir! (%.8x)\n",mkdirRet); + logW("could not make config dir! (%.8x)",mkdirRet); configPath=L"."; } } } else { - logW("unable to determine config directory! (%.8x)\n",configHR); + logW("unable to determine config directory! (%.8x)",configHR); configPath=L"."; } return utf16To8(configPath.c_str()); diff --git a/src/gui/doAction.cpp b/src/gui/doAction.cpp index f9ae0428..a1b974e3 100644 --- a/src/gui/doAction.cpp +++ b/src/gui/doAction.cpp @@ -212,6 +212,9 @@ void FurnaceGUI::doAction(int what) { case GUI_ACTION_WINDOW_REGISTER_VIEW: nextWindow=GUI_WINDOW_REGISTER_VIEW; break; + case GUI_ACTION_WINDOW_LOG: + nextWindow=GUI_WINDOW_LOG; + break; case GUI_ACTION_COLLAPSE_WINDOW: collapseWindow=true; diff --git a/src/gui/editing.cpp b/src/gui/editing.cpp index 034ca441..96f827f3 100644 --- a/src/gui/editing.cpp +++ b/src/gui/editing.cpp @@ -546,8 +546,8 @@ void FurnaceGUI::doPaste(PasteMode mode) { } if (invalidData) { - logW("invalid clipboard data! failed at line %d char %d\n",i,charPos); - logW("%s\n",line.c_str()); + logW("invalid clipboard data! failed at line %d char %d",i,charPos); + logW("%s",line.c_str()); break; } j++; diff --git a/src/gui/fileDialog.cpp b/src/gui/fileDialog.cpp index 95a6ac7b..a0a10103 100644 --- a/src/gui/fileDialog.cpp +++ b/src/gui/fileDialog.cpp @@ -65,7 +65,7 @@ bool FurnaceGUIFileDialog::render(const ImVec2& min, const ImVec2& max) { if (dialogS!=NULL) { if (dialogS->ready(0)) { fileName=dialogS->result(); - logD("returning %s\n",fileName.c_str()); + logD("returning %s",fileName.c_str()); return true; } } @@ -74,10 +74,10 @@ bool FurnaceGUIFileDialog::render(const ImVec2& min, const ImVec2& max) { if (dialogO->ready(0)) { if (dialogO->result().empty()) { fileName=""; - logD("returning nothing\n"); + logD("returning nothing"); } else { fileName=dialogO->result()[0]; - logD("returning %s\n",fileName.c_str()); + logD("returning %s",fileName.c_str()); } return true; } diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 66930051..ee69ae00 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -815,10 +815,10 @@ void FurnaceGUI::prepareLayout() { } // copy initial layout - logI("loading default layout.\n"); + logI("loading default layout."); check=ps_fopen(finalLayoutPath,"w"); if (check==NULL) { - logW("could not write default layout!\n"); + logW("could not write default layout!"); return; } @@ -1539,7 +1539,7 @@ int FurnaceGUI::save(String path, int dmfVersion) { memset(&zl,0,sizeof(z_stream)); ret=deflateInit(&zl,Z_DEFAULT_COMPRESSION); if (ret!=Z_OK) { - logE("zlib error!\n"); + logE("zlib error!"); lastError="compression error"; fclose(outFile); w->finish(); @@ -1551,7 +1551,7 @@ int FurnaceGUI::save(String path, int dmfVersion) { zl.avail_out=131072; zl.next_out=zbuf; if ((ret=deflate(&zl,Z_NO_FLUSH))==Z_STREAM_ERROR) { - logE("zlib stream error!\n"); + logE("zlib stream error!"); lastError="zlib stream error"; deflateEnd(&zl); fclose(outFile); @@ -1561,7 +1561,7 @@ int FurnaceGUI::save(String path, int dmfVersion) { size_t amount=131072-zl.avail_out; if (amount>0) { if (fwrite(zbuf,1,amount,outFile)!=amount) { - logE("did not write entirely: %s!\n",strerror(errno)); + logE("did not write entirely: %s!",strerror(errno)); lastError=strerror(errno); deflateEnd(&zl); fclose(outFile); @@ -1573,7 +1573,7 @@ int FurnaceGUI::save(String path, int dmfVersion) { zl.avail_out=131072; zl.next_out=zbuf; if ((ret=deflate(&zl,Z_FINISH))==Z_STREAM_ERROR) { - logE("zlib finish stream error!\n"); + logE("zlib finish stream error!"); lastError="zlib finish stream error"; deflateEnd(&zl); fclose(outFile); @@ -1582,7 +1582,7 @@ int FurnaceGUI::save(String path, int dmfVersion) { } if (131072-zl.avail_out>0) { if (fwrite(zbuf,1,131072-zl.avail_out,outFile)!=(131072-zl.avail_out)) { - logE("did not write entirely: %s!\n",strerror(errno)); + logE("did not write entirely: %s!",strerror(errno)); lastError=strerror(errno); deflateEnd(&zl); fclose(outFile); @@ -1593,7 +1593,7 @@ int FurnaceGUI::save(String path, int dmfVersion) { deflateEnd(&zl); #else if (fwrite(w->getFinalBuf(),1,w->size(),outFile)!=w->size()) { - logE("did not write entirely: %s!\n",strerror(errno)); + logE("did not write entirely: %s!",strerror(errno)); lastError=strerror(errno); fclose(outFile); w->finish(); @@ -1613,7 +1613,7 @@ int FurnaceGUI::save(String path, int dmfVersion) { int FurnaceGUI::load(String path) { if (!path.empty()) { - logI("loading module...\n"); + logI("loading module..."); FILE* f=ps_fopen(path.c_str(),"rb"); if (f==NULL) { perror("error"); @@ -1635,7 +1635,7 @@ int FurnaceGUI::load(String path) { } if (len<1) { if (len==0) { - logE("that file is empty!\n"); + logE("that file is empty!"); lastError="file is empty"; } else { perror("tell error"); @@ -1662,7 +1662,7 @@ int FurnaceGUI::load(String path) { fclose(f); if (!e->load(file,(size_t)len)) { lastError=e->getLastError(); - logE("could not open file!\n"); + logE("could not open file!"); return 1; } } @@ -2076,7 +2076,7 @@ bool FurnaceGUI::loop() { macroLoopDragActive=false; waveDragActive=false; if (sampleDragActive) { - logD("stopping sample drag\n"); + logD("stopping sample drag"); if (sampleDragMode) { e->renderSamplesP(); } else { @@ -2506,6 +2506,7 @@ bool FurnaceGUI::loop() { if (ImGui::MenuItem("oscilloscope",BIND_FOR(GUI_ACTION_WINDOW_OSCILLOSCOPE),oscOpen)) oscOpen=!oscOpen; if (ImGui::MenuItem("volume meter",BIND_FOR(GUI_ACTION_WINDOW_VOL_METER),volMeterOpen)) volMeterOpen=!volMeterOpen; if (ImGui::MenuItem("register view",BIND_FOR(GUI_ACTION_WINDOW_REGISTER_VIEW),regViewOpen)) regViewOpen=!regViewOpen; + if (ImGui::MenuItem("log viewer",BIND_FOR(GUI_ACTION_WINDOW_LOG),logOpen)) logOpen=!logOpen; if (ImGui::MenuItem("statistics",BIND_FOR(GUI_ACTION_WINDOW_STATS),statsOpen)) statsOpen=!statsOpen; ImGui::EndMenu(); @@ -2613,6 +2614,7 @@ bool FurnaceGUI::loop() { drawNotes(); drawChannels(); drawRegView(); + drawLog(); if (inspectorOpen) ImGui::ShowMetricsWindow(&inspectorOpen); @@ -2713,7 +2715,7 @@ bool FurnaceGUI::loop() { } break; case GUI_FILE_SAVE: { - logD("saving: %s\n",copyOfName.c_str()); + logD("saving: %s",copyOfName.c_str()); String lowerCase=fileName; for (char& i: lowerCase) { if (i>='A' && i<='Z') i+='a'-'A'; @@ -2730,7 +2732,7 @@ bool FurnaceGUI::loop() { break; } case GUI_FILE_SAVE_DMF_LEGACY: - logD("saving: %s\n",copyOfName.c_str()); + logD("saving: %s",copyOfName.c_str()); if (save(copyOfName,24)>0) { showError(fmt::sprintf("Error while saving file! (%s)",lastError)); } @@ -2865,7 +2867,7 @@ bool FurnaceGUI::loop() { if (aboutOpen) drawAbout(); if (ImGui::BeginPopupModal("Rendering...",NULL,ImGuiWindowFlags_AlwaysAutoResize)) { - ImGui::Text("Please wait...\n"); + ImGui::Text("Please wait..."); if (ImGui::Button("Abort")) { if (e->haltAudioFile()) { ImGui::CloseCurrentPopup(); @@ -2947,22 +2949,22 @@ bool FurnaceGUI::loop() { if (backupTimer<=0) { backupTask=std::async(std::launch::async,[this]() -> bool { if (backupPath==curFileName) { - logD("backup file open. not saving backup.\n"); + logD("backup file open. not saving backup."); return true; } - logD("saving backup...\n"); + logD("saving backup..."); SafeWriter* w=e->saveFur(true); if (w!=NULL) { FILE* outFile=ps_fopen(backupPath.c_str(),"wb"); if (outFile!=NULL) { if (fwrite(w->getFinalBuf(),1,w->size(),outFile)!=w->size()) { - logW("did not write backup entirely: %s!\n",strerror(errno)); + logW("did not write backup entirely: %s!",strerror(errno)); w->finish(); } fclose(outFile); } else { - logW("could not save backup: %s!\n",strerror(errno)); + logW("could not save backup: %s!",strerror(errno)); w->finish(); } } @@ -3037,6 +3039,7 @@ bool FurnaceGUI::init() { notesOpen=e->getConfBool("notesOpen",false); channelsOpen=e->getConfBool("channelsOpen",false); regViewOpen=e->getConfBool("regViewOpen",false); + logOpen=e->getConfBool("logOpen",false); tempoView=e->getConfBool("tempoView",true); waveHex=e->getConfBool("waveHex",false); @@ -3066,7 +3069,7 @@ bool FurnaceGUI::init() { sdlWin=SDL_CreateWindow("Furnace",SDL_WINDOWPOS_CENTERED,SDL_WINDOWPOS_CENTERED,scrW*dpiScale,scrH*dpiScale,SDL_WINDOW_RESIZABLE|SDL_WINDOW_ALLOW_HIGHDPI); if (sdlWin==NULL) { - logE("could not open window! %s\n",SDL_GetError()); + logE("could not open window! %s",SDL_GetError()); return false; } @@ -3091,14 +3094,14 @@ bool FurnaceGUI::init() { SDL_FreeSurface(icon); free(furIcon); } else { - logW("could not create icon!\n"); + logW("could not create icon!"); } #endif sdlRend=SDL_CreateRenderer(sdlWin,-1,SDL_RENDERER_ACCELERATED|SDL_RENDERER_PRESENTVSYNC|SDL_RENDERER_TARGETTEXTURE); if (sdlRend==NULL) { - logE("could not init renderer! %s\n",SDL_GetError()); + logE("could not init renderer! %s",SDL_GetError()); return false; } @@ -3115,14 +3118,14 @@ bool FurnaceGUI::init() { applyUISettings(); if (!ImGui::GetIO().Fonts->Build()) { - logE("error while building font atlas!\n"); + logE("error while building font atlas!"); showError("error while loading fonts! please check your settings."); ImGui::GetIO().Fonts->Clear(); mainFont=ImGui::GetIO().Fonts->AddFontDefault(); patFont=mainFont; ImGui_ImplSDLRenderer_DestroyFontsTexture(); if (!ImGui::GetIO().Fonts->Build()) { - logE("error again while building font atlas!\n"); + logE("error again while building font atlas!"); } } @@ -3199,6 +3202,7 @@ bool FurnaceGUI::finish() { e->setConf("notesOpen",notesOpen); e->setConf("channelsOpen",channelsOpen); e->setConf("regViewOpen",regViewOpen); + e->setConf("logOpen",logOpen); // commit last window size e->setConf("lastWindowWidth",scrW); @@ -3298,6 +3302,7 @@ FurnaceGUI::FurnaceGUI(): notesOpen(false), channelsOpen(false), regViewOpen(false), + logOpen(false), /* editControlsDocked(false), ordersDocked(false), diff --git a/src/gui/gui.h b/src/gui/gui.h index 641cf7c0..bcb7deee 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -167,6 +167,12 @@ enum FurnaceGUIColors { GUI_COLOR_PATTERN_EFFECT_SYS_SECONDARY, GUI_COLOR_PATTERN_EFFECT_MISC, + GUI_COLOR_LOGLEVEL_ERROR, + GUI_COLOR_LOGLEVEL_WARNING, + GUI_COLOR_LOGLEVEL_INFO, + GUI_COLOR_LOGLEVEL_DEBUG, + GUI_COLOR_LOGLEVEL_TRACE, + GUI_COLOR_EE_VALUE, GUI_COLOR_PLAYBACK_STAT, GUI_COLOR_MAX @@ -195,7 +201,8 @@ enum FurnaceGUIWindows { GUI_WINDOW_PIANO, GUI_WINDOW_NOTES, GUI_WINDOW_CHANNELS, - GUI_WINDOW_REGISTER_VIEW + GUI_WINDOW_REGISTER_VIEW, + GUI_WINDOW_LOG }; enum FurnaceGUIFileDialogs { @@ -290,6 +297,7 @@ enum FurnaceGUIActions { GUI_ACTION_WINDOW_NOTES, GUI_ACTION_WINDOW_CHANNELS, GUI_ACTION_WINDOW_REGISTER_VIEW, + GUI_ACTION_WINDOW_LOG, GUI_ACTION_COLLAPSE_WINDOW, GUI_ACTION_CLOSE_WINDOW, @@ -848,7 +856,7 @@ class FurnaceGUI { bool editControlsOpen, ordersOpen, insListOpen, songInfoOpen, patternOpen, insEditOpen; bool waveListOpen, waveEditOpen, sampleListOpen, sampleEditOpen, aboutOpen, settingsOpen; bool mixerOpen, debugOpen, inspectorOpen, oscOpen, volMeterOpen, statsOpen, compatFlagsOpen; - bool pianoOpen, notesOpen, channelsOpen, regViewOpen; + bool pianoOpen, notesOpen, channelsOpen, regViewOpen, logOpen; /* there ought to be a better way... bool editControlsDocked, ordersDocked, insListDocked, songInfoDocked, patternDocked, insEditDocked; @@ -1044,6 +1052,7 @@ class FurnaceGUI { void drawSettings(); void drawDebug(); void drawNewSong(); + void drawLog(); void parseKeybinds(); void promptKey(int which); diff --git a/src/gui/guiConst.cpp b/src/gui/guiConst.cpp index c3a7c72b..1b292638 100644 --- a/src/gui/guiConst.cpp +++ b/src/gui/guiConst.cpp @@ -191,6 +191,7 @@ const FurnaceGUIActionDef guiActions[GUI_ACTION_MAX]={ D("WINDOW_NOTES", "Song Comments", 0), D("WINDOW_CHANNELS", "Channels", 0), D("WINDOW_REGISTER_VIEW", "Register View", 0), + D("WINDOW_LOG", "Log Viewer", 0), D("COLLAPSE_WINDOW", "Collapse/expand current window", 0), D("CLOSE_WINDOW", "Close current window", FURKMOD_SHIFT|SDLK_ESCAPE), @@ -473,6 +474,12 @@ const FurnaceGUIColorDef guiColors[GUI_COLOR_MAX]={ D(GUI_COLOR_PATTERN_EFFECT_SYS_SECONDARY,"",ImVec4(0.0f,1.0f,0.5f,1.0f)), D(GUI_COLOR_PATTERN_EFFECT_MISC,"",ImVec4(0.3f,0.3f,1.0f,1.0f)), + D(GUI_COLOR_LOGLEVEL_ERROR,"",ImVec4(1.0f,0.2f,0.2f,1.0f)), + D(GUI_COLOR_LOGLEVEL_WARNING,"",ImVec4(1.0f,1.0f,0.2f,1.0f)), + D(GUI_COLOR_LOGLEVEL_INFO,"",ImVec4(0.4f,1.0f,0.4f,1.0f)), + D(GUI_COLOR_LOGLEVEL_DEBUG,"",ImVec4(0.3f,0.5f,1.0f,1.0f)), + D(GUI_COLOR_LOGLEVEL_TRACE,"",ImVec4(0.8f,0.8f,0.8f,1.0f)), + D(GUI_COLOR_EE_VALUE,"",ImVec4(0.0f,1.0f,1.0f,1.0f)), D(GUI_COLOR_PLAYBACK_STAT,"",ImVec4(0.6f,0.6f,0.6f,1.0f)), }; diff --git a/src/gui/log.cpp b/src/gui/log.cpp new file mode 100644 index 00000000..2b83ab90 --- /dev/null +++ b/src/gui/log.cpp @@ -0,0 +1,71 @@ +#include "gui.h" +#include "../ta-log.h" +#include +#include + +const char* logLevels[5]={ + "ERROR", + "warning", + "info", + "debug", + "trace" +}; + +FurnaceGUIColors logColors[5]={ + GUI_COLOR_LOGLEVEL_ERROR, + GUI_COLOR_LOGLEVEL_WARNING, + GUI_COLOR_LOGLEVEL_INFO, + GUI_COLOR_LOGLEVEL_DEBUG, + GUI_COLOR_LOGLEVEL_TRACE +}; + +void FurnaceGUI::drawLog() { + if (nextWindow==GUI_WINDOW_LOG) { + logOpen=true; + ImGui::SetNextWindowFocus(); + nextWindow=GUI_WINDOW_NOTHING; + } + if (!logOpen) return; + if (ImGui::Begin("Log Viewer",&logOpen)) { + ImGui::Text("Level"); + ImGui::SameLine(); + ImGui::Combo("##LogLevel",&logLevel,logLevels,5); + if (ImGui::BeginTable("LogView",3,ImGuiTableFlags_ScrollY|ImGuiTableFlags_BordersInnerV)) { + ImGui::PushFont(patFont); + + float timeChars=ImGui::CalcTextSize("00:00:00").x; + float levelChars=ImGui::CalcTextSize("warning").x; + + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed,timeChars); + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthFixed,levelChars); + ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch); + + ImGui::TableNextRow(ImGuiTableRowFlags_Headers); + ImGui::TableNextColumn(); + ImGui::TextUnformatted("time"); + ImGui::TableNextColumn(); + ImGui::TextUnformatted("level"); + ImGui::TableNextColumn(); + ImGui::TextUnformatted("message"); + + int pos=logPosition; + for (int i=0; i(logEntry.time).time_since_epoch().count(); + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + // this will fail on 32-bit :< + ImGui::Text("%02ld:%02ld:%02ld",(t/3600)%24,(t/60)%60,t%60); + ImGui::TableNextColumn(); + ImGui::TextColored(uiColors[logColors[logEntry.loglevel]],"%s",logLevels[logEntry.loglevel]); + ImGui::TableNextColumn(); + ImGui::TextWrapped("%s",logEntry.text.c_str()); + } + ImGui::PopFont(); + ImGui::EndTable(); + } + } + ImGui::End(); +} \ No newline at end of file diff --git a/src/gui/midiMap.cpp b/src/gui/midiMap.cpp index 071540f9..568bf16e 100644 --- a/src/gui/midiMap.cpp +++ b/src/gui/midiMap.cpp @@ -64,7 +64,7 @@ int MIDIMap::at(const TAMidiMessage& where) { #define UNDERSTAND_ARRAY_OPTION(x,yMax) if (optionNameS==#x) { \ if (optionIndex<0 || optionIndex>=yMax) { \ - logW("MIDI map array option %d out of range (0-%d) at line %d: %s\n",optionIndex,yMax,curLine,line); \ + logW("MIDI map array option %d out of range (0-%d) at line %d: %s",optionIndex,yMax,curLine,line); \ break; \ } \ x[optionIndex]=std::stoi(optionValueS); \ @@ -76,7 +76,7 @@ bool MIDIMap::read(String path) { FILE* f=fopen(path.c_str(),"rb"); if (f==NULL) { if (errno!=ENOENT) { - logE("error while loading MIDI mapping! %s\n",strerror(errno)); + logE("error while loading MIDI mapping! %s",strerror(errno)); } return false; } @@ -93,7 +93,7 @@ bool MIDIMap::read(String path) { int result=sscanf(line,"aOption %255s %d %255s",optionName,&optionIndex,optionValue); if (result!=3) { - logW("MIDI map garbage data at line %d: %s\n",curLine,line); + logW("MIDI map garbage data at line %d: %s",curLine,line); break; } @@ -105,12 +105,12 @@ bool MIDIMap::read(String path) { UNDERSTAND_ARRAY_OPTION(valueInputSpecificMSB,18) else UNDERSTAND_ARRAY_OPTION(valueInputSpecificLSB,18) else UNDERSTAND_ARRAY_OPTION(valueInputSpecificSingle,18) else { - logW("MIDI map unknown array option %s at line %d: %s\n",optionName,curLine,line); + logW("MIDI map unknown array option %s at line %d: %s",optionName,curLine,line); } } catch (std::out_of_range& e) { - logW("MIDI map invalid value %s for array option %s at line %d: %s\n",optionValue,optionName,curLine,line); + logW("MIDI map invalid value %s for array option %s at line %d: %s",optionValue,optionName,curLine,line); } catch (std::invalid_argument& e) { - logW("MIDI map invalid value %s for array option %s at line %d: %s\n",optionValue,optionName,curLine,line); + logW("MIDI map invalid value %s for array option %s at line %d: %s",optionValue,optionName,curLine,line); } curLine++; @@ -122,7 +122,7 @@ bool MIDIMap::read(String path) { String optionNameS, optionValueS; int result=sscanf(line,"option %255s %255s",optionName,optionValue); if (result!=2) { - logW("MIDI map garbage data at line %d: %s\n",curLine,line); + logW("MIDI map garbage data at line %d: %s",curLine,line); break; } @@ -143,12 +143,12 @@ bool MIDIMap::read(String path) { UNDERSTAND_OPTION(valueInputControlLSB) else UNDERSTAND_OPTION(valueInputControlSingle) else UNDERSTAND_FLOAT_OPTION(volExp) else { - logW("MIDI map unknown option %s at line %d: %s\n",optionName,curLine,line); + logW("MIDI map unknown option %s at line %d: %s",optionName,curLine,line); } } catch (std::out_of_range& e) { - logW("MIDI map invalid value %s for option %s at line %d: %s\n",optionValue,optionName,curLine,line); + logW("MIDI map invalid value %s for option %s at line %d: %s",optionValue,optionName,curLine,line); } catch (std::invalid_argument& e) { - logW("MIDI map invalid value %s for option %s at line %d: %s\n",optionValue,optionName,curLine,line); + logW("MIDI map invalid value %s for option %s at line %d: %s",optionValue,optionName,curLine,line); } curLine++; @@ -159,7 +159,7 @@ bool MIDIMap::read(String path) { MIDIBind bind; int result=sscanf(line,"%d %d %d %d %255s",&bind.type,&bind.channel,&bind.data1,&bind.data2,bindAction); if (result!=5 || result==EOF) { - logW("MIDI map garbage data at line %d: %s\n",curLine,line); + logW("MIDI map garbage data at line %d: %s",curLine,line); break; } @@ -172,7 +172,7 @@ bool MIDIMap::read(String path) { } } if (!foundAction) { - logW("MIDI map unknown action %s at line %d: %s\n",bindAction,curLine,line); + logW("MIDI map unknown action %s at line %d: %s",bindAction,curLine,line); break; } @@ -191,7 +191,7 @@ bool MIDIMap::read(String path) { bool MIDIMap::write(String path) { FILE* f=fopen(path.c_str(),"wb"); if (f==NULL) { - logE("error while saving MIDI mapping! %s\n",strerror(errno)); + logE("error while saving MIDI mapping! %s",strerror(errno)); return false; } @@ -218,7 +218,7 @@ bool MIDIMap::write(String path) { for (MIDIBind& i: binds) { if (fprintf(f,"%d %d %d %d %s\n",i.type,i.channel,i.data1,i.data2,guiActions[i.action].name)<0) { - logW("did not write MIDI mapping entirely! %s\n",strerror(errno)); + logW("did not write MIDI mapping entirely! %s",strerror(errno)); break; } } @@ -274,6 +274,6 @@ void MIDIMap::compile() { } map[i.type-8][i.channel][i.data1][i.data2]=i.action; - logD("MIDI mapping %d %d %d %d to %d\n",i.type-8,i.channel,i.data1,i.data2,i.action); + logD("MIDI mapping %d %d %d %d to %d",i.type-8,i.channel,i.data1,i.data2,i.action); } } diff --git a/src/gui/pattern.cpp b/src/gui/pattern.cpp index d56196d6..0decef97 100644 --- a/src/gui/pattern.cpp +++ b/src/gui/pattern.cpp @@ -874,6 +874,6 @@ void FurnaceGUI::drawPattern() { if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_PATTERN; ImGui::End(); //int delta1=SDL_GetPerformanceCounter(); - //logV("render time: %dµs\n",(delta1-delta0)/(SDL_GetPerformanceFrequency()/1000000)); + //logV("render time: %dµs",(delta1-delta0)/(SDL_GetPerformanceFrequency()/1000000)); } diff --git a/src/gui/sampleEdit.cpp b/src/gui/sampleEdit.cpp index 18a91e29..04af4cab 100644 --- a/src/gui/sampleEdit.cpp +++ b/src/gui/sampleEdit.cpp @@ -579,12 +579,12 @@ void FurnaceGUI::drawSampleEdit() { sampleTex=NULL; } if (avail.x>=1 && avail.y>=1) { - logD("recreating sample texture.\n"); + logD("recreating sample texture."); sampleTex=SDL_CreateTexture(sdlRend,SDL_PIXELFORMAT_ABGR8888,SDL_TEXTUREACCESS_STREAMING,avail.x,avail.y); sampleTexW=avail.x; sampleTexH=avail.y; if (sampleTex==NULL) { - logE("error while creating sample texture! %s\n",SDL_GetError()); + logE("error while creating sample texture! %s",SDL_GetError()); } else { updateSampleTex=true; } @@ -595,9 +595,9 @@ void FurnaceGUI::drawSampleEdit() { if (updateSampleTex) { unsigned int* data=NULL; int pitch=0; - logD("updating sample texture.\n"); + logD("updating sample texture."); if (SDL_LockTexture(sampleTex,NULL,(void**)&data,&pitch)!=0) { - logE("error while locking sample texture! %s\n",SDL_GetError()); + logE("error while locking sample texture! %s",SDL_GetError()); } else { ImU32 bgColor=ImGui::GetColorU32(ImGuiCol_FrameBg); ImU32 bgColorLoop=ImAlphaBlendColors(bgColor,ImGui::GetColorU32(ImGuiCol_FrameBgHovered,0.5)); diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index 316e3ef5..2727c3a3 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -384,8 +384,8 @@ void FurnaceGUI::drawSettings() { TAAudioDesc& audioWant=e->getAudioDescWant(); TAAudioDesc& audioGot=e->getAudioDescGot(); - ImGui::Text("want: %d samples @ %.0fHz\n",audioWant.bufsize,audioWant.rate); - ImGui::Text("got: %d samples @ %.0fHz\n",audioGot.bufsize,audioGot.rate); + ImGui::Text("want: %d samples @ %.0fHz",audioWant.bufsize,audioWant.rate); + ImGui::Text("got: %d samples @ %.0fHz",audioGot.bufsize,audioGot.rate); ImGui::Separator(); @@ -1053,6 +1053,14 @@ void FurnaceGUI::drawSettings() { UI_COLOR_CONFIG(GUI_COLOR_EE_VALUE,"External command output"); ImGui::TreePop(); } + if (ImGui::TreeNode("Log Viewer")) { + UI_COLOR_CONFIG(GUI_COLOR_LOGLEVEL_ERROR,"Log level: Error"); + UI_COLOR_CONFIG(GUI_COLOR_LOGLEVEL_WARNING,"Log level: Warning"); + UI_COLOR_CONFIG(GUI_COLOR_LOGLEVEL_INFO,"Log level: Info"); + UI_COLOR_CONFIG(GUI_COLOR_LOGLEVEL_DEBUG,"Log level: Debug"); + UI_COLOR_CONFIG(GUI_COLOR_LOGLEVEL_TRACE,"Log level: Trace/Verbose"); + ImGui::TreePop(); + } ImGui::TreePop(); } @@ -1126,6 +1134,7 @@ void FurnaceGUI::drawSettings() { UI_KEYBIND_CONFIG(GUI_ACTION_WINDOW_NOTES); UI_KEYBIND_CONFIG(GUI_ACTION_WINDOW_CHANNELS); UI_KEYBIND_CONFIG(GUI_ACTION_WINDOW_REGISTER_VIEW); + UI_KEYBIND_CONFIG(GUI_ACTION_WINDOW_LOG); UI_KEYBIND_CONFIG(GUI_ACTION_COLLAPSE_WINDOW); UI_KEYBIND_CONFIG(GUI_ACTION_CLOSE_WINDOW); @@ -1633,14 +1642,14 @@ void FurnaceGUI::commitSettings() { ImGui_ImplSDLRenderer_DestroyFontsTexture(); if (!ImGui::GetIO().Fonts->Build()) { - logE("error while building font atlas!\n"); + logE("error while building font atlas!"); showError("error while loading fonts! please check your settings."); ImGui::GetIO().Fonts->Clear(); mainFont=ImGui::GetIO().Fonts->AddFontDefault(); patFont=mainFont; ImGui_ImplSDLRenderer_DestroyFontsTexture(); if (!ImGui::GetIO().Fonts->Build()) { - logE("error again while building font atlas!\n"); + logE("error again while building font atlas!"); } } } @@ -1648,7 +1657,7 @@ void FurnaceGUI::commitSettings() { bool FurnaceGUI::importColors(String path) { FILE* f=ps_fopen(path.c_str(),"rb"); if (f==NULL) { - logW("error while opening color file for import: %s\n",strerror(errno)); + logW("error while opening color file for import: %s",strerror(errno)); return false; } resetColors(); @@ -1689,7 +1698,7 @@ bool FurnaceGUI::importColors(String path) { break; } } - if (!found) logW("line invalid: %s\n",line); + if (!found) logW("line invalid: %s",line); } } fclose(f); @@ -1699,12 +1708,12 @@ bool FurnaceGUI::importColors(String path) { bool FurnaceGUI::exportColors(String path) { FILE* f=ps_fopen(path.c_str(),"wb"); if (f==NULL) { - logW("error while opening color file for export: %s\n",strerror(errno)); + logW("error while opening color file for export: %s",strerror(errno)); return false; } for (int i=0; i6) settings.patFont=0; if (settings.mainFont==6 && settings.mainFontPath.empty()) { - logW("UI font path is empty! reverting to default font\n"); + logW("UI font path is empty! reverting to default font"); settings.mainFont=0; } if (settings.patFont==6 && settings.patFontPath.empty()) { - logW("pattern font path is empty! reverting to default font\n"); + logW("pattern font path is empty! reverting to default font"); settings.patFont=0; } @@ -2113,10 +2122,10 @@ void FurnaceGUI::applyUISettings() { if (settings.mainFont==6) { // custom font if ((mainFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(settings.mainFontPath.c_str(),e->getConfInt("mainFontSize",18)*dpiScale,NULL,fontRange))==NULL) { - logW("could not load UI font! reverting to default font\n"); + logW("could not load UI font! reverting to default font"); settings.mainFont=0; if ((mainFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFont[settings.mainFont],builtinFontLen[settings.mainFont],e->getConfInt("mainFontSize",18)*dpiScale,NULL,fontRange))==NULL) { - logE("could not load UI font! falling back to Proggy Clean.\n"); + logE("could not load UI font! falling back to Proggy Clean."); mainFont=ImGui::GetIO().Fonts->AddFontDefault(); } } @@ -2124,10 +2133,10 @@ void FurnaceGUI::applyUISettings() { if ((mainFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_FONT_PATH_1,e->getConfInt("mainFontSize",18)*dpiScale,NULL,fontRange))==NULL) { if ((mainFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_FONT_PATH_2,e->getConfInt("mainFontSize",18)*dpiScale,NULL,fontRange))==NULL) { if ((mainFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_FONT_PATH_3,e->getConfInt("mainFontSize",18)*dpiScale,NULL,fontRange))==NULL) { - logW("could not load UI font! reverting to default font\n"); + logW("could not load UI font! reverting to default font"); settings.mainFont=0; if ((mainFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFont[settings.mainFont],builtinFontLen[settings.mainFont],e->getConfInt("mainFontSize",18)*dpiScale,NULL,fontRange))==NULL) { - logE("could not load UI font! falling back to Proggy Clean.\n"); + logE("could not load UI font! falling back to Proggy Clean."); mainFont=ImGui::GetIO().Fonts->AddFontDefault(); } } @@ -2135,7 +2144,7 @@ void FurnaceGUI::applyUISettings() { } } else { if ((mainFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFont[settings.mainFont],builtinFontLen[settings.mainFont],e->getConfInt("mainFontSize",18)*dpiScale,NULL,fontRange))==NULL) { - logE("could not load UI font! falling back to Proggy Clean.\n"); + logE("could not load UI font! falling back to Proggy Clean."); mainFont=ImGui::GetIO().Fonts->AddFontDefault(); } } @@ -2149,18 +2158,18 @@ void FurnaceGUI::applyUISettings() { fc.GlyphMinAdvanceX=e->getConfInt("iconSize",16)*dpiScale; static const ImWchar fontRangeIcon[]={ICON_MIN_FA,ICON_MAX_FA,0}; if ((iconFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(iconFont_compressed_data,iconFont_compressed_size,e->getConfInt("iconSize",16)*dpiScale,&fc,fontRangeIcon))==NULL) { - logE("could not load icon font!\n"); + logE("could not load icon font!"); } if (settings.mainFontSize==settings.patFontSize && settings.patFont<5 && builtinFontM[settings.patFont]==builtinFont[settings.mainFont]) { - logD("using main font for pat font.\n"); + logD("using main font for pat font."); patFont=mainFont; } else { if (settings.patFont==6) { // custom font if ((patFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(settings.patFontPath.c_str(),e->getConfInt("patFontSize",18)*dpiScale,NULL,upTo800))==NULL) { - logW("could not load pattern font! reverting to default font\n"); + logW("could not load pattern font! reverting to default font"); settings.patFont=0; if ((patFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFontM[settings.patFont],builtinFontMLen[settings.patFont],e->getConfInt("patFontSize",18)*dpiScale,NULL,upTo800))==NULL) { - logE("could not load pattern font! falling back to Proggy Clean.\n"); + logE("could not load pattern font! falling back to Proggy Clean."); patFont=ImGui::GetIO().Fonts->AddFontDefault(); } } @@ -2168,10 +2177,10 @@ void FurnaceGUI::applyUISettings() { if ((patFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_PAT_FONT_PATH_1,e->getConfInt("patFontSize",18)*dpiScale,NULL,upTo800))==NULL) { if ((patFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_PAT_FONT_PATH_2,e->getConfInt("patFontSize",18)*dpiScale,NULL,upTo800))==NULL) { if ((patFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_PAT_FONT_PATH_3,e->getConfInt("patFontSize",18)*dpiScale,NULL,upTo800))==NULL) { - logW("could not load pattern font! reverting to default font\n"); + logW("could not load pattern font! reverting to default font"); settings.patFont=0; if ((patFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFontM[settings.patFont],builtinFontMLen[settings.patFont],e->getConfInt("patFontSize",18)*dpiScale,NULL,upTo800))==NULL) { - logE("could not load pattern font! falling back to Proggy Clean.\n"); + logE("could not load pattern font! falling back to Proggy Clean."); patFont=ImGui::GetIO().Fonts->AddFontDefault(); } } @@ -2179,13 +2188,13 @@ void FurnaceGUI::applyUISettings() { } } else { if ((patFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFontM[settings.patFont],builtinFontMLen[settings.patFont],e->getConfInt("patFontSize",18)*dpiScale,NULL,upTo800))==NULL) { - logE("could not load pattern font!\n"); + logE("could not load pattern font!"); patFont=ImGui::GetIO().Fonts->AddFontDefault(); } } } if ((bigFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(font_plexSans_compressed_data,font_plexSans_compressed_size,40*dpiScale))==NULL) { - logE("could not load big UI font!\n"); + logE("could not load big UI font!"); } mainFont->FallbackChar='?'; diff --git a/src/log.cpp b/src/log.cpp index 1f77925b..a3a6000c 100644 --- a/src/log.cpp +++ b/src/log.cpp @@ -17,12 +17,16 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -// TODO: improve these routines to allow logging to memory for eventual log window! - #include "ta-log.h" int logLevel=LOGLEVEL_INFO; +std::atomic logPosition; + +LogEntry logEntries[TA_LOG_SIZE]; + +static constexpr unsigned int TA_LOG_MASK=TA_LOG_SIZE-1; + int logV(const char* format, ...) { va_list va; int ret; @@ -55,21 +59,6 @@ int logD(const char* format, ...) { return ret; } -int logI(const char* format, ...) { - va_list va; - int ret; - if (logLevelgetFinalBuf(),1,w->size(),f); fclose(f); } else { - logE("could not open file! %s\n",strerror(errno)); + logE("could not open file! %s",strerror(errno)); } w->finish(); delete w; } else { - logE("could not write VGM!\n"); + logE("could not write VGM!"); } } if (outName!="") { @@ -391,7 +392,7 @@ int main(int argc, char** argv) { } if (consoleMode) { - logI("playing...\n"); + logI("playing..."); e.play(); #ifdef HAVE_GUI SDL_Event ev; @@ -417,7 +418,7 @@ int main(int argc, char** argv) { if (!g.init()) return 1; if (displayEngineFailError) { - logE("displaying engine fail error.\n"); + logE("displaying engine fail error."); g.showError("error while initializing audio!"); } @@ -426,13 +427,13 @@ int main(int argc, char** argv) { } g.loop(); - logI("closing GUI.\n"); + logI("closing GUI."); g.finish(); #else - logE("GUI requested but GUI not compiled!\n"); + logE("GUI requested but GUI not compiled!"); #endif - logI("stopping engine.\n"); + logI("stopping engine."); e.quit(); return 0; } diff --git a/src/ta-log.h b/src/ta-log.h index e7867de5..666dfa48 100644 --- a/src/ta-log.h +++ b/src/ta-log.h @@ -19,8 +19,12 @@ #ifndef _TA_LOG_H #define _TA_LOG_H +#include #include #include +#include +#include +#include #define LOGLEVEL_ERROR 0 #define LOGLEVEL_WARN 1 @@ -28,11 +32,51 @@ #define LOGLEVEL_DEBUG 3 #define LOGLEVEL_TRACE 4 +// this has to be a power of 2 +#define TA_LOG_SIZE 2048 + extern int logLevel; -int logV(const char* format, ...); -int logD(const char* format, ...); -int logI(const char* format, ...); -int logW(const char* format, ...); -int logE(const char* format, ...); +extern std::atomic logPosition; + +struct LogEntry { + int loglevel; + std::chrono::system_clock::time_point time; + std::string text; + bool ready; + LogEntry(): + loglevel(0), + ready(false) {} +}; + +int writeLog(int level, const char* msg, fmt::printf_args& args); + +extern LogEntry logEntries[TA_LOG_SIZE]; + +template int logV(const char* msg, const T&... args) { + fmt::printf_args a=fmt::make_printf_args(args...); + return writeLog(LOGLEVEL_TRACE,msg,a); +} + +template int logD(const char* msg, const T&... args) { + fmt::printf_args a=fmt::make_printf_args(args...); + return writeLog(LOGLEVEL_DEBUG,msg,a); +} + +template int logI(const char* msg, const T&... args) { + fmt::printf_args a=fmt::make_printf_args(args...); + return writeLog(LOGLEVEL_INFO,msg,a); +} + +template int logW(const char* msg, const T&... args) { + fmt::printf_args a=fmt::make_printf_args(args...); + return writeLog(LOGLEVEL_WARN,msg,a); +} + +template int logE(const char* msg, const T&... args) { + fmt::printf_args a=fmt::make_printf_args(args...); + return writeLog(LOGLEVEL_ERROR,msg,a); +} + +void initLog(); #endif From 6b627ab885436e403a30ed512a8e85bf5af88059 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 10 Apr 2022 22:16:42 -0500 Subject: [PATCH 61/76] TOOK --- src/engine/engine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 690ee993..14577b40 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -824,7 +824,7 @@ void DivEngine::playSub(bool preserveDrift, int goalRow) { skipping=false; cmdStream.clear(); std::chrono::high_resolution_clock::time_point timeEnd=std::chrono::high_resolution_clock::now(); - logV("playSub() tool %dµs",std::chrono::duration_cast(timeEnd-timeStart).count()); + logV("playSub() took %dµs",std::chrono::duration_cast(timeEnd-timeStart).count()); } /* From 552967246d5f582516a77fbd510d66b3e7553dc6 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 10 Apr 2022 23:01:55 -0500 Subject: [PATCH 62/76] **SUBMODULE UPDATE - PLEASE READ!** as of now I have added the Date library as a submodule in order to have log messages in the correct time zone please update your submodules by doing: ``` git submodule update --init --recursive ``` --- .gitmodules | 3 +++ CMakeLists.txt | 19 +++++++++++++++++++ extern/date | 1 + src/gui/gui.cpp | 3 ++- src/gui/gui.h | 3 +++ src/gui/log.cpp | 13 ++++++++++--- 6 files changed, 38 insertions(+), 4 deletions(-) create mode 160000 extern/date diff --git a/.gitmodules b/.gitmodules index d63fd70b..e96848c3 100644 --- a/.gitmodules +++ b/.gitmodules @@ -22,3 +22,6 @@ [submodule "extern/Nuked-OPL3"] path = extern/Nuked-OPL3 url = https://github.com/nukeykt/Nuked-OPL3.git +[submodule "extern/date"] + path = extern/date + url = https://github.com/HowardHinnant/date diff --git a/CMakeLists.txt b/CMakeLists.txt index d3b98fc6..ae93abda 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -42,6 +42,7 @@ option(SYSTEM_LIBSNDFILE "Use a system-installed version of libsndfile instead o option(SYSTEM_RTMIDI "Use a system-installed version of RtMidi instead of the vendored one" OFF) option(SYSTEM_ZLIB "Use a system-installed version of zlib instead of the vendored one" OFF) option(SYSTEM_SDL2 "Use a system-installed version of SDL2 instead of the vendored one" ${SYSTEM_SDL2_DEFAULT}) +option(SYSTEM_DATE "Use a system-installed version of Date instead of the vendored one" OFF) option(WARNINGS_ARE_ERRORS "Whether warnings in furnace's C++ code should be treated as errors" OFF) set(DEPENDENCIES_INCLUDE_DIRS "") @@ -126,6 +127,24 @@ if (USE_RTMIDI) endif() endif() +if (SYSTEM_DATE) + find_package(PkgConfig REQUIRED) + pkg_check_modules(HHDATE REQUIRED date) + list(APPEND DEPENDENCIES_INCLUDE_DIRS ${HHDATE_INCLUDE_DIRS}) + list(APPEND DEPENDENCIES_COMPILE_OPTIONS ${HHDATE_CFLAGS_OTHER}) + list(APPEND DEPENDENCIES_LIBRARIES ${HHDATE_LIBRARIES}) + list(APPEND DEPENDENCIES_LIBRARY_DIRS ${HHDATE_LIBRARY_DIRS}) + list(APPEND DEPENDENCIES_LINK_OPTIONS ${HHDATE_LDFLAGS_OTHER}) + list(APPEND DEPENDENCIES_LEGACY_LDFLAGS ${HHDATE_LDFLAGS}) + message(STATUS "Using system-installed Date") +else() + set(BUILD_TZ_LIB ON CACHE BOOL "build/install of TZ library" FORCE) + add_subdirectory(extern/date EXCLUDE_FROM_ALL) + list(APPEND DEPENDENCIES_INCLUDE_DIRS extern/date/include) + list(APPEND DEPENDENCIES_LIBRARIES date date-tz) + message(STATUS "Using vendored Date") +endif() + if (SYSTEM_ZLIB) find_package(PkgConfig REQUIRED) pkg_check_modules(ZLIB REQUIRED zlib) diff --git a/extern/date b/extern/date new file mode 160000 index 00000000..9ea5654c --- /dev/null +++ b/extern/date @@ -0,0 +1 @@ +Subproject commit 9ea5654c1206e19245dc21d8a2c433e090c8c3f5 diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index ee69ae00..4b3542b1 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -3439,7 +3439,8 @@ FurnaceGUI::FurnaceGUI(): openSampleFilterOpt(false), oscTotal(0), oscZoom(0.5f), - oscZoomSlider(false) { + oscZoomSlider(false), + followLog(true) { // value keys valueKeys[SDLK_0]=0; valueKeys[SDLK_1]=1; diff --git a/src/gui/gui.h b/src/gui/gui.h index bcb7deee..cadc84d4 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1003,6 +1003,9 @@ class FurnaceGUI { // visualizer float keyHit[DIV_MAX_CHANS]; int lastIns[DIV_MAX_CHANS]; + + // log window + bool followLog; void drawSSGEnv(unsigned char type, const ImVec2& size); void drawWaveform(unsigned char type, bool opz, const ImVec2& size); diff --git a/src/gui/log.cpp b/src/gui/log.cpp index 2b83ab90..b6536cdb 100644 --- a/src/gui/log.cpp +++ b/src/gui/log.cpp @@ -1,7 +1,7 @@ #include "gui.h" #include "../ta-log.h" #include -#include +#include "date/tz.h" const char* logLevels[5]={ "ERROR", @@ -27,8 +27,11 @@ void FurnaceGUI::drawLog() { } if (!logOpen) return; if (ImGui::Begin("Log Viewer",&logOpen)) { + ImGui::Checkbox("Follow",&followLog); + ImGui::SameLine(); ImGui::Text("Level"); ImGui::SameLine(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); ImGui::Combo("##LogLevel",&logLevel,logLevels,5); if (ImGui::BeginTable("LogView",3,ImGuiTableFlags_ScrollY|ImGuiTableFlags_BordersInnerV)) { ImGui::PushFont(patFont); @@ -53,17 +56,21 @@ void FurnaceGUI::drawLog() { const LogEntry& logEntry=logEntries[(pos+i)&(TA_LOG_SIZE-1)]; if (!logEntry.ready) continue; if (logLevel(logEntry.time).time_since_epoch().count(); + String t=date::format("%T",date::make_zoned(date::current_zone(),date::floor(logEntry.time))); ImGui::TableNextRow(); ImGui::TableNextColumn(); // this will fail on 32-bit :< - ImGui::Text("%02ld:%02ld:%02ld",(t/3600)%24,(t/60)%60,t%60); + ImGui::TextUnformatted(t.c_str()); ImGui::TableNextColumn(); ImGui::TextColored(uiColors[logColors[logEntry.loglevel]],"%s",logLevels[logEntry.loglevel]); ImGui::TableNextColumn(); ImGui::TextWrapped("%s",logEntry.text.c_str()); } ImGui::PopFont(); + + if (followLog) { + ImGui::SetScrollY(ImGui::GetScrollMaxY()); + } ImGui::EndTable(); } } From 1d2c08bbf27859d17c7ff867761636f44203a864 Mon Sep 17 00:00:00 2001 From: Alex <99325922+ActualNK358@users.noreply.github.com> Date: Sun, 10 Apr 2022 23:03:33 -0500 Subject: [PATCH 63/76] Demo Song update: Fixing typo and crediting arranger --- demos/silverlining.fur | Bin 24216 -> 24250 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/demos/silverlining.fur b/demos/silverlining.fur index 06567d7313d66cd2f4236e40215dad829cc3082f..9ad4a88159094c0c0b973b4ce4fa39404d5ae269 100644 GIT binary patch literal 24250 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 literal 24216 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 Date: Sun, 10 Apr 2022 23:15:06 -0500 Subject: [PATCH 64/76] CI: don't be verbose i spend too much time scrolling through the logs --- .github/workflows/build.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2fbae0f5..86466036 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -165,7 +165,6 @@ jobs: - name: Build (System Libraries) if: ${{ runner.os == 'Linux' && matrix.config.compiler != 'mingw' }} run: | - export VERBOSE=1 cmake \ --build ${PWD}/build \ --config ${{ env.BUILD_TYPE }} \ @@ -214,7 +213,6 @@ jobs: - name: Build run: | - export VERBOSE=1 cmake \ --build ${PWD}/build \ --config ${{ env.BUILD_TYPE }} \ From 92b8703574dfc4897aef8568f13a4c40be6a6f2d Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 10 Apr 2022 23:20:25 -0500 Subject: [PATCH 65/76] try fixing the build if this doesn't work then goodbye Date --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index ae93abda..2989a36f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -139,6 +139,7 @@ if (SYSTEM_DATE) message(STATUS "Using system-installed Date") else() set(BUILD_TZ_LIB ON CACHE BOOL "build/install of TZ library" FORCE) + set(USE_SYSTEM_TZ_DB ON CACHE BOOL "Fix the build already" FORCE) add_subdirectory(extern/date EXCLUDE_FROM_ALL) list(APPEND DEPENDENCIES_INCLUDE_DIRS extern/date/include) list(APPEND DEPENDENCIES_LIBRARIES date date-tz) From 9e0e7258026dba86292260fb6212a9f6d7d057e1 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 11 Apr 2022 00:12:24 -0500 Subject: [PATCH 66/76] Sorry but I think I'd like to go now. --- .gitmodules | 3 --- CMakeLists.txt | 20 -------------------- extern/date | 1 - src/gui/log.cpp | 8 ++------ src/log.cpp | 9 +++++++-- src/ta-log.h | 4 ++-- 6 files changed, 11 insertions(+), 34 deletions(-) delete mode 160000 extern/date diff --git a/.gitmodules b/.gitmodules index e96848c3..d63fd70b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -22,6 +22,3 @@ [submodule "extern/Nuked-OPL3"] path = extern/Nuked-OPL3 url = https://github.com/nukeykt/Nuked-OPL3.git -[submodule "extern/date"] - path = extern/date - url = https://github.com/HowardHinnant/date diff --git a/CMakeLists.txt b/CMakeLists.txt index 2989a36f..d3b98fc6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -42,7 +42,6 @@ option(SYSTEM_LIBSNDFILE "Use a system-installed version of libsndfile instead o option(SYSTEM_RTMIDI "Use a system-installed version of RtMidi instead of the vendored one" OFF) option(SYSTEM_ZLIB "Use a system-installed version of zlib instead of the vendored one" OFF) option(SYSTEM_SDL2 "Use a system-installed version of SDL2 instead of the vendored one" ${SYSTEM_SDL2_DEFAULT}) -option(SYSTEM_DATE "Use a system-installed version of Date instead of the vendored one" OFF) option(WARNINGS_ARE_ERRORS "Whether warnings in furnace's C++ code should be treated as errors" OFF) set(DEPENDENCIES_INCLUDE_DIRS "") @@ -127,25 +126,6 @@ if (USE_RTMIDI) endif() endif() -if (SYSTEM_DATE) - find_package(PkgConfig REQUIRED) - pkg_check_modules(HHDATE REQUIRED date) - list(APPEND DEPENDENCIES_INCLUDE_DIRS ${HHDATE_INCLUDE_DIRS}) - list(APPEND DEPENDENCIES_COMPILE_OPTIONS ${HHDATE_CFLAGS_OTHER}) - list(APPEND DEPENDENCIES_LIBRARIES ${HHDATE_LIBRARIES}) - list(APPEND DEPENDENCIES_LIBRARY_DIRS ${HHDATE_LIBRARY_DIRS}) - list(APPEND DEPENDENCIES_LINK_OPTIONS ${HHDATE_LDFLAGS_OTHER}) - list(APPEND DEPENDENCIES_LEGACY_LDFLAGS ${HHDATE_LDFLAGS}) - message(STATUS "Using system-installed Date") -else() - set(BUILD_TZ_LIB ON CACHE BOOL "build/install of TZ library" FORCE) - set(USE_SYSTEM_TZ_DB ON CACHE BOOL "Fix the build already" FORCE) - add_subdirectory(extern/date EXCLUDE_FROM_ALL) - list(APPEND DEPENDENCIES_INCLUDE_DIRS extern/date/include) - list(APPEND DEPENDENCIES_LIBRARIES date date-tz) - message(STATUS "Using vendored Date") -endif() - if (SYSTEM_ZLIB) find_package(PkgConfig REQUIRED) pkg_check_modules(ZLIB REQUIRED zlib) diff --git a/extern/date b/extern/date deleted file mode 160000 index 9ea5654c..00000000 --- a/extern/date +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 9ea5654c1206e19245dc21d8a2c433e090c8c3f5 diff --git a/src/gui/log.cpp b/src/gui/log.cpp index b6536cdb..2246df4e 100644 --- a/src/gui/log.cpp +++ b/src/gui/log.cpp @@ -1,7 +1,5 @@ #include "gui.h" #include "../ta-log.h" -#include -#include "date/tz.h" const char* logLevels[5]={ "ERROR", @@ -56,11 +54,9 @@ void FurnaceGUI::drawLog() { const LogEntry& logEntry=logEntries[(pos+i)&(TA_LOG_SIZE-1)]; if (!logEntry.ready) continue; if (logLevel(logEntry.time))); ImGui::TableNextRow(); ImGui::TableNextColumn(); - // this will fail on 32-bit :< - ImGui::TextUnformatted(t.c_str()); + ImGui::Text("%02d:%02d:%02d",logEntry.time.tm_hour,logEntry.time.tm_min,logEntry.time.tm_sec); ImGui::TableNextColumn(); ImGui::TextColored(uiColors[logColors[logEntry.loglevel]],"%s",logLevels[logEntry.loglevel]); ImGui::TableNextColumn(); @@ -75,4 +71,4 @@ void FurnaceGUI::drawLog() { } } ImGui::End(); -} \ No newline at end of file +} diff --git a/src/log.cpp b/src/log.cpp index a3a6000c..d0ea0603 100644 --- a/src/log.cpp +++ b/src/log.cpp @@ -90,11 +90,16 @@ int logE(const char* format, ...) { } int writeLog(int level, const char* msg, fmt::printf_args& args) { + time_t thisMakesNoSense=time(NULL); int pos=logPosition; logPosition=(logPosition+1)&TA_LOG_MASK; logEntries[pos].text=fmt::vsprintf(msg,args); - logEntries[pos].time=std::chrono::system_clock::now(); + // why do I have to pass a pointer + // can't I just pass the time_t directly?! + if (localtime_r(&thisMakesNoSense,&logEntries[pos].time)==NULL) { + memset(&logEntries[pos].time,0,sizeof(struct tm)); + } logEntries[pos].loglevel=level; logEntries[pos].ready=true; @@ -119,4 +124,4 @@ void initLog() { for (int i=0; i #include #include +#include #include #include #include @@ -41,7 +41,7 @@ extern std::atomic logPosition; struct LogEntry { int loglevel; - std::chrono::system_clock::time_point time; + struct tm time; std::string text; bool ready; LogEntry(): From 8a49522e5956b271a76645f2588aa30f893a4154 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 11 Apr 2022 01:41:45 -0500 Subject: [PATCH 67/76] beta 1-3 .dmf loading i did it --- src/engine/fileOps.cpp | 309 ++++++++++++++++++++++++++--------------- 1 file changed, 195 insertions(+), 114 deletions(-) diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index 8514d91a..356e40e7 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -53,6 +53,10 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { warnings=""; try { DivSong ds; + unsigned char historicColIns[DIV_MAX_CHANS]; + for (int i=0; i0x03) { + if (ds.version>0x05) { ds.speed2=reader.readC(); ds.pal=reader.readC(); ds.hz=(ds.pal)?60:50; @@ -258,7 +262,9 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { addWarning("Yamaha YMU759 emulation is incomplete! please migrate your song to the OPL3 system."); } - logI("reading pattern matrix (%d)...",ds.ordersLen); + logV("%x",reader.tell()); + + logI("reading pattern matrix (%d * %d = %d)...",ds.ordersLen,getChannelCount(ds.system[0]),ds.ordersLen*getChannelCount(ds.system[0])); for (int i=0; iname=reader.readString((unsigned char)reader.readC()); } } + if (ds.version>0x03 && ds.version<0x06 && i<16) { + historicColIns[i]=reader.readC(); + } } - if (ds.version>0x03) { + logV("%x",reader.tell()); + + if (ds.version>0x05) { ds.insLen=(unsigned char)reader.readC(); } else { ds.insLen=16; @@ -282,7 +293,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { logI("reading instruments (%d)...",ds.insLen); for (int i=0; i0x03) { + if (ds.version>0x05) { ins->name=reader.readString((unsigned char)reader.readC()); } logD("%d name: %s",i,ins->name.c_str()); @@ -319,29 +330,41 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { } if (ins->mode) { // FM - ins->fm.alg=reader.readC(); - if (ds.version<0x13) { - reader.readC(); - } - ins->fm.fb=reader.readC(); - if (ds.version<0x13) { - reader.readC(); - } - ins->fm.fms=reader.readC(); - if (ds.version<0x13) { - reader.readC(); - ins->fm.ops=2+reader.readC()*2; - if (ds.system[0]!=DIV_SYSTEM_YMU759) ins->fm.ops=4; + if (ds.version>0x05) { + ins->fm.alg=reader.readC(); + if (ds.version<0x13) { + reader.readC(); + } + ins->fm.fb=reader.readC(); + if (ds.version<0x13) { + reader.readC(); + } + ins->fm.fms=reader.readC(); + if (ds.version<0x13) { + reader.readC(); + ins->fm.ops=2+reader.readC()*2; + if (ds.system[0]!=DIV_SYSTEM_YMU759) ins->fm.ops=4; + } else { + ins->fm.ops=4; + } + ins->fm.ams=reader.readC(); } else { - ins->fm.ops=4; + ins->fm.alg=reader.readC(); + reader.readC(); + ins->fm.fb=reader.readC(); + reader.readC(); // apparently an index of sorts starting from 0x59? + ins->fm.fms=reader.readC(); + reader.readC(); // 0x59+index? + ins->fm.ops=2+reader.readC()*2; } + + logD("ALG %d FB %d FMS %d AMS %d OPS %d",ins->fm.alg,ins->fm.fb,ins->fm.fms,ins->fm.ams,ins->fm.ops); if (ins->fm.ops!=2 && ins->fm.ops!=4) { logE("invalid op count %d. did we read it wrong?",ins->fm.ops); lastError="file is corrupt or unreadable at operators"; delete[] file; return false; } - ins->fm.ams=reader.readC(); for (int j=0; jfm.ops; j++) { ins->fm.op[j].am=reader.readC(); @@ -385,7 +408,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { ins->fm.op[j].dt2=reader.readC(); } } - if (ds.version>0x03) { + if (ds.version>0x05) { if (ds.system[0]==DIV_SYSTEM_SMS_OPLL || ds.system[0]==DIV_SYSTEM_NES_VRC7) { ins->fm.op[j].ksr=reader.readC(); ins->fm.op[j].vib=reader.readC(); @@ -588,6 +611,8 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { } } + logV("%x",reader.tell()); + logI("reading patterns (%d channels, %d orders)...",getChannelCount(ds.system[0]),ds.ordersLen); for (int i=0; i4 || chan.effectRows<1) { @@ -606,79 +630,110 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { } for (int j=0; jdata[k][0]=reader.readS(); - // octave - pat->data[k][1]=reader.readS(); - if (ds.system[0]==DIV_SYSTEM_SMS && ds.version<0x0e && pat->data[k][1]>0) { - // apparently it was up one octave before - pat->data[k][1]--; - } else if (ds.system[0]==DIV_SYSTEM_GENESIS && ds.version<0x0e && pat->data[k][1]>0 && i>5) { - // ditto - pat->data[k][1]--; - } - if (ds.version<0x12) { - if (ds.system[0]==DIV_SYSTEM_GB && i==3 && pat->data[k][1]>0) { - // back then noise was 2 octaves lower - pat->data[k][1]-=2; + if (ds.version>0x05) { // current pattern format + for (int k=0; kdata[k][0]=reader.readS(); + // octave + pat->data[k][1]=reader.readS(); + if (ds.system[0]==DIV_SYSTEM_SMS && ds.version<0x0e && pat->data[k][1]>0) { + // apparently it was up one octave before + pat->data[k][1]--; + } else if (ds.system[0]==DIV_SYSTEM_GENESIS && ds.version<0x0e && pat->data[k][1]>0 && i>5) { + // ditto + pat->data[k][1]--; + } + if (ds.version<0x12) { + if (ds.system[0]==DIV_SYSTEM_GB && i==3 && pat->data[k][1]>0) { + // back then noise was 2 octaves lower + pat->data[k][1]-=2; + } + } + if (ds.system[0]==DIV_SYSTEM_YMU759 && pat->data[k][0]!=0) { + // apparently YMU759 is stored 2 octaves lower + pat->data[k][1]+=2; + } + if (pat->data[k][0]==0 && pat->data[k][1]!=0) { + logD("what? %d:%d:%d note %d octave %d",i,j,k,pat->data[k][0],pat->data[k][1]); + pat->data[k][0]=12; + pat->data[k][1]--; + } + // volume + pat->data[k][3]=reader.readS(); + if (ds.version<0x0a) { + // back then volume was stored as 00-ff instead of 00-7f/0-f + if (i>5) { + pat->data[k][3]>>=4; + } else { + pat->data[k][3]>>=1; + } + } + if (ds.version<0x12) { + if (ds.system[0]==DIV_SYSTEM_GB && i==2 && pat->data[k][3]>0) { + // volume range of GB wave channel was 0-3 rather than 0-F + pat->data[k][3]=(pat->data[k][3]&3)*5; + } + } + for (int l=0; ldata[k][4+(l<<1)]=reader.readS(); + pat->data[k][5+(l<<1)]=reader.readS(); + + if (ds.version<0x14) { + if (pat->data[k][4+(l<<1)]==0xe5 && pat->data[k][5+(l<<1)]!=-1) { + pat->data[k][5+(l<<1)]=128+((pat->data[k][5+(l<<1)]-128)/4); + } + } + } + // instrument + pat->data[k][2]=reader.readS(); + + // this is sad + if (ds.system[0]==DIV_SYSTEM_NES_FDS) { + if (i==5 && pat->data[k][2]!=-1) { + if (pat->data[k][2]>=0 && pat->data[k][2]data[k][2]]->type=DIV_INS_FDS; + } + } } } - if (ds.system[0]==DIV_SYSTEM_YMU759 && pat->data[k][0]!=0) { - // apparently YMU759 is stored 2 octaves lower - pat->data[k][1]+=2; - } - if (pat->data[k][0]==0 && pat->data[k][1]!=0) { - logD("what? %d:%d:%d note %d octave %d",i,j,k,pat->data[k][0],pat->data[k][1]); - pat->data[k][0]=12; - pat->data[k][1]--; - } - // volume - pat->data[k][3]=reader.readS(); - if (ds.version<0x0a) { - // back then volume was stored as 00-ff instead of 00-7f/0-f - if (i>5) { - pat->data[k][3]>>=4; - } else { - pat->data[k][3]>>=1; + } else { // historic pattern format + if (i<16) pat->data[0][2]=historicColIns[i]; + for (int k=0; kdata[k][0]=reader.readC(); + // octave + pat->data[k][1]=reader.readC(); + if (pat->data[k][0]!=0) { + // YMU759 is stored 2 octaves lower + pat->data[k][1]+=2; } - } - if (ds.version<0x12) { - if (ds.system[0]==DIV_SYSTEM_GB && i==2 && pat->data[k][3]>0) { - // volume range of GB wave channel was 0-3 rather than 0-F - pat->data[k][3]=(pat->data[k][3]&3)*5; + if (pat->data[k][0]==0 && pat->data[k][1]!=0) { + logD("what? %d:%d:%d note %d octave %d",i,j,k,pat->data[k][0],pat->data[k][1]); + pat->data[k][0]=12; + pat->data[k][1]--; } - } - for (int l=0; ldata[k][3]=(vol==0x80)?-1:vol; // effect - pat->data[k][4+(l<<1)]=reader.readS(); - pat->data[k][5+(l<<1)]=reader.readS(); - - if (ds.version<0x14) { - if (pat->data[k][4+(l<<1)]==0xe5 && pat->data[k][5+(l<<1)]!=-1) { - pat->data[k][5+(l<<1)]=128+((pat->data[k][5+(l<<1)]-128)/4); - } - } - } - // instrument - pat->data[k][2]=reader.readS(); - - // this is sad - if (ds.system[0]==DIV_SYSTEM_NES_FDS) { - if (i==5 && pat->data[k][2]!=-1) { - if (pat->data[k][2]>=0 && pat->data[k][2]data[k][2]]->type=DIV_INS_FDS; - } - } + pat->data[k][4]=(fx==0x80)?-1:fx; + pat->data[k][5]=(fxVal==0x80)?-1:fxVal; + // instrument wasn't stored back then } } } } + int ymuSampleRate=20; + ds.sampleLen=(unsigned char)reader.readC(); logI("reading samples (%d)...",ds.sampleLen); - if (ds.version<0x0b && ds.sampleLen>0) { // TODO what is this for? - reader.readC(); + if (ds.version<0x0b && ds.sampleLen>0) { + // it appears this byte stored the YMU759 sample rate + ymuSampleRate=reader.readC(); } for (int i=0; irate=ymuSampleRate*400; + } if (ds.version>0x15) { sample->depth=reader.readC(); if (sample->depth!=8 && sample->depth!=16) { @@ -711,43 +770,65 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { sample->depth=16; } } else { - sample->depth=16; + if (ds.version>0x05) { + sample->depth=16; + } else { + // it appears samples were stored as ADPCM back then + sample->depth=6; + } } if (length>0) { - if (ds.version<0x0b) { - data=new short[1+(length/2)]; - reader.read(data,length); - length/=2; - } else { - data=new short[length]; - reader.read(data,length*2); - } - - if (pitch!=5) { - logD("%d: scaling from %d...",i,pitch); - } - - // render data - if (!sample->init((double)length/samplePitches[pitch])) { - logE("%d: error while initializing sample!",i); - } - - unsigned int k=0; - float mult=(float)(vol)/50.0f; - for (double j=0; j=sample->samples) { - break; - } - if (sample->depth==8) { - float next=(float)(data[(unsigned int)j]-0x80)*mult; - sample->data8[k++]=fmin(fmax(next,-128),127); + if (ds.version>0x05) { + if (ds.version<0x0b) { + data=new short[1+(length/2)]; + reader.read(data,length); + length/=2; } else { - float next=(float)data[(unsigned int)j]*mult; - sample->data16[k++]=fmin(fmax(next,-32768),32767); + data=new short[length]; + reader.read(data,length*2); } - } - delete[] data; + if (pitch!=5) { + logD("%d: scaling from %d...",i,pitch); + } + + // render data + if (!sample->init((double)length/samplePitches[pitch])) { + logE("%d: error while initializing sample!",i); + } + + unsigned int k=0; + float mult=(float)(vol)/50.0f; + for (double j=0; j=sample->samples) { + break; + } + if (sample->depth==8) { + float next=(float)(data[(unsigned int)j]-0x80)*mult; + sample->data8[k++]=fmin(fmax(next,-128),127); + } else { + float next=(float)data[(unsigned int)j]*mult; + sample->data16[k++]=fmin(fmax(next,-32768),32767); + } + } + + delete[] data; + } else { + // ADPCM? + // it appears to be a slightly modified version of ADPCM-B! + adpcmData=new unsigned char[length]; + logV("%x",reader.tell()); + reader.read(adpcmData,length); + for (int i=0; i>4); + } + if (!sample->init(length*2)) { + logE("%d: error while initializing sample!",i); + } + + memcpy(sample->dataB,adpcmData,length); + delete[] adpcmData; + } } ds.sample.push_back(sample); } From 39784bc7c2e35310e286c9649cd1002121d92378 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 11 Apr 2022 01:58:41 -0500 Subject: [PATCH 68/76] YMU759 samples at 48KHz --- src/engine/platform/opl.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/engine/platform/opl.cpp b/src/engine/platform/opl.cpp index 040c8035..3e222eec 100644 --- a/src/engine/platform/opl.cpp +++ b/src/engine/platform/opl.cpp @@ -1067,6 +1067,11 @@ void DivPlatformOPL::setFlags(unsigned int flags) { chipClock=COLOR_NTSC; rate=chipClock/72; } + + if (pretendYMU) { + rate=48000; + chipClock=rate*288; + } } int DivPlatformOPL::init(DivEngine* p, int channels, int sugRate, unsigned int flags) { From d485411727dd744f0791f480feebde94db502411 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 11 Apr 2022 02:01:23 -0500 Subject: [PATCH 69/76] hopefully fix Windows build --- src/log.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/log.cpp b/src/log.cpp index d0ea0603..7f7fae8a 100644 --- a/src/log.cpp +++ b/src/log.cpp @@ -97,9 +97,18 @@ int writeLog(int level, const char* msg, fmt::printf_args& args) { logEntries[pos].text=fmt::vsprintf(msg,args); // why do I have to pass a pointer // can't I just pass the time_t directly?! +#ifdef _WIN32 + struct tm* tempTM=localtime(&thisMakesNoSense); + if (tempTM==NULL) { + memset(&logEntries[pos].time,0,sizeof(struct tm)); + } else { + memcpy(&logEntries[pos].time,tempTM,sizeof(struct tm)); + } +#else if (localtime_r(&thisMakesNoSense,&logEntries[pos].time)==NULL) { memset(&logEntries[pos].time,0,sizeof(struct tm)); } +#endif logEntries[pos].loglevel=level; logEntries[pos].ready=true; From 45f1c827792225c2e8dad69a1b269f1f16645482 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 11 Apr 2022 02:05:58 -0500 Subject: [PATCH 70/76] sorry --- .github/workflows/build.yml | 2 +- CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 86466036..293c4cd0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -143,7 +143,7 @@ jobs: else # Test with system libs CMAKE_EXTRA_ARGS+=( - '-DSYSTEM_FMT=ON' + '-DSYSTEM_FMT=OFF' '-DSYSTEM_LIBSNDFILE=ON' '-DSYSTEM_RTMIDI=ON' '-DSYSTEM_ZLIB=ON' diff --git a/CMakeLists.txt b/CMakeLists.txt index d3b98fc6..498f3df6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -65,7 +65,7 @@ list(APPEND DEPENDENCIES_LIBRARIES ${CMAKE_THREAD_LIBS_INIT}) if (SYSTEM_FMT) if (PKG_CONFIG_FOUND) - pkg_check_modules(FMT fmt) + pkg_check_modules(FMT fmt>=7.1.0) if (FMT_FOUND) list(APPEND DEPENDENCIES_INCLUDE_DIRS ${FMT_INCLUDE_DIRS}) list(APPEND DEPENDENCIES_COMPILE_OPTIONS ${FMT_CFLAGS_OTHER}) From 283d74c32fc002960994d92ca373d27c6fb8075a Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 11 Apr 2022 02:39:06 -0500 Subject: [PATCH 71/76] GUI: friendlier name for N163 TDM disable --- src/gui/sysConf.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/sysConf.cpp b/src/gui/sysConf.cpp index 5b2aa658..40cc67a3 100644 --- a/src/gui/sysConf.cpp +++ b/src/gui/sysConf.cpp @@ -373,7 +373,7 @@ void FurnaceGUI::drawSysConf(int i) { updateWindowTitle(); } rightClickable bool n163Multiplex=flags&128; - if (ImGui::Checkbox("Disable Multiplexed Output",&n163Multiplex)) { + if (ImGui::Checkbox("Disable hissing",&n163Multiplex)) { e->setSysFlags(i,(flags&(~128))|(n163Multiplex<<7),restart); updateWindowTitle(); } From 7905b813e0eea1486f942d528b56ce4a00a645fd Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 11 Apr 2022 02:45:02 -0500 Subject: [PATCH 72/76] GUI: TableSetupScrollFreeze() for log view --- src/gui/log.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/gui/log.cpp b/src/gui/log.cpp index 2246df4e..c6c4e2a8 100644 --- a/src/gui/log.cpp +++ b/src/gui/log.cpp @@ -1,5 +1,6 @@ #include "gui.h" #include "../ta-log.h" +#include const char* logLevels[5]={ "ERROR", @@ -41,6 +42,8 @@ void FurnaceGUI::drawLog() { ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthFixed,levelChars); ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch); + ImGui::TableSetupScrollFreeze(0,1); + ImGui::TableNextRow(ImGuiTableRowFlags_Headers); ImGui::TableNextColumn(); ImGui::TextUnformatted("time"); From ac286fc8d102eaf49f0b3b97d123b3404d6628ea Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 11 Apr 2022 02:53:21 -0500 Subject: [PATCH 73/76] GUI: real-time color setting preview --- src/gui/gui.cpp | 1 + src/gui/gui.h | 2 +- src/gui/settings.cpp | 219 ++++++++++++++++++++++--------------------- 3 files changed, 116 insertions(+), 106 deletions(-) diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 4b3542b1..94848977 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -2928,6 +2928,7 @@ bool FurnaceGUI::loop() { break; case GUI_WARN_RESET_COLORS: resetColors(); + applyUISettings(false); break; case GUI_WARN_GENERIC: break; diff --git a/src/gui/gui.h b/src/gui/gui.h index cadc84d4..83082835 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1126,7 +1126,7 @@ class FurnaceGUI { int load(String path); void exportAudio(String path, DivAudioExportModes mode); - void applyUISettings(); + void applyUISettings(bool updateFonts=true); void initSystemPresets(); void encodeMMLStr(String& target, int* macro, int macroLen, int macroLoop, int macroRel, bool hex=false); diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index 2727c3a3..215958fa 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -148,7 +148,9 @@ const char* specificControls[18]={ } #define UI_COLOR_CONFIG(what,label) \ - ImGui::ColorEdit4(label "##CC_" #what,(float*)&uiColors[what]); + if (ImGui::ColorEdit4(label "##CC_" #what,(float*)&uiColors[what])) { \ + applyUISettings(false); \ + } #define KEYBIND_CONFIG_BEGIN(id) \ if (ImGui::BeginTable(id,2)) { @@ -1702,6 +1704,7 @@ bool FurnaceGUI::importColors(String path) { } } fclose(f); + applyUISettings(false); return true; } @@ -1945,7 +1948,7 @@ void FurnaceGUI::parseKeybinds() { #define SYSTEM_PAT_FONT_PATH_3 "/usr/share/fonts/ubuntu/UbuntuMono-R.ttf" #endif -void FurnaceGUI::applyUISettings() { +void FurnaceGUI::applyUISettings(bool updateFonts) { ImGuiStyle sty; if (settings.guiColorsBase) { ImGui::StyleColorsLight(&sty); @@ -1956,8 +1959,10 @@ void FurnaceGUI::applyUISettings() { if (settings.dpiScale>=0.5f) dpiScale=settings.dpiScale; // colors - for (int i=0; igetConfInt(guiColors[i].name,guiColors[i].defaultColor)); + if (updateFonts) { + for (int i=0; igetConfInt(guiColors[i].name,guiColors[i].defaultColor)); + } } for (int i=0; i<64; i++) { @@ -2085,120 +2090,122 @@ void FurnaceGUI::applyUISettings() { sysCmd2Grad[i]=ImGui::GetColorU32(ImVec4(base.x,base.y,base.z,((float)i/255.0f)*base.w)); } - // set to 800 for now due to problems with unifont - static const ImWchar upTo800[]={0x20,0x7e,0xa0,0x800,0}; - ImFontGlyphRangesBuilder range; - ImVector outRange; + if (updateFonts) { + // set to 800 for now due to problems with unifont + static const ImWchar upTo800[]={0x20,0x7e,0xa0,0x800,0}; + ImFontGlyphRangesBuilder range; + ImVector outRange; - range.AddRanges(upTo800); - if (settings.loadJapanese) { - range.AddRanges(ImGui::GetIO().Fonts->GetGlyphRangesJapanese()); - } - // I'm terribly sorry - range.UsedChars[0x80>>5]=0; + range.AddRanges(upTo800); + if (settings.loadJapanese) { + range.AddRanges(ImGui::GetIO().Fonts->GetGlyphRangesJapanese()); + } + // I'm terribly sorry + range.UsedChars[0x80>>5]=0; - range.BuildRanges(&outRange); - if (fontRange!=NULL) delete[] fontRange; - fontRange=new ImWchar[outRange.size()]; - int index=0; - for (ImWchar& i: outRange) { - fontRange[index++]=i; - } + range.BuildRanges(&outRange); + if (fontRange!=NULL) delete[] fontRange; + fontRange=new ImWchar[outRange.size()]; + int index=0; + for (ImWchar& i: outRange) { + fontRange[index++]=i; + } - if (settings.mainFont<0 || settings.mainFont>6) settings.mainFont=0; - if (settings.patFont<0 || settings.patFont>6) settings.patFont=0; + if (settings.mainFont<0 || settings.mainFont>6) settings.mainFont=0; + if (settings.patFont<0 || settings.patFont>6) settings.patFont=0; - if (settings.mainFont==6 && settings.mainFontPath.empty()) { - logW("UI font path is empty! reverting to default font"); - settings.mainFont=0; - } - if (settings.patFont==6 && settings.patFontPath.empty()) { - logW("pattern font path is empty! reverting to default font"); - settings.patFont=0; - } - - ImFontConfig fc1; - fc1.MergeMode=true; - - if (settings.mainFont==6) { // custom font - if ((mainFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(settings.mainFontPath.c_str(),e->getConfInt("mainFontSize",18)*dpiScale,NULL,fontRange))==NULL) { - logW("could not load UI font! reverting to default font"); + if (settings.mainFont==6 && settings.mainFontPath.empty()) { + logW("UI font path is empty! reverting to default font"); settings.mainFont=0; - if ((mainFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFont[settings.mainFont],builtinFontLen[settings.mainFont],e->getConfInt("mainFontSize",18)*dpiScale,NULL,fontRange))==NULL) { - logE("could not load UI font! falling back to Proggy Clean."); - mainFont=ImGui::GetIO().Fonts->AddFontDefault(); - } } - } else if (settings.mainFont==5) { // system font - if ((mainFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_FONT_PATH_1,e->getConfInt("mainFontSize",18)*dpiScale,NULL,fontRange))==NULL) { - if ((mainFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_FONT_PATH_2,e->getConfInt("mainFontSize",18)*dpiScale,NULL,fontRange))==NULL) { - if ((mainFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_FONT_PATH_3,e->getConfInt("mainFontSize",18)*dpiScale,NULL,fontRange))==NULL) { - logW("could not load UI font! reverting to default font"); - settings.mainFont=0; - if ((mainFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFont[settings.mainFont],builtinFontLen[settings.mainFont],e->getConfInt("mainFontSize",18)*dpiScale,NULL,fontRange))==NULL) { - logE("could not load UI font! falling back to Proggy Clean."); - mainFont=ImGui::GetIO().Fonts->AddFontDefault(); - } + if (settings.patFont==6 && settings.patFontPath.empty()) { + logW("pattern font path is empty! reverting to default font"); + settings.patFont=0; + } + + ImFontConfig fc1; + fc1.MergeMode=true; + + if (settings.mainFont==6) { // custom font + if ((mainFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(settings.mainFontPath.c_str(),e->getConfInt("mainFontSize",18)*dpiScale,NULL,fontRange))==NULL) { + logW("could not load UI font! reverting to default font"); + settings.mainFont=0; + if ((mainFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFont[settings.mainFont],builtinFontLen[settings.mainFont],e->getConfInt("mainFontSize",18)*dpiScale,NULL,fontRange))==NULL) { + logE("could not load UI font! falling back to Proggy Clean."); + mainFont=ImGui::GetIO().Fonts->AddFontDefault(); } } - } - } else { - if ((mainFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFont[settings.mainFont],builtinFontLen[settings.mainFont],e->getConfInt("mainFontSize",18)*dpiScale,NULL,fontRange))==NULL) { - logE("could not load UI font! falling back to Proggy Clean."); - mainFont=ImGui::GetIO().Fonts->AddFontDefault(); - } - } - - // two fallback fonts - mainFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(font_liberationSans_compressed_data,font_liberationSans_compressed_size,e->getConfInt("mainFontSize",18)*dpiScale,&fc1,fontRange); - mainFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(font_unifont_compressed_data,font_unifont_compressed_size,e->getConfInt("mainFontSize",18)*dpiScale,&fc1,fontRange); - - ImFontConfig fc; - fc.MergeMode=true; - fc.GlyphMinAdvanceX=e->getConfInt("iconSize",16)*dpiScale; - static const ImWchar fontRangeIcon[]={ICON_MIN_FA,ICON_MAX_FA,0}; - if ((iconFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(iconFont_compressed_data,iconFont_compressed_size,e->getConfInt("iconSize",16)*dpiScale,&fc,fontRangeIcon))==NULL) { - logE("could not load icon font!"); - } - if (settings.mainFontSize==settings.patFontSize && settings.patFont<5 && builtinFontM[settings.patFont]==builtinFont[settings.mainFont]) { - logD("using main font for pat font."); - patFont=mainFont; - } else { - if (settings.patFont==6) { // custom font - if ((patFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(settings.patFontPath.c_str(),e->getConfInt("patFontSize",18)*dpiScale,NULL,upTo800))==NULL) { - logW("could not load pattern font! reverting to default font"); - settings.patFont=0; - if ((patFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFontM[settings.patFont],builtinFontMLen[settings.patFont],e->getConfInt("patFontSize",18)*dpiScale,NULL,upTo800))==NULL) { - logE("could not load pattern font! falling back to Proggy Clean."); - patFont=ImGui::GetIO().Fonts->AddFontDefault(); - } - } - } else if (settings.patFont==5) { // system font - if ((patFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_PAT_FONT_PATH_1,e->getConfInt("patFontSize",18)*dpiScale,NULL,upTo800))==NULL) { - if ((patFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_PAT_FONT_PATH_2,e->getConfInt("patFontSize",18)*dpiScale,NULL,upTo800))==NULL) { - if ((patFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_PAT_FONT_PATH_3,e->getConfInt("patFontSize",18)*dpiScale,NULL,upTo800))==NULL) { - logW("could not load pattern font! reverting to default font"); - settings.patFont=0; - if ((patFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFontM[settings.patFont],builtinFontMLen[settings.patFont],e->getConfInt("patFontSize",18)*dpiScale,NULL,upTo800))==NULL) { - logE("could not load pattern font! falling back to Proggy Clean."); - patFont=ImGui::GetIO().Fonts->AddFontDefault(); + } else if (settings.mainFont==5) { // system font + if ((mainFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_FONT_PATH_1,e->getConfInt("mainFontSize",18)*dpiScale,NULL,fontRange))==NULL) { + if ((mainFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_FONT_PATH_2,e->getConfInt("mainFontSize",18)*dpiScale,NULL,fontRange))==NULL) { + if ((mainFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_FONT_PATH_3,e->getConfInt("mainFontSize",18)*dpiScale,NULL,fontRange))==NULL) { + logW("could not load UI font! reverting to default font"); + settings.mainFont=0; + if ((mainFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFont[settings.mainFont],builtinFontLen[settings.mainFont],e->getConfInt("mainFontSize",18)*dpiScale,NULL,fontRange))==NULL) { + logE("could not load UI font! falling back to Proggy Clean."); + mainFont=ImGui::GetIO().Fonts->AddFontDefault(); } } } } } else { - if ((patFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFontM[settings.patFont],builtinFontMLen[settings.patFont],e->getConfInt("patFontSize",18)*dpiScale,NULL,upTo800))==NULL) { - logE("could not load pattern font!"); - patFont=ImGui::GetIO().Fonts->AddFontDefault(); + if ((mainFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFont[settings.mainFont],builtinFontLen[settings.mainFont],e->getConfInt("mainFontSize",18)*dpiScale,NULL,fontRange))==NULL) { + logE("could not load UI font! falling back to Proggy Clean."); + mainFont=ImGui::GetIO().Fonts->AddFontDefault(); } - } - } - if ((bigFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(font_plexSans_compressed_data,font_plexSans_compressed_size,40*dpiScale))==NULL) { - logE("could not load big UI font!"); - } + } - mainFont->FallbackChar='?'; - mainFont->DotChar='.'; + // two fallback fonts + mainFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(font_liberationSans_compressed_data,font_liberationSans_compressed_size,e->getConfInt("mainFontSize",18)*dpiScale,&fc1,fontRange); + mainFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(font_unifont_compressed_data,font_unifont_compressed_size,e->getConfInt("mainFontSize",18)*dpiScale,&fc1,fontRange); + + ImFontConfig fc; + fc.MergeMode=true; + fc.GlyphMinAdvanceX=e->getConfInt("iconSize",16)*dpiScale; + static const ImWchar fontRangeIcon[]={ICON_MIN_FA,ICON_MAX_FA,0}; + if ((iconFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(iconFont_compressed_data,iconFont_compressed_size,e->getConfInt("iconSize",16)*dpiScale,&fc,fontRangeIcon))==NULL) { + logE("could not load icon font!"); + } + if (settings.mainFontSize==settings.patFontSize && settings.patFont<5 && builtinFontM[settings.patFont]==builtinFont[settings.mainFont]) { + logD("using main font for pat font."); + patFont=mainFont; + } else { + if (settings.patFont==6) { // custom font + if ((patFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(settings.patFontPath.c_str(),e->getConfInt("patFontSize",18)*dpiScale,NULL,upTo800))==NULL) { + logW("could not load pattern font! reverting to default font"); + settings.patFont=0; + if ((patFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFontM[settings.patFont],builtinFontMLen[settings.patFont],e->getConfInt("patFontSize",18)*dpiScale,NULL,upTo800))==NULL) { + logE("could not load pattern font! falling back to Proggy Clean."); + patFont=ImGui::GetIO().Fonts->AddFontDefault(); + } + } + } else if (settings.patFont==5) { // system font + if ((patFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_PAT_FONT_PATH_1,e->getConfInt("patFontSize",18)*dpiScale,NULL,upTo800))==NULL) { + if ((patFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_PAT_FONT_PATH_2,e->getConfInt("patFontSize",18)*dpiScale,NULL,upTo800))==NULL) { + if ((patFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_PAT_FONT_PATH_3,e->getConfInt("patFontSize",18)*dpiScale,NULL,upTo800))==NULL) { + logW("could not load pattern font! reverting to default font"); + settings.patFont=0; + if ((patFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFontM[settings.patFont],builtinFontMLen[settings.patFont],e->getConfInt("patFontSize",18)*dpiScale,NULL,upTo800))==NULL) { + logE("could not load pattern font! falling back to Proggy Clean."); + patFont=ImGui::GetIO().Fonts->AddFontDefault(); + } + } + } + } + } else { + if ((patFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFontM[settings.patFont],builtinFontMLen[settings.patFont],e->getConfInt("patFontSize",18)*dpiScale,NULL,upTo800))==NULL) { + logE("could not load pattern font!"); + patFont=ImGui::GetIO().Fonts->AddFontDefault(); + } + } + } + if ((bigFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(font_plexSans_compressed_data,font_plexSans_compressed_size,40*dpiScale))==NULL) { + logE("could not load big UI font!"); + } + + mainFont->FallbackChar='?'; + mainFont->DotChar='.'; + } // TODO: allow changing these colors. ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByTypeDir,"",uiColors[GUI_COLOR_FILE_DIR],ICON_FA_FOLDER_O); @@ -2224,6 +2231,8 @@ void FurnaceGUI::applyUISettings() { ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".fti",uiColors[GUI_COLOR_FILE_INSTR],ICON_FA_FILE); ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".bti",uiColors[GUI_COLOR_FILE_INSTR],ICON_FA_FILE); - if (fileDialog!=NULL) delete fileDialog; - fileDialog=new FurnaceGUIFileDialog(settings.sysFileDialog); + if (updateFonts) { + if (fileDialog!=NULL) delete fileDialog; + fileDialog=new FurnaceGUIFileDialog(settings.sysFileDialog); + } } From 7bb0743598e205a403a995bf178280a6cf618402 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 11 Apr 2022 03:14:12 -0500 Subject: [PATCH 74/76] GUI: fix file path corruption on sys file picker --- src/gui/fileDialog.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/gui/fileDialog.cpp b/src/gui/fileDialog.cpp index a0a10103..c66a27e6 100644 --- a/src/gui/fileDialog.cpp +++ b/src/gui/fileDialog.cpp @@ -8,6 +8,7 @@ bool FurnaceGUIFileDialog::openLoad(String header, std::vector filter, c if (opened) return false; saving=false; curPath=path; + logD("opening load file dialog with curPath %s",curPath); if (sysDialog) { dialogO=new pfd::open_file(header,path,filter); } else { @@ -22,6 +23,7 @@ bool FurnaceGUIFileDialog::openSave(String header, std::vector filter, c if (opened) return false; saving=true; curPath=path; + logD("opening save file dialog with curPath %s",curPath); if (sysDialog) { dialogS=new pfd::save_file(header,path,filter); } else { @@ -65,6 +67,8 @@ bool FurnaceGUIFileDialog::render(const ImVec2& min, const ImVec2& max) { if (dialogS!=NULL) { if (dialogS->ready(0)) { fileName=dialogS->result(); + size_t dsPos=fileName.rfind(DIR_SEPARATOR); + if (dsPos!=String::npos) curPath=fileName.substr(0,dsPos); logD("returning %s",fileName.c_str()); return true; } @@ -77,6 +81,8 @@ bool FurnaceGUIFileDialog::render(const ImVec2& min, const ImVec2& max) { logD("returning nothing"); } else { fileName=dialogO->result()[0]; + size_t dsPos=fileName.rfind(DIR_SEPARATOR); + if (dsPos!=String::npos) curPath=fileName.substr(0,dsPos); logD("returning %s",fileName.c_str()); } return true; @@ -91,8 +97,15 @@ bool FurnaceGUIFileDialog::render(const ImVec2& min, const ImVec2& max) { String FurnaceGUIFileDialog::getPath() { if (sysDialog) { + if (curPath.size()>0) { + if (curPath[curPath.size()-1]==DIR_SEPARATOR) { + curPath=curPath.substr(0,curPath.size()-1); + } + } + logD("curPath: %s",curPath); return curPath; } else { + logD("curPath: %s",ImGuiFileDialog::Instance()->GetCurrentPath()); return ImGuiFileDialog::Instance()->GetCurrentPath(); } } From 224d8e11e5ea2a4727d1270d98513873b2129e07 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 11 Apr 2022 03:34:38 -0500 Subject: [PATCH 75/76] GUI: add some oscilloscope settings --- src/gui/gui.h | 6 ++++++ src/gui/osc.cpp | 18 ++++++++++++------ src/gui/settings.cpp | 25 +++++++++++++++++++++++++ 3 files changed, 43 insertions(+), 6 deletions(-) diff --git a/src/gui/gui.h b/src/gui/gui.h index 83082835..7cc66c84 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -779,6 +779,9 @@ class FurnaceGUI { int titleBarSys; int frameBorders; int effectDeletionAltersValue; + int oscRoundedCorners; + int oscTakesEntireWindow; + int oscBorder; unsigned int maxUndoSteps; String mainFontPath; String patFontPath; @@ -839,6 +842,9 @@ class FurnaceGUI { titleBarSys(1), frameBorders(0), effectDeletionAltersValue(1), + oscRoundedCorners(1), + oscTakesEntireWindow(0), + oscBorder(1), maxUndoSteps(100), mainFontPath(""), patFontPath(""), diff --git a/src/gui/osc.cpp b/src/gui/osc.cpp index 9a1c6aff..c0ce978c 100644 --- a/src/gui/osc.cpp +++ b/src/gui/osc.cpp @@ -73,9 +73,11 @@ void FurnaceGUI::drawOsc() { } if (!oscOpen) return; ImGui::SetNextWindowSizeConstraints(ImVec2(64.0f*dpiScale,32.0f*dpiScale),ImVec2(scrW*dpiScale,scrH*dpiScale)); - /*ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding,ImVec2(0,0)); - ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing,ImVec2(0,0)); - ImGui::PushStyleVar(ImGuiStyleVar_ItemInnerSpacing,ImVec2(0,0));*/ + if (settings.oscTakesEntireWindow) { + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding,ImVec2(0,0)); + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing,ImVec2(0,0)); + ImGui::PushStyleVar(ImGuiStyleVar_ItemInnerSpacing,ImVec2(0,0)); + } if (ImGui::Begin("Oscilloscope",&oscOpen)) { if (oscZoomSlider) { if (ImGui::VSliderFloat("##OscZoom",ImVec2(20.0f*dpiScale,ImGui::GetContentRegionAvail().y),&oscZoom,0.5,2.0)) { @@ -110,7 +112,7 @@ void FurnaceGUI::drawOsc() { if (ImGui::ItemAdd(rect,ImGui::GetID("wsDisplay"))) { // https://github.com/ocornut/imgui/issues/3710 const int v0 = dl->VtxBuffer.Size; - dl->AddRectFilled(inRect.Min,inRect.Max,0xffffffff,8.0f*dpiScale); + dl->AddRectFilled(inRect.Min,inRect.Max,0xffffffff,settings.oscRoundedCorners?(8.0f*dpiScale):0.0f); const int v1 = dl->VtxBuffer.Size; for (int i=v0; iAddPolyline(waveform,512,color,ImDrawFlags_None,dpiScale); - dl->AddRect(rect.Min,rect.Max,borderColor,8.0f*dpiScale,0,2.0f*dpiScale); + if (settings.oscBorder) { + dl->AddRect(inRect.Min,inRect.Max,borderColor,settings.oscRoundedCorners?(8.0f*dpiScale):0.0f,0,1.5f*dpiScale); + } } if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) { oscZoomSlider=!oscZoomSlider; } } - //ImGui::PopStyleVar(3); + if (settings.oscTakesEntireWindow) { + ImGui::PopStyleVar(3); + } if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_OSCILLOSCOPE; ImGui::End(); } diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index 215958fa..87b79857 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -896,6 +896,25 @@ void FurnaceGUI::drawSettings() { ImGui::Separator(); + ImGui::Text("Oscilloscope settings:"); + + bool oscRoundedCornersB=settings.oscRoundedCorners; + if (ImGui::Checkbox("Rounded corners",&oscRoundedCornersB)) { + settings.oscRoundedCorners=oscRoundedCornersB; + } + + bool oscTakesEntireWindowB=settings.oscTakesEntireWindow; + if (ImGui::Checkbox("Fill entire window",&oscTakesEntireWindowB)) { + settings.oscTakesEntireWindow=oscTakesEntireWindowB; + } + + bool oscBorderB=settings.oscBorder; + if (ImGui::Checkbox("Border",&oscBorderB)) { + settings.oscBorder=oscBorderB; + } + + ImGui::Separator(); + if (ImGui::TreeNode("Color scheme")) { if (ImGui::Button("Import")) { openFileDialog(GUI_FILE_IMPORT_COLORS); @@ -1486,6 +1505,9 @@ void FurnaceGUI::syncSettings() { settings.titleBarSys=e->getConfInt("titleBarSys",1); settings.frameBorders=e->getConfInt("frameBorders",0); settings.effectDeletionAltersValue=e->getConfInt("effectDeletionAltersValue",1); + settings.oscRoundedCorners=e->getConfInt("oscRoundedCorners",1); + settings.oscTakesEntireWindow=e->getConfInt("oscTakesEntireWindow",0); + settings.oscBorder=e->getConfInt("oscBorder",1); clampSetting(settings.mainFontSize,2,96); clampSetting(settings.patFontSize,2,96); @@ -1613,6 +1635,9 @@ void FurnaceGUI::commitSettings() { e->setConf("titleBarSys",settings.titleBarSys); e->setConf("frameBorders",settings.frameBorders); e->setConf("effectDeletionAltersValue",settings.effectDeletionAltersValue); + e->setConf("oscRoundedCorners",settings.oscRoundedCorners); + e->setConf("oscTakesEntireWindow",settings.oscTakesEntireWindow); + e->setConf("oscBorder",settings.oscBorder); // colors for (int i=0; i Date: Mon, 11 Apr 2022 04:07:01 -0500 Subject: [PATCH 76/76] GUI: wait what? --- src/gui/fileDialog.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/gui/fileDialog.cpp b/src/gui/fileDialog.cpp index c66a27e6..7bfafb4a 100644 --- a/src/gui/fileDialog.cpp +++ b/src/gui/fileDialog.cpp @@ -8,7 +8,7 @@ bool FurnaceGUIFileDialog::openLoad(String header, std::vector filter, c if (opened) return false; saving=false; curPath=path; - logD("opening load file dialog with curPath %s",curPath); + logD("opening load file dialog with curPath %s",curPath.c_str()); if (sysDialog) { dialogO=new pfd::open_file(header,path,filter); } else { @@ -23,7 +23,7 @@ bool FurnaceGUIFileDialog::openSave(String header, std::vector filter, c if (opened) return false; saving=true; curPath=path; - logD("opening save file dialog with curPath %s",curPath); + logD("opening save file dialog with curPath %s",curPath.c_str()); if (sysDialog) { dialogS=new pfd::save_file(header,path,filter); } else { @@ -97,15 +97,14 @@ bool FurnaceGUIFileDialog::render(const ImVec2& min, const ImVec2& max) { String FurnaceGUIFileDialog::getPath() { if (sysDialog) { - if (curPath.size()>0) { + if (curPath.size()>1) { if (curPath[curPath.size()-1]==DIR_SEPARATOR) { curPath=curPath.substr(0,curPath.size()-1); } } - logD("curPath: %s",curPath); + logD("curPath: %s",curPath.c_str()); return curPath; } else { - logD("curPath: %s",ImGuiFileDialog::Instance()->GetCurrentPath()); return ImGuiFileDialog::Instance()->GetCurrentPath(); } }