diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4dce0467..293c4cd0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -18,17 +18,16 @@ 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 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: ${{ matrix.config.name }} runs-on: ${{ matrix.config.os }} - defaults: - run: - shell: ${{ matrix.config.shell }} steps: - name: Checkout @@ -36,53 +35,123 @@ jobs: with: submodules: recursive + - name: Set Windows arch identifiers + id: windows-identify + if: ${{ matrix.config.compiler == 'msvc' || matrix.config.compiler == 'mingw' }} + run: | + vswhere_target="${{ matrix.config.arch }}" + msvc_target="${{ matrix.config.arch }}" + mingw_target="${{ matrix.config.arch }}" + + 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: 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: 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: ${{ runner.os == 'Windows' && matrix.config.compiler == '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: ${{ 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 - - - name: Install Dependencies [macOS] - if: ${{ runner.os == 'macOS' }} + if: ${{ matrix.config.compiler == 'mingw' }} run: | - export HOMEBREW_NO_INSTALL_CLEANUP=1 - brew update - brew install \ - pkg-config \ - sdl2 \ - libsndfile \ - zlib \ - jack + sudo apt update + sudo apt install \ + mingw-w64 \ + mingw-w64-tools - name: Install Dependencies [Ubuntu] - if: ${{ runner.os == 'Linux' }} + 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 + 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 (System Libraries) + if: ${{ runner.os == 'Linux' && matrix.config.compiler != 'mingw' }} 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 - # We don't want all the MSVC warnings to cause errors yet - export USE_WAE=OFF + if [ '${{ matrix.config.compiler }}' == 'msvc' ]; then + CMAKE_EXTRA_ARGS+=('-DCMAKE_GENERATOR_PLATFORM=${{ steps.windows-identify.outputs.msvc-target }}') + 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=OFF' + '-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 @@ -93,16 +162,122 @@ jobs: -DWARNINGS_ARE_ERRORS=${USE_WAE} \ "${CMAKE_EXTRA_ARGS[@]}" - - name: Build + - name: Build (System Libraries) + if: ${{ runner.os == 'Linux' && matrix.config.compiler != 'mingw' }} run: | - export VERBOSE=1 cmake \ --build ${PWD}/build \ --config ${{ env.BUILD_TYPE }} \ - --parallel 2 + --parallel ${{ steps.build-cores.outputs.amount }} - - name: Install + - name: Install (System Libraries) + if: ${{ runner.os == 'Linux' && matrix.config.compiler != 'mingw' }} run: | cmake \ --install ${PWD}/build \ --config ${{ env.BUILD_TYPE }} + + - name: Cleanup (System Libraries) + if: ${{ runner.os == 'Linux' && matrix.config.compiler != 'mingw' }} + run: | + rm -rf build/ target/ + + - name: Configure + run: | + 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 }}') + + # 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 + 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 + 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: | + cmake \ + --build ${PWD}/build \ + --config ${{ env.BUILD_TYPE }} \ + --parallel ${{ steps.build-cores.outputs.amount }} + + - name: Package [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' ] && [ '${{ env.BUILD_TYPE }}' == 'Release' ]; then + # 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 }} + pushd ${{ steps.package-identify.outputs.filename }} + + cp -v ../LICENSE LICENSE.txt + cp -v ../README.md README.txt + cp -vr ../{papers,demos} ../${binPath}/furnace.exe ./ + + popd + + - name: Package [macOS] + if: ${{ runner.os == 'macOS' }} + run: | + pushd build + cpack + mv Furnace-*-Darwin.dmg ../${{ steps.package-identify.outputs.filename }} + popd + + - name: Package [Ubuntu] + if: ${{ runner.os == 'Linux' && matrix.config.compiler != 'mingw' }} + run: | + 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 + 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-identify.outputs.filename }} + popd + + - name: Upload artifact + uses: actions/upload-artifact@v3 + with: + name: ${{ steps.package-identify.outputs.id }} + path: ${{ steps.package-identify.outputs.filename }} diff --git a/CMakeLists.txt b/CMakeLists.txt index c5fc06e7..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}) @@ -167,11 +167,20 @@ 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) + # 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() @@ -385,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 @@ -452,9 +462,13 @@ 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) + 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() diff --git a/demos/silverlining.fur b/demos/silverlining.fur index 06567d73..9ad4a881 100644 Binary files a/demos/silverlining.fur and b/demos/silverlining.fur differ diff --git a/extern/pfd-fixed/portable-file-dialogs.h b/extern/pfd-fixed/portable-file-dialogs.h index 41e588ac..fc6df0a1 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 @@ -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) -> 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; 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 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..9cf7b643 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, 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. # 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/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/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) 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/dispatch.h b/src/engine/dispatch.h index b4394f60..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, @@ -319,6 +320,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..4f4ecf39 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); @@ -140,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; } @@ -304,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 c26058e6..14577b40 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" @@ -196,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; } @@ -210,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); @@ -219,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; } } @@ -232,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; @@ -242,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: { @@ -265,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; } } @@ -314,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: { @@ -341,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; @@ -408,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; } } @@ -482,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); } @@ -507,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); } @@ -536,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]; @@ -570,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); } @@ -767,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; @@ -825,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() took %dµs",std::chrono::duration_cast(timeEnd-timeStart).count()); } /* @@ -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; } @@ -1281,7 +1294,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) { @@ -1333,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; } @@ -1373,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); @@ -1401,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; i=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,oldPat->data,256*32*sizeof(short)); - logD("found at %d\n",j); + logD("found at %d",j); didNotFind=false; break; } @@ -1715,7 +1728,7 @@ void DivEngine::moveOrderDown() { void DivEngine::exchangeIns(int one, int two) { for (int i=0; idata[k][2]==one) { @@ -1940,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 { @@ -2058,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="."; \ } \ } @@ -2068,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="."; \ } \ } \ @@ -2101,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; @@ -2116,7 +2129,7 @@ bool DivEngine::initAudioBackend() { output=new TAAudio; break; default: - logE("invalid audio engine!\n"); + logE("invalid audio engine!"); return false; } @@ -2134,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; @@ -2145,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!"); } } } @@ -2161,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!"); } } } @@ -2175,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(); } } @@ -2209,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; @@ -2228,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; } @@ -2277,7 +2290,7 @@ bool DivEngine::init() { return false; } else { if (!output->setRun(true)) { - logE("error while activating!\n"); + logE("error while activating!"); return false; } } @@ -2287,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/engine.h b/src/engine/engine.h index 677cdeaa..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 "dev79" -#define DIV_ENGINE_VERSION 79 +#define DIV_VERSION "dev81" +#define DIV_ENGINE_VERSION 81 // for imports #define DIV_VERSION_MOD 0xff01 @@ -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 { @@ -151,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); @@ -169,7 +172,8 @@ struct DivDispatchContainer { prevSample{0,0}, bbIn{NULL,NULL}, bbOut{NULL,NULL}, - lowQuality(false) {} + lowQuality(false), + dcOffCompensation(false) {} }; class DivEngine { @@ -295,6 +299,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); @@ -769,6 +774,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/fileOps.cpp b/src/engine/fileOps.cpp index 7988992b..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; i0x1a) { - 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 +110,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 +168,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(); @@ -172,7 +176,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { ds.timeBase=reader.readC(); ds.speed1=reader.readC(); - if (ds.version>0x03) { + if (ds.version>0x05) { ds.speed2=reader.readC(); ds.pal=reader.readC(); ds.hz=(ds.pal)?60:50; @@ -186,7 +190,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 +203,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 +262,14 @@ 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); + 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; 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; @@ -272,26 +278,31 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { ds.pat[i].getPattern(j,true)->name=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; } - logI("reading instruments (%d)...\n",ds.insLen); + 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\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; @@ -307,12 +318,9 @@ 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; } if (ds.system[0]==DIV_SYSTEM_PCE) { ins->type=DIV_INS_PCE; - ins->std.volMacroHeight=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; @@ -322,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?\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; } - ins->fm.ams=reader.readC(); for (int j=0; jfm.ops; j++) { ins->fm.op[j].am=reader.readC(); @@ -388,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(); @@ -402,7 +422,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, @@ -425,76 +445,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 +553,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); + 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.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!"); @@ -556,7 +576,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(); @@ -567,12 +587,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(); @@ -591,97 +611,129 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { } } - logI("reading patterns (%d channels, %d orders)...\n",getChannelCount(ds.system[0]),ds.ordersLen); + 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) { - 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; } 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\n",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)...\n",ds.sampleLen); - if (ds.version<0x0b && ds.sampleLen>0) { // TODO what is this for? - reader.readC(); + logI("reading samples (%d)...",ds.sampleLen); + if (ds.version<0x0b && ds.sampleLen>0) { + // it appears this byte stored the YMU759 sample rate + ymuSampleRate=reader.readC(); } for (int i=0; iname=""; } - 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()); pitch=reader.readC(); vol=reader.readC(); } + if (ds.version<=0x05) { + sample->rate=ymuSampleRate*400; + } 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 { - 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...\n",i,pitch); - } - - // render data - if (!sample->init((double)length/samplePitches[pitch])) { - logE("%d: error while initializing sample!\n",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); } 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!"); } @@ -906,7 +984,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; @@ -915,7 +993,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; @@ -942,49 +1020,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>127) { - logE("song is too long!\n"); + if (ds.ordersLen>256) { + 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; @@ -994,7 +1072,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; @@ -1007,7 +1085,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 @@ -1064,7 +1142,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(); @@ -1170,7 +1248,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; @@ -1245,9 +1323,9 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { // read instruments for (int i=0; iname=reader.readString(); sample->samples=reader.readI(); @@ -1351,12 +1429,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]; @@ -1386,16 +1464,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; @@ -1407,23 +1485,23 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { int index=reader.readS(); reader.readI(); + 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>127) { - logE("pattern index out of range!\n",i); + if (index<0 || index>255) { + logE("pattern index out of range!",i); lastError="pattern index out of range!"; ds.unload(); delete[] file; 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(); @@ -1443,7 +1521,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? @@ -1835,10 +1913,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; @@ -1856,14 +1934,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)); @@ -1878,9 +1956,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; @@ -1897,10 +1975,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; @@ -1919,10 +1997,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; @@ -1937,7 +2015,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(); @@ -1954,7 +2032,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; } @@ -1963,7 +2041,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; @@ -2230,7 +2308,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; } @@ -2258,40 +2336,65 @@ 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!"); + lastError="maximum .dmf song length is 127"; + return NULL; + } + if (song.ins.size()>128) { + 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!"); + 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)!",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; @@ -2421,36 +2524,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) { @@ -2464,7 +2567,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 6689c554..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,81 +179,81 @@ 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.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) { @@ -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 729c8caa..8b0e5a2e 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" @@ -31,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++) { @@ -47,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; @@ -67,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; @@ -85,4 +84,4 @@ float* DivFilterTables::getSincIntegralTable() { } } return sincIntegralTable; -} \ No newline at end of file +} diff --git a/src/engine/instrument.cpp b/src/engine/instrument.cpp index 60ce6810..68896a45 100644 --- a/src/engine/instrument.cpp +++ b/src/engine/instrument.cpp @@ -111,264 +111,264 @@ 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); + 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]); } } @@ -394,65 +394,65 @@ 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.ex7Macro.val[j]); } - for (int j=0; jwriteI(std.ex8Macro[j]); + for (int j=0; jwriteI(std.ex8Macro.val[j]); } // FDS @@ -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(); @@ -575,53 +575,51 @@ DivDataErrors DivInstrument::readInsData(SafeReader& reader, short version) { for (int k=0; k<14; k++) reader.readC(); // standard - std.volMacroLen=reader.readI(); - std.arpMacroLen=reader.readI(); - std.dutyMacroLen=reader.readI(); - std.waveMacroLen=reader.readI(); + std.volMacro.len=reader.readI(); + std.arpMacro.len=reader.readI(); + std.dutyMacro.len=reader.readI(); + std.waveMacro.len=reader.readI(); if (version>=17) { - std.pitchMacroLen=reader.readI(); - std.ex1MacroLen=reader.readI(); - std.ex2MacroLen=reader.readI(); - std.ex3MacroLen=reader.readI(); + std.pitchMacro.len=reader.readI(); + std.ex1Macro.len=reader.readI(); + std.ex2Macro.len=reader.readI(); + std.ex3Macro.len=reader.readI(); } - std.volMacroLoop=reader.readI(); - std.arpMacroLoop=reader.readI(); - std.dutyMacroLoop=reader.readI(); - std.waveMacroLoop=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.pitchMacroLoop=reader.readI(); - std.ex1MacroLoop=reader.readI(); - std.ex2MacroLoop=reader.readI(); - std.ex3MacroLoop=reader.readI(); + std.pitchMacro.loop=reader.readI(); + std.ex1Macro.loop=reader.readI(); + std.ex2Macro.loop=reader.readI(); + std.ex3Macro.loop=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); + 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.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); + 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.volMacroHeight==31) { + if (oldVolHeight==31) { type=DIV_INS_PCE; } - if (std.dutyMacroHeight==31) { + if (oldDutyHeight==31) { type=DIV_INS_AY; } } @@ -629,122 +627,122 @@ DivDataErrors DivInstrument::readInsData(SafeReader& reader, short version) { // FM macros if (version>=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(); + 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,4*std.algMacroLen); - reader.read(std.fbMacro,4*std.fbMacroLen); - reader.read(std.fmsMacro,4*std.fmsMacroLen); - reader.read(std.amsMacro,4*std.amsMacroLen); + 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.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.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.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.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.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(); + 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(); } 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); + 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); } } // 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(); + 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.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.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(); } } @@ -753,53 +751,53 @@ DivDataErrors DivInstrument::readInsData(SafeReader& reader, short version) { for (int i=0; i<4; i++) { DivInstrumentSTD::OpMacro& op=std.opMacros[i]; - 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.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.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.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.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.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.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(); + 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.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); + reader.read(op.damMacro.val,op.damMacro.len); + reader.read(op.dvbMacro.val,op.dvbMacro.len); + reader.read(op.egtMacro.val,op.egtMacro.len); + reader.read(op.kslMacro.val,op.kslMacro.len); + reader.read(op.susMacro.val,op.susMacro.len); + reader.read(op.vibMacro.val,op.vibMacro.len); + reader.read(op.wsMacro.val,op.wsMacro.len); + reader.read(op.ksrMacro.val,op.ksrMacro.len); } } @@ -814,16 +812,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 @@ -846,50 +844,50 @@ 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(); + 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 @@ -951,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/instrument.h b/src/engine/instrument.h index 8109030e..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 { +enum DivInstrumentType: unsigned short { DIV_INS_STD=0, DIV_INS_FM=1, DIV_INS_GB=2, @@ -77,9 +77,11 @@ 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(): + enable(true), am(0), ar(0), dr(0), @@ -151,248 +153,97 @@ struct DivInstrumentFM { }; // this is getting out of hand +struct DivInstrumentMacro { + String name; + int val[256]; + unsigned int mode; + bool open; + unsigned char len; + signed char loop; + signed char rel; + DivInstrumentMacro(String n, bool initOpen=false): + name(n), + mode(0), + open(initOpen), + len(0), + loop(-1), + rel(-1) { + memset(val,0,256*sizeof(int)); + } +}; + 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 amsMacro; + 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",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]; 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",true), + arpMacro("arp"), + dutyMacro("duty"), + waveMacro("wave"), + pitchMacro("pitch"), + ex1Macro("ex1"), + ex2Macro("ex2"), + ex3Macro("ex3"), + algMacro("alg"), + fbMacro("fb"), + fmsMacro("fms"), + amsMacro("ams"), + panLMacro("panL"), + panRMacro("panR"), + phaseResetMacro("phaseReset"), + ex4Macro("ex4"), + ex5Macro("ex5"), + ex6Macro("ex6"), + ex7Macro("ex7"), + ex8Macro("ex8") {} }; struct DivInstrumentGB { diff --git a/src/engine/macroInt.cpp b/src/engine/macroInt.cpp index d74b59a6..21ca93a1 100644 --- a/src/engine/macroInt.cpp +++ b/src/engine/macroInt.cpp @@ -20,85 +20,41 @@ #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 + // TODO: potentially get rid of list to avoid allocations + for (size_t i=0; idoMacro(*macroSource[i],released); + } } } @@ -106,316 +62,155 @@ void DivMacroInt::release() { released=true; } +#define ADD_MACRO(m,s) \ + macroList[macroListLen]=&m; \ + macroSource[macroListLen++]=&s; + 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; + // initialize + for (size_t i=0; iinit(); + } + macroListLen=0; 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; - - op[0]=IntOp(); - op[1]=IntOp(); - op[2]=IntOp(); - op[3]=IntOp(); - - arpMode=false; - if (ins==NULL) return; - if (ins->std.volMacroLen>0) { - hadVol=true; - hasVol=true; - willVol=true; + // prepare common macro + if (ins->std.volMacro.len>0) { + ADD_MACRO(vol,ins->std.volMacro); } - if (ins->std.arpMacroLen>0) { - hadArp=true; - hasArp=true; - willArp=true; + if (ins->std.arpMacro.len>0) { + ADD_MACRO(arp,ins->std.arpMacro); } - if (ins->std.dutyMacroLen>0) { - hadDuty=true; - hasDuty=true; - willDuty=true; + if (ins->std.dutyMacro.len>0) { + ADD_MACRO(duty,ins->std.dutyMacro); } - if (ins->std.waveMacroLen>0) { - hadWave=true; - hasWave=true; - willWave=true; + if (ins->std.waveMacro.len>0) { + ADD_MACRO(wave,ins->std.waveMacro); } - if (ins->std.pitchMacroLen>0) { - hadPitch=true; - hasPitch=true; - willPitch=true; + if (ins->std.pitchMacro.len>0) { + ADD_MACRO(pitch,ins->std.pitchMacro); } - if (ins->std.ex1MacroLen>0) { - hadEx1=true; - hasEx1=true; - willEx1=true; + if (ins->std.ex1Macro.len>0) { + ADD_MACRO(ex1,ins->std.ex1Macro); } - if (ins->std.ex2MacroLen>0) { - hadEx2=true; - hasEx2=true; - willEx2=true; + if (ins->std.ex2Macro.len>0) { + ADD_MACRO(ex2,ins->std.ex2Macro); } - if (ins->std.ex3MacroLen>0) { - hadEx3=true; - hasEx3=true; - willEx3=true; + if (ins->std.ex3Macro.len>0) { + ADD_MACRO(ex3,ins->std.ex3Macro); } - if (ins->std.algMacroLen>0) { - hadAlg=true; - hasAlg=true; - willAlg=true; + if (ins->std.algMacro.len>0) { + ADD_MACRO(alg,ins->std.algMacro); } - if (ins->std.fbMacroLen>0) { - hadFb=true; - hasFb=true; - willFb=true; + if (ins->std.fbMacro.len>0) { + ADD_MACRO(fb,ins->std.fbMacro); } - if (ins->std.fmsMacroLen>0) { - hadFms=true; - hasFms=true; - willFms=true; + if (ins->std.fmsMacro.len>0) { + ADD_MACRO(fms,ins->std.fmsMacro); } - if (ins->std.amsMacroLen>0) { - hadAms=true; - hasAms=true; - willAms=true; + if (ins->std.amsMacro.len>0) { + ADD_MACRO(ams,ins->std.amsMacro); } - // TODO: other macros - if (ins->std.panLMacroLen>0) { - hadPanL=true; - hasPanL=true; - willPanL=true; + if (ins->std.panLMacro.len>0) { + ADD_MACRO(panL,ins->std.panLMacro); } - if (ins->std.panRMacroLen>0) { - hadPanR=true; - hasPanR=true; - willPanR=true; + if (ins->std.panRMacro.len>0) { + ADD_MACRO(panR,ins->std.panRMacro); } - if (ins->std.phaseResetMacroLen>0) { - hadPhaseReset=true; - hasPhaseReset=true; - willPhaseReset=true; + if (ins->std.phaseResetMacro.len>0) { + ADD_MACRO(phaseReset,ins->std.phaseResetMacro); } - if (ins->std.ex4MacroLen>0) { - hadEx4=true; - hasEx4=true; - willEx4=true; + if (ins->std.ex4Macro.len>0) { + ADD_MACRO(ex4,ins->std.ex4Macro); } - if (ins->std.ex5MacroLen>0) { - hadEx5=true; - hasEx5=true; - willEx5=true; + if (ins->std.ex5Macro.len>0) { + ADD_MACRO(ex5,ins->std.ex5Macro); } - if (ins->std.ex6MacroLen>0) { - hadEx6=true; - hasEx6=true; - willEx6=true; + if (ins->std.ex6Macro.len>0) { + ADD_MACRO(ex6,ins->std.ex6Macro); } - if (ins->std.ex7MacroLen>0) { - hadEx7=true; - hasEx7=true; - willEx7=true; + if (ins->std.ex7Macro.len>0) { + ADD_MACRO(ex7,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) { + ADD_MACRO(ex8,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) { + ADD_MACRO(o.am,m.amMacro); } - if (m.arMacroLen>0) { - o.hadAr=true; - o.hasAr=true; - o.willAr=true; + if (m.arMacro.len>0) { + ADD_MACRO(o.ar,m.arMacro); } - if (m.drMacroLen>0) { - o.hadDr=true; - o.hasDr=true; - o.willDr=true; + if (m.drMacro.len>0) { + ADD_MACRO(o.dr,m.drMacro); } - if (m.multMacroLen>0) { - o.hadMult=true; - o.hasMult=true; - o.willMult=true; + if (m.multMacro.len>0) { + ADD_MACRO(o.mult,m.multMacro); } - if (m.rrMacroLen>0) { - o.hadRr=true; - o.hasRr=true; - o.willRr=true; + if (m.rrMacro.len>0) { + ADD_MACRO(o.rr,m.rrMacro); } - if (m.slMacroLen>0) { - o.hadSl=true; - o.hasSl=true; - o.willSl=true; + if (m.slMacro.len>0) { + ADD_MACRO(o.sl,m.slMacro); } - if (m.tlMacroLen>0) { - o.hadTl=true; - o.hasTl=true; - o.willTl=true; + if (m.tlMacro.len>0) { + ADD_MACRO(o.tl,m.tlMacro); } - if (m.dt2MacroLen>0) { - o.hadDt2=true; - o.hasDt2=true; - o.willDt2=true; + if (m.dt2Macro.len>0) { + ADD_MACRO(o.dt2,m.dt2Macro); } - if (m.rsMacroLen>0) { - o.hadRs=true; - o.hasRs=true; - o.willRs=true; + if (m.rsMacro.len>0) { + ADD_MACRO(o.rs,m.rsMacro); } - if (m.dtMacroLen>0) { - o.hadDt=true; - o.hasDt=true; - o.willDt=true; + if (m.dtMacro.len>0) { + ADD_MACRO(o.dt,m.dtMacro); } - if (m.d2rMacroLen>0) { - o.hadD2r=true; - o.hasD2r=true; - o.willD2r=true; + if (m.d2rMacro.len>0) { + ADD_MACRO(o.d2r,m.d2rMacro); } - if (m.ssgMacroLen>0) { - o.hadSsg=true; - o.hasSsg=true; - o.willSsg=true; + if (m.ssgMacro.len>0) { + ADD_MACRO(o.ssg,m.ssgMacro); } - if (m.damMacroLen>0) { - o.hadDam=true; - o.hasDam=true; - o.willDam=true; + if (m.damMacro.len>0) { + ADD_MACRO(o.dam,m.damMacro); } - if (m.dvbMacroLen>0) { - o.hadDvb=true; - o.hasDvb=true; - o.willDvb=true; + if (m.dvbMacro.len>0) { + ADD_MACRO(o.dvb,m.dvbMacro); } - if (m.egtMacroLen>0) { - o.hadEgt=true; - o.hasEgt=true; - o.willEgt=true; + if (m.egtMacro.len>0) { + ADD_MACRO(o.egt,m.egtMacro); } - if (m.kslMacroLen>0) { - o.hadKsl=true; - o.hasKsl=true; - o.willKsl=true; + if (m.kslMacro.len>0) { + ADD_MACRO(o.ksl,m.kslMacro); } - if (m.susMacroLen>0) { - o.hadSus=true; - o.hasSus=true; - o.willSus=true; + if (m.susMacro.len>0) { + ADD_MACRO(o.sus,m.susMacro); } - if (m.vibMacroLen>0) { - o.hadVib=true; - o.hasVib=true; - o.willVib=true; + if (m.vibMacro.len>0) { + ADD_MACRO(o.vib,m.vibMacro); } - if (m.wsMacroLen>0) { - o.hadWs=true; - o.hasWs=true; - o.willWs=true; + if (m.wsMacro.len>0) { + ADD_MACRO(o.ws,m.wsMacro); } - if (m.ksrMacroLen>0) { - o.hadKsr=true; - o.hasKsr=true; - o.willKsr=true; + if (m.ksrMacro.len>0) { + ADD_MACRO(o.ksr,m.ksrMacro); } } + + for (size_t i=0; iprepare(*macroSource[i]); + } } void DivMacroInt::notifyInsDeletion(DivInstrument* which) { diff --git a/src/engine/macroInt.h b/src/engine/macroInt.h index d5e6fd14..3c26eb65 100644 --- a/src/engine/macroInt.h +++ b/src/engine/macroInt.h @@ -22,125 +22,72 @@ #include "instrument.h" +struct DivMacroStruct { + int pos; + int val; + bool has, had, finished, will; + unsigned int mode; + void doMacro(DivInstrumentMacro& source, bool released); + void init() { + pos=mode=0; + has=had=will=false; + } + void prepare(DivInstrumentMacro& source) { + has=had=will=true; + mode=source.mode; + } + DivMacroStruct(): + pos(0), + val(0), + has(false), + had(false), + finished(false), + will(false), + mode(0) {} +}; + 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; + DivMacroStruct* macroList[128]; + DivInstrumentMacro* macroSource[128]; + size_t macroListLen; 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, ams; + 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]; /** @@ -167,128 +114,31 @@ 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), + macroListLen(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(), + ams(), + panL(), + panR(), + phaseReset(), + ex4(), + ex5(), + ex6(), + ex7(), + ex8() { + memset(macroList,0,128*sizeof(void*)); + memset(macroSource,0,128*sizeof(void*)); + } }; #endif 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/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/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..55172394 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; } @@ -220,8 +223,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 +236,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,77 +299,94 @@ 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)); } } 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; } } @@ -413,7 +433,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 +492,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++) { @@ -602,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/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/ay.cpp b/src/engine/platform/ay.cpp index b798cba4..727a1440 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]) { @@ -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)); @@ -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/ay8930.cpp b/src/engine/platform/ay8930.cpp index 1849d0cd..e9af64fc 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]); @@ -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]) { @@ -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/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..b7521f03 100644 --- a/src/engine/platform/c64.cpp +++ b/src/engine/platform/c64.cpp @@ -118,50 +118,50 @@ 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); } 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; + 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; - 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.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)|(int)(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,13 +226,13 @@ 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); } 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(); } @@ -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 { @@ -330,10 +330,10 @@ 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))); + 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; @@ -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/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..e85bc768 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; } @@ -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,26 +327,44 @@ 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); } } 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; } } @@ -505,7 +523,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 +596,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++) { @@ -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/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..79d9fc61 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; @@ -99,29 +98,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 +242,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 +290,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; @@ -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/n163.cpp b/src/engine/platform/n163.cpp index 2800fad1..7c9188d4 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; @@ -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/nes.cpp b/src/engine/platform/nes.cpp index f61ed4fb..9f56e4e5 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; @@ -136,9 +143,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 +154,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 +344,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 +413,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; @@ -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/opl.cpp b/src/engine/platform/opl.cpp index fcba9f80..3e222eec 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 { @@ -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); } @@ -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; @@ -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) { diff --git a/src/engine/platform/opll.cpp b/src/engine/platform/opll.cpp index 55a1fa80..ee07463c 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) { @@ -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/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..0fd25ec7 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; } @@ -336,9 +336,9 @@ 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.hadVol) { + 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; @@ -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..708fbc7a 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]) { @@ -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/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/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/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/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/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 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..7ea634b2 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; } @@ -184,8 +187,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 +200,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,82 +263,99 @@ 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)); } } 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; } } @@ -401,7 +421,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; } @@ -435,6 +455,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; @@ -463,7 +484,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++) { @@ -596,6 +617,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) { @@ -652,6 +676,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/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/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..dd7220fa 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; } @@ -376,8 +379,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 +392,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,74 +425,92 @@ 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); } } 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; } } @@ -498,22 +519,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 +629,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 +706,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 +785,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 @@ -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/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.cpp b/src/engine/platform/ym2610b.cpp index dfd84723..c51f4119 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; } @@ -440,8 +443,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 +456,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,74 +489,92 @@ 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); } } 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; } } @@ -561,22 +582,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 +692,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 +769,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 +848,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 @@ -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; 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 8e1f1d66..97047b64 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" @@ -64,6 +61,7 @@ const char* cmdName[DIV_CMD_MAX]={ "SAMPLE_BANK", "SAMPLE_POS", + "FM_HARD_RESET", "FM_LFO", "FM_LFO_WAVE", "FM_TL", @@ -201,16 +199,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: @@ -235,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; } @@ -335,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; } @@ -963,6 +1002,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 +1478,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) { @@ -1613,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 { @@ -1665,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(); } @@ -1732,8 +1779,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(); @@ -1795,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; @@ -1831,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; @@ -1847,6 +1897,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; j=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/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 (curPos #include "../ta-utils.h" +enum Endianness { + LittleEndian=0, + BigEndian +}; + class SafeReader; struct EndOfFileException { diff --git a/src/engine/sample.cpp b/src/engine/sample.cpp index 5fab8b2b..93e3ece6 100644 --- a/src/engine/sample.cpp +++ b/src/engine/sample.cpp @@ -50,7 +50,7 @@ bool DivSample::save(const char* path) { f=sf_open(path,SFM_WRITE,&si); if (f==NULL) { - logE("could not open wave file for saving! %s\n",sf_error_number(sf_error(f))); + logE("could not open wave file for saving! %s",sf_error_number(sf_error(f))); return false; } @@ -822,7 +822,7 @@ DivSampleHistory* DivSample::prepareUndo(bool data, bool doNotPush) { initInternal(h->depth,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/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; 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/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 +} 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); } }; 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 9efd436f..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++; @@ -562,6 +562,7 @@ void FurnaceGUI::doPaste(PasteMode mode) { } if (settings.cursorPastePos) { cursor.y=j; + updateScroll(cursor.y); } makeUndo(GUI_UNDO_PATTERN_PASTE); diff --git a/src/gui/fileDialog.cpp b/src/gui/fileDialog.cpp index 95a6ac7b..7bfafb4a 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.c_str()); 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.c_str()); if (sysDialog) { dialogS=new pfd::save_file(header,path,filter); } else { @@ -65,7 +67,9 @@ 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()); + size_t dsPos=fileName.rfind(DIR_SEPARATOR); + if (dsPos!=String::npos) curPath=fileName.substr(0,dsPos); + logD("returning %s",fileName.c_str()); return true; } } @@ -74,10 +78,12 @@ 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()); + 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,6 +97,12 @@ bool FurnaceGUIFileDialog::render(const ImVec2& min, const ImVec2& max) { String FurnaceGUIFileDialog::getPath() { if (sysDialog) { + if (curPath.size()>1) { + if (curPath[curPath.size()-1]==DIR_SEPARATOR) { + curPath=curPath.substr(0,curPath.size()-1); + } + } + logD("curPath: %s",curPath.c_str()); return curPath; } else { return ImGuiFileDialog::Instance()->GetCurrentPath(); diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index bae782ff..94848977 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; } @@ -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; @@ -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(); @@ -2600,6 +2601,9 @@ bool FurnaceGUI::loop() { drawInsList(); drawInsEdit(); drawMixer(); + + readOsc(); + drawOsc(); drawVolMeter(); drawSettings(); @@ -2610,6 +2614,7 @@ bool FurnaceGUI::loop() { drawNotes(); drawChannels(); drawRegView(); + drawLog(); if (inspectorOpen) ImGui::ShowMetricsWindow(&inspectorOpen); @@ -2710,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'; @@ -2727,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)); } @@ -2862,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(); @@ -2923,6 +2928,7 @@ bool FurnaceGUI::loop() { break; case GUI_WARN_RESET_COLORS: resetColors(); + applyUISettings(false); break; case GUI_WARN_GENERIC: break; @@ -2944,22 +2950,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(); } } @@ -3034,6 +3040,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); @@ -3063,7 +3070,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; } @@ -3088,14 +3095,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; } @@ -3112,14 +3119,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!"); } } @@ -3196,6 +3203,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); @@ -3295,6 +3303,7 @@ FurnaceGUI::FurnaceGUI(): notesOpen(false), channelsOpen(false), regViewOpen(false), + logOpen(false), /* editControlsDocked(false), ordersDocked(false), @@ -3428,7 +3437,11 @@ FurnaceGUI::FurnaceGUI(): openSampleResampleOpt(false), openSampleAmplifyOpt(false), openSampleSilenceOpt(false), - openSampleFilterOpt(false) { + openSampleFilterOpt(false), + oscTotal(0), + oscZoom(0.5f), + oscZoomSlider(false), + followLog(true) { // value keys valueKeys[SDLK_0]=0; valueKeys[SDLK_1]=1; @@ -3469,4 +3482,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 445369f0..7cc66c84 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, @@ -157,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 @@ -185,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 { @@ -280,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, @@ -761,6 +779,9 @@ class FurnaceGUI { int titleBarSys; int frameBorders; int effectDeletionAltersValue; + int oscRoundedCorners; + int oscTakesEntireWindow; + int oscBorder; unsigned int maxUndoSteps; String mainFontPath; String patFontPath; @@ -821,6 +842,9 @@ class FurnaceGUI { titleBarSys(1), frameBorders(0), effectDeletionAltersValue(1), + oscRoundedCorners(1), + oscTakesEntireWindow(0), + oscBorder(1), maxUndoSteps(100), mainFontPath(""), patFontPath(""), @@ -838,7 +862,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; @@ -952,7 +976,7 @@ class FurnaceGUI { int oldOrdersLen; DivOrders oldOrders; - DivPattern* oldPat[128]; + DivPattern* oldPat[DIV_MAX_CHANS]; std::deque undoHist; std::deque redoHist; @@ -976,9 +1000,18 @@ class FurnaceGUI { size_t sampleClipboardLen; bool openSampleResizeOpt, openSampleResampleOpt, openSampleAmplifyOpt, openSampleSilenceOpt, openSampleFilterOpt; + // oscilloscope + int oscTotal; + float oscValues[512]; + float oscZoom; + bool oscZoomSlider; + // 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); @@ -996,6 +1029,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); @@ -1026,6 +1061,7 @@ class FurnaceGUI { void drawSettings(); void drawDebug(); void drawNewSong(); + void drawLog(); void parseKeybinds(); void promptKey(int which); @@ -1096,7 +1132,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/guiConst.cpp b/src/gui/guiConst.cpp index 08582933..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), @@ -377,6 +378,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)), @@ -463,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/insEdit.cpp b/src/gui/insEdit.cpp index 14ca65b4..3e141612 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"} }; @@ -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", "op2", "op3", "op4", NULL +}; + const char* c64ShapeBits[5]={ "triangle", "saw", "pulse", "noise", NULL }; @@ -176,6 +180,16 @@ const char* dualWSEffects[7]={ "Phase (dual)", }; +const char* macroAbsoluteMode[2]={ + "Relative", + "Absolute" +}; + +const char* macroDummyMode[2]={ + "Bug", + "Bug" +}; + String macroHoverNote(int id, float val) { if (val<-60 || val>=120) return "???"; return fmt::sprintf("%d: %s",id,noteNames[(int)val+60]); @@ -924,8 +938,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 +977,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 +987,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("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]); \ + 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 +1029,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 +1042,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,37 +1051,37 @@ 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("##IOPMacroLen_" #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("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]); \ + 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 +1133,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 +1146,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("##IOPMacroLoop_" #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<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)) { @@ -1804,8 +1851,6 @@ void FurnaceGUI::drawInsEdit() { op.am=amOn; } - ImGui::SameLine(); - int maxTl=127; if (ins->type==DIV_INS_OPLL) { if (i==1) { @@ -1825,6 +1870,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); } @@ -1836,6 +1882,7 @@ void FurnaceGUI::drawInsEdit() { } if (ins->type==DIV_INS_OPL) { + ImGui::SameLine(); if (ImGui::Checkbox(FM_NAME(FM_SUS),&susOn)) { PARAMETER op.sus=susOn; } @@ -1953,14 +2000,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) { @@ -1999,24 +2048,31 @@ void FurnaceGUI::drawInsEdit() { if (ImGui::BeginTabItem("FM Macros")) { MACRO_BEGIN(0); if (ins->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) { + // 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.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); + } 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); + 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(); @@ -2041,45 +2097,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(); @@ -2464,7 +2520,7 @@ void FurnaceGUI::drawInsEdit() { volMax=32; } - bool arpMode=ins->std.arpMacroMode; + bool arpMode=ins->std.arpMacro.mode; const char* dutyLabel="Duty/Noise"; int dutyMax=3; @@ -2571,66 +2627,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 +2703,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; } @@ -2748,39 +2805,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 +2845,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 +2873,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 +2905,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; } } } diff --git a/src/gui/log.cpp b/src/gui/log.cpp new file mode 100644 index 00000000..c6c4e2a8 --- /dev/null +++ b/src/gui/log.cpp @@ -0,0 +1,77 @@ +#include "gui.h" +#include "../ta-log.h" +#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::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); + + 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::TableSetupScrollFreeze(0,1); + + 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=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/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/osc.cpp b/src/gui/osc.cpp index 0bdcdf8a..c0ce978c 100644 --- a/src/gui/osc.cpp +++ b/src/gui/osc.cpp @@ -18,6 +18,52 @@ */ #include "gui.h" +#include "imgui_internal.h" +#include +#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) { @@ -27,21 +73,112 @@ 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 (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::EndDisabled(); + 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)) { + 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); + ImRect inRect=rect; + inRect.Min.x+=dpiScale; + inRect.Min.y+=dpiScale; + inRect.Max.x-=dpiScale; + inRect.Max.y-=dpiScale; + 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]); + ImU32 refColor=ImGui::GetColorU32(uiColors[GUI_COLOR_OSC_REF]); + ImGui::ItemSize(size,style.FramePadding.y); + 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,settings.oscRoundedCorners?(8.0f*dpiScale):0.0f); + 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; + + ImVec4 conv=ImGui::ColorConvertU32ToFloat4(v->col); + 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; + 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); + 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; + } + } + if (settings.oscTakesEntireWindow) { + 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/pattern.cpp b/src/gui/pattern.cpp index d4bf904b..0decef97 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" @@ -284,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); @@ -870,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 d83505df..a70f70fc 100644 --- a/src/gui/sampleEdit.cpp +++ b/src/gui/sampleEdit.cpp @@ -589,12 +589,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; } @@ -605,9 +605,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)); @@ -615,7 +615,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; @@ -880,4 +880,4 @@ void FurnaceGUI::doRedoSample() { updateSampleTex=true; } }); -} \ No newline at end of file +} diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index 1cbd6a06..87b79857 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)) { @@ -384,8 +386,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(); @@ -894,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); @@ -942,6 +963,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"); @@ -1041,6 +1074,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(); } @@ -1114,6 +1155,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); @@ -1463,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); @@ -1590,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; iBuild()) { - 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!"); } } } @@ -1636,7 +1684,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(); @@ -1677,22 +1725,23 @@ bool FurnaceGUI::importColors(String path) { break; } } - if (!found) logW("line invalid: %s\n",line); + if (!found) logW("line invalid: %s",line); } } fclose(f); + applyUISettings(false); return true; } 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; i=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++) { @@ -2064,120 +2115,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\n"); - settings.mainFont=0; - } - if (settings.patFont==6 && settings.patFontPath.empty()) { - logW("pattern font path is empty! reverting to default font\n"); - 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\n"); + 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.\n"); - 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\n"); - 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"); - 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.\n"); - 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!\n"); - } - if (settings.mainFontSize==settings.patFontSize && settings.patFont<5 && builtinFontM[settings.patFont]==builtinFont[settings.mainFont]) { - logD("using main font for pat font.\n"); - 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"); - 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"); - 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\n"); - 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"); - 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!\n"); - 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!\n"); - } + } - 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); @@ -2203,6 +2256,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); + } } 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); diff --git a/src/gui/sysConf.cpp b/src/gui/sysConf.cpp index 1bc60c7c..40cc67a3 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; @@ -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 hissing",&n163Multiplex)) { + e->setSysFlags(i,(flags&(~128))|(n163Multiplex<<7),restart); + updateWindowTitle(); + } break; } case DIV_SYSTEM_GB: @@ -395,4 +400,4 @@ void FurnaceGUI::drawSysConf(int i) { } break; } -} \ No newline at end of file +} 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; diff --git a/src/log.cpp b/src/log.cpp index 1f77925b..7f7fae8a 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..dd26dd94 100644 --- a/src/ta-log.h +++ b/src/ta-log.h @@ -21,6 +21,10 @@ #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; + struct tm 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