mirror of
https://github.com/tildearrow/furnace.git
synced 2024-11-15 17:25:06 +00:00
Merge branch 'tildearrow:master' into master
This commit is contained in:
commit
72632b9b72
105 changed files with 3745 additions and 3039 deletions
257
.github/workflows/build.yml
vendored
257
.github/workflows/build.yml
vendored
|
@ -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 }}
|
||||
|
|
|
@ -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()
|
||||
|
|
Binary file not shown.
18
extern/pfd-fixed/portable-file-dialogs.h
vendored
18
extern/pfd-fixed/portable-file-dialogs.h
vendored
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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).
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
4
scripts/Cross-MinGW-x86.cmake
Normal file
4
scripts/Cross-MinGW-x86.cmake
Normal file
|
@ -0,0 +1,4 @@
|
|||
set(CMAKE_SYSTEM_NAME Windows)
|
||||
set(CMAKE_SYSTEM_PROCESSOR i686)
|
||||
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/Cross-MinGW.cmake)
|
4
scripts/Cross-MinGW-x86_64.cmake
Normal file
4
scripts/Cross-MinGW-x86_64.cmake
Normal file
|
@ -0,0 +1,4 @@
|
|||
set(CMAKE_SYSTEM_NAME Windows)
|
||||
set(CMAKE_SYSTEM_PROCESSOR x86_64)
|
||||
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/Cross-MinGW.cmake)
|
14
scripts/Cross-MinGW.cmake
Normal file
14
scripts/Cross-MinGW.cmake
Normal file
|
@ -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)
|
|
@ -44,18 +44,18 @@ bool TAMidiInRtMidi::gather() {
|
|||
|
||||
std::vector<String> TAMidiInRtMidi::listDevices() {
|
||||
std::vector<String> 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; i<count; i++) {
|
||||
String name=port->getPortName(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<String> 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;
|
||||
|
|
|
@ -75,7 +75,7 @@ std::vector<String> TAAudioSDL::listAudioDevices() {
|
|||
std::vector<String> 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<String> 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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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="";
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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; i<runtotal; i++) {
|
||||
temp[0]=bbIn[0][i];
|
||||
|
@ -126,6 +131,9 @@ void DivDispatchContainer::clear() {
|
|||
temp[1]=0;
|
||||
prevSample[0]=0;
|
||||
prevSample[1]=0;
|
||||
if (dispatch->getDCOffRequired()) {
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -17,9 +17,6 @@
|
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "dataErrors.h"
|
||||
#include "song.h"
|
||||
#include <functional>
|
||||
#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; i<song.systemLen; i++) {
|
||||
fname[i]=fmt::sprintf("%s_s%02d.wav",exportPath,i+1);
|
||||
logI("- %s\n",fname[i].c_str());
|
||||
logI("- %s",fname[i].c_str());
|
||||
sf[i]=sf_open(fname[i].c_str(),SFM_WRITE,&si[i]);
|
||||
if (sf[i]==NULL) {
|
||||
logE("could not open file for writing! (%s)\n",sf_strerror(NULL));
|
||||
logE("could not open file for writing! (%s)",sf_strerror(NULL));
|
||||
for (int j=0; j<i; j++) {
|
||||
sf_close(sf[i]);
|
||||
}
|
||||
|
@ -285,7 +282,7 @@ void DivEngine::runExportThread() {
|
|||
deinitAudioBackend();
|
||||
playSub(false);
|
||||
|
||||
logI("rendering to files...\n");
|
||||
logI("rendering to files...");
|
||||
|
||||
while (playing) {
|
||||
nextBuf(NULL,outBuf,0,2,EXPORT_BUFSIZE);
|
||||
|
@ -299,10 +296,10 @@ void DivEngine::runExportThread() {
|
|||
}
|
||||
}
|
||||
if (totalProcessed>EXPORT_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; i<song.systemLen; i++) {
|
||||
if (sf_close(sf[i])!=0) {
|
||||
logE("could not close audio file!\n");
|
||||
logE("could not close audio file!");
|
||||
}
|
||||
}
|
||||
exporting=false;
|
||||
|
@ -325,10 +322,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_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; i<chans; i++) {
|
||||
SNDFILE* sf;
|
||||
SF_INFO si;
|
||||
String fname=fmt::sprintf("%s_c%02d.wav",exportPath,i+1);
|
||||
logI("- %s\n",fname.c_str());
|
||||
logI("- %s",fname.c_str());
|
||||
si.samplerate=got.rate;
|
||||
si.channels=2;
|
||||
si.format=SF_FORMAT_WAV|SF_FORMAT_PCM_16;
|
||||
|
||||
sf=sf_open(fname.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));
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -377,16 +374,16 @@ void DivEngine::runExportThread() {
|
|||
outBuf[2][1+(j<<1)]=MAX(-1.0f,MIN(1.0f,outBuf[1][j]));
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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; i<length; i++) {
|
||||
qsoundMem[(memPos+i)^0x8000]=s->data8[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<DivCommand>& 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; i<song.systemLen; i++) disCont[i].dispatch->setSkipRegisterWrites(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<std::chrono::microseconds>(timeEnd-timeStart).count());
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -873,6 +873,11 @@ void DivEngine::play() {
|
|||
for (int i=0; i<DIV_MAX_CHANS; i++) {
|
||||
keyHit[i]=false;
|
||||
}
|
||||
if (output) if (!skipping && output->midiOut!=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; i<song.systemLen; i++) {
|
||||
disCont[i].dispatch->notifyPlaybackStop();
|
||||
}
|
||||
if (output) if (output->midiOut!=NULL) {
|
||||
output->midiOut->send(TAMidiMessage(TA_MIDI_MACHINE_STOP,0,0));
|
||||
for (int i=0; i<chans; i++) {
|
||||
if (chan[i].curMidiNote>=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; i<chans; i++) {
|
||||
for (int j=0; j<128; j++) {
|
||||
for (int j=0; j<256; j++) {
|
||||
if (song.pat[i].data[j]==NULL) continue;
|
||||
for (int k=0; k<song.patLen; k++) {
|
||||
if (song.pat[i].data[j]->data[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; i<len; i++) {
|
||||
wave->data[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; i<len; i++) {
|
||||
wave->data[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<len; i++) {
|
||||
|
@ -1475,7 +1488,7 @@ int DivEngine::addSampleFromFile(const char* path) {
|
|||
}
|
||||
short* buf=new short[si.channels*si.frames];
|
||||
if (sf_readf_short(f,buf,si.frames)!=si.frames) {
|
||||
logW("sample read size mismatch!\n");
|
||||
logW("sample read size mismatch!");
|
||||
}
|
||||
DivSample* sample=new DivSample;
|
||||
int sampleCount=(int)song.sample.size();
|
||||
|
@ -1556,7 +1569,7 @@ void DivEngine::delSample(int index) {
|
|||
|
||||
void DivEngine::addOrder(bool duplicate, bool where) {
|
||||
unsigned char order[DIV_MAX_CHANS];
|
||||
if (song.ordersLen>=0x7e) return;
|
||||
if (song.ordersLen>=0xff) return;
|
||||
BUSY_BEGIN_SOFT;
|
||||
if (duplicate) {
|
||||
for (int i=0; i<DIV_MAX_CHANS; i++) {
|
||||
|
@ -1569,7 +1582,7 @@ void DivEngine::addOrder(bool duplicate, bool where) {
|
|||
for (int j=0; j<song.ordersLen; j++) {
|
||||
used[song.orders.ord[i][j]]=true;
|
||||
}
|
||||
order[i]=0x7e;
|
||||
order[i]=0xff;
|
||||
for (int j=0; j<256; j++) {
|
||||
if (!used[j]) {
|
||||
order[i]=j;
|
||||
|
@ -1605,23 +1618,23 @@ void DivEngine::addOrder(bool duplicate, bool where) {
|
|||
|
||||
void DivEngine::deepCloneOrder(bool where) {
|
||||
unsigned char order[DIV_MAX_CHANS];
|
||||
if (song.ordersLen>=0x7e) return;
|
||||
if (song.ordersLen>=0xff) return;
|
||||
warnings="";
|
||||
BUSY_BEGIN_SOFT;
|
||||
for (int i=0; i<chans; i++) {
|
||||
bool didNotFind=true;
|
||||
logD("channel %d\n",i);
|
||||
logD("channel %d",i);
|
||||
order[i]=song.orders.ord[i][curOrder];
|
||||
// find free slot
|
||||
for (int j=0; j<128; j++) {
|
||||
logD("finding free slot in %d...\n",j);
|
||||
for (int j=0; j<256; j++) {
|
||||
logD("finding free slot in %d...",j);
|
||||
if (song.pat[i].data[j]==NULL) {
|
||||
int origOrd=order[i];
|
||||
order[i]=j;
|
||||
DivPattern* oldPat=song.pat[i].getPattern(origOrd,false);
|
||||
DivPattern* pat=song.pat[i].getPattern(j,true);
|
||||
memcpy(pat->data,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; i<chans; i++) {
|
||||
for (int j=0; j<128; j++) {
|
||||
for (int j=0; j<256; j++) {
|
||||
if (song.pat[i].data[j]==NULL) continue;
|
||||
for (int k=0; k<song.patLen; k++) {
|
||||
if (song.pat[i].data[j]->data[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];
|
||||
|
|
|
@ -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),
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -41,10 +41,10 @@ void DivEngine::loadDMP(SafeReader& reader, std::vector<DivInstrument*>& 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<DivInstrument*>& 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<DivInstrument*>& 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<DivInstrument*>& 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<DivInstrument*>& 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<DivInstrument*>& ret, St
|
|||
if (sys!=1) ins->fm.ams=reader.readC();
|
||||
|
||||
for (int j=0; j<ins->fm.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<DivInstrument*>& 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; i<ins->std.volMacroLen; i++) {
|
||||
ins->std.volMacro[i]=reader.readI();
|
||||
for (int i=0; i<ins->std.volMacro.len; i++) {
|
||||
ins->std.volMacro.val[i]=reader.readI();
|
||||
}
|
||||
} else {
|
||||
for (int i=0; i<ins->std.volMacroLen; i++) {
|
||||
ins->std.volMacro[i]=reader.readC();
|
||||
for (int i=0; i<ins->std.volMacro.len; i++) {
|
||||
ins->std.volMacro.val[i]=reader.readC();
|
||||
}
|
||||
}
|
||||
if (version<11) for (int i=0; i<ins->std.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; i<ins->std.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; i<ins->std.arpMacroLen; i++) {
|
||||
ins->std.arpMacro[i]=reader.readI();
|
||||
for (int i=0; i<ins->std.arpMacro.len; i++) {
|
||||
ins->std.arpMacro.val[i]=reader.readI();
|
||||
}
|
||||
} else {
|
||||
for (int i=0; i<ins->std.arpMacroLen; i++) {
|
||||
ins->std.arpMacro[i]=reader.readC();
|
||||
for (int i=0; i<ins->std.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; i<ins->std.dutyMacroLen; i++) {
|
||||
ins->std.dutyMacro[i]=reader.readI();
|
||||
for (int i=0; i<ins->std.dutyMacro.len; i++) {
|
||||
ins->std.dutyMacro.val[i]=reader.readI();
|
||||
}
|
||||
} else {
|
||||
for (int i=0; i<ins->std.dutyMacroLen; i++) {
|
||||
ins->std.dutyMacro[i]=reader.readC();
|
||||
for (int i=0; i<ins->std.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; i<ins->std.waveMacroLen; i++) {
|
||||
ins->std.waveMacro[i]=reader.readI();
|
||||
for (int i=0; i<ins->std.waveMacro.len; i++) {
|
||||
ins->std.waveMacro.val[i]=reader.readI();
|
||||
}
|
||||
} else {
|
||||
for (int i=0; i<ins->std.waveMacroLen; i++) {
|
||||
ins->std.waveMacro[i]=reader.readC();
|
||||
for (int i=0; i<ins->std.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<DivInstrument*>& 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<DivInstrument*>& 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<DivInstrument*>& 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<DivInstrument*>& 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<DivInstrument*>& 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<DivInstrument*>& 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<DivInstrument*> 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<DivInstrument*> 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;
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <math.h>
|
||||
#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;
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -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 {
|
||||
|
|
|
@ -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<sourceLen && sourceLoop>=0 && sourceLoop<sourceRel) { \
|
||||
pos=sourceLoop; \
|
||||
} else { \
|
||||
pos--; \
|
||||
} \
|
||||
} \
|
||||
if (pos>=sourceLen) { \
|
||||
if (sourceLoop<sourceLen && 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<source.len && source.loop>=0 && source.loop<source.rel) {
|
||||
pos=source.loop;
|
||||
} else {
|
||||
pos--;
|
||||
}
|
||||
}
|
||||
if (pos>=source.len) {
|
||||
if (source.loop<source.len && 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; i<macroListLen; i++) {
|
||||
if (macroList[i]!=NULL && macroSource[i]!=NULL) {
|
||||
macroList[i]->doMacro(*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; i<macroListLen; i++) {
|
||||
if (macroList[i]!=NULL) macroList[i]->init();
|
||||
}
|
||||
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; i<macroListLen; i++) {
|
||||
macroList[i]->prepare(*macroSource[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void DivMacroInt::notifyInsDeletion(DivInstrument* which) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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*));
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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].sample<parent->song.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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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<DivRegWrite>& wlist);
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -74,8 +74,8 @@ 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)";
|
||||
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;
|
||||
|
|
|
@ -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) {}
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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<next) {
|
||||
dacAntiClick+=8;
|
||||
rWrite(0x4011,dacAntiClick);
|
||||
} else {
|
||||
dacAntiClickOn=false;
|
||||
rWrite(0x4011,next);
|
||||
}
|
||||
}
|
||||
if (++dacPos>=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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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; j<ops; j++) {
|
||||
unsigned char slot=slots[j][i];
|
||||
if (slot==255) continue;
|
||||
|
@ -253,30 +253,30 @@ void DivPlatformOPL::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;
|
||||
}
|
||||
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 (chan[i].std.hadAlg || chan[i].std.hadFb) {
|
||||
if (chan[i].std.alg.had || chan[i].std.fb.had) {
|
||||
if (isMuted[i]) {
|
||||
rWrite(chanMap[i]+ADDR_LR_FB_ALG,(chan[i].state.alg&1)|(chan[i].state.fb<<1));
|
||||
if (ops==4) {
|
||||
|
@ -296,58 +296,58 @@ void DivPlatformOPL::tick() {
|
|||
unsigned short baseAddr=slotMap[slot];
|
||||
DivInstrumentFM::Operator& op=chan[i].state.op[(ops==4)?orderedOpsL[j]:j];
|
||||
DivMacroInt::IntOp& m=chan[i].std.op[(ops==4)?orderedOpsL[j]:j];
|
||||
if (m.hadAm) {
|
||||
op.am=m.am;
|
||||
if (m.am.had) {
|
||||
op.am=m.am.val;
|
||||
rWrite(baseAddr+ADDR_AM_VIB_SUS_KSR_MULT,(op.am<<7)|(op.vib<<6)|(op.sus<<5)|(op.ksr<<4)|op.mult);
|
||||
}
|
||||
if (m.hadVib) {
|
||||
op.vib=m.vib;
|
||||
if (m.vib.had) {
|
||||
op.vib=m.vib.val;
|
||||
rWrite(baseAddr+ADDR_AM_VIB_SUS_KSR_MULT,(op.am<<7)|(op.vib<<6)|(op.sus<<5)|(op.ksr<<4)|op.mult);
|
||||
}
|
||||
if (m.hadSus) {
|
||||
op.sus=m.sus;
|
||||
if (m.sus.had) {
|
||||
op.sus=m.sus.val;
|
||||
rWrite(baseAddr+ADDR_AM_VIB_SUS_KSR_MULT,(op.am<<7)|(op.vib<<6)|(op.sus<<5)|(op.ksr<<4)|op.mult);
|
||||
}
|
||||
if (m.hadKsr) {
|
||||
op.ksr=m.ksr;
|
||||
if (m.ksr.had) {
|
||||
op.ksr=m.ksr.val;
|
||||
rWrite(baseAddr+ADDR_AM_VIB_SUS_KSR_MULT,(op.am<<7)|(op.vib<<6)|(op.sus<<5)|(op.ksr<<4)|op.mult);
|
||||
}
|
||||
if (m.hadMult) {
|
||||
op.mult=m.mult;
|
||||
if (m.mult.had) {
|
||||
op.mult=m.mult.val;
|
||||
rWrite(baseAddr+ADDR_AM_VIB_SUS_KSR_MULT,(op.am<<7)|(op.vib<<6)|(op.sus<<5)|(op.ksr<<4)|op.mult);
|
||||
}
|
||||
|
||||
if (m.hadAr) {
|
||||
op.ar=m.ar;
|
||||
if (m.ar.had) {
|
||||
op.ar=m.ar.val;
|
||||
rWrite(baseAddr+ADDR_AR_DR,(op.ar<<4)|op.dr);
|
||||
}
|
||||
if (m.hadDr) {
|
||||
op.dr=m.dr;
|
||||
if (m.dr.had) {
|
||||
op.dr=m.dr.val;
|
||||
rWrite(baseAddr+ADDR_AR_DR,(op.ar<<4)|op.dr);
|
||||
}
|
||||
if (m.hadSl) {
|
||||
op.sl=m.sl;
|
||||
if (m.sl.had) {
|
||||
op.sl=m.sl.val;
|
||||
rWrite(baseAddr+ADDR_SL_RR,(op.sl<<4)|op.rr);
|
||||
}
|
||||
if (m.hadRr) {
|
||||
op.rr=m.rr;
|
||||
if (m.rr.had) {
|
||||
op.rr=m.rr.val;
|
||||
rWrite(baseAddr+ADDR_SL_RR,(op.sl<<4)|op.rr);
|
||||
}
|
||||
|
||||
if (oplType>1) {
|
||||
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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
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<u32>(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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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]) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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:
|
||||
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;
|
||||
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<size; i++) {
|
||||
oscBuf[0][oscWritePos]=out[0][i];
|
||||
oscBuf[1][oscWritePos]=out[1][i];
|
||||
if (++oscWritePos>=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; i<song.systemLen; i++) {
|
||||
float volL=((float)song.systemVol[i]/64.0f)*((float)MIN(127,127-(int)song.systemPan[i])/127.0f)*song.masterVol;
|
||||
float volR=((float)song.systemVol[i]/64.0f)*((float)MIN(127,127+(int)song.systemPan[i])/127.0f)*song.masterVol;
|
||||
volL*=disCont[i].dispatch->getPostAmp();
|
||||
volR*=disCont[i].dispatch->getPostAmp();
|
||||
if (disCont[i].dispatch->isStereo()) {
|
||||
for (size_t j=0; j<size; j++) {
|
||||
out[0][j]+=((float)disCont[i].bbOut[0][j]/32768.0)*volL;
|
||||
|
@ -1880,8 +1932,11 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi
|
|||
while (metroPos>=1) metroPos--;
|
||||
}
|
||||
|
||||
memcpy(oscBuf[0],out[0],size*sizeof(float));
|
||||
memcpy(oscBuf[1],out[1],size*sizeof(float));
|
||||
for (unsigned int i=0; i<size; i++) {
|
||||
oscBuf[0][oscWritePos]=out[0][i];
|
||||
oscBuf[1][oscWritePos]=out[1][i];
|
||||
if (++oscWritePos>=32768) oscWritePos=0;
|
||||
}
|
||||
oscSize=size;
|
||||
|
||||
if (forceMono) {
|
||||
|
|
|
@ -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<stlen) {
|
||||
|
|
|
@ -24,6 +24,11 @@
|
|||
#include <stdint.h>
|
||||
#include "../ta-utils.h"
|
||||
|
||||
enum Endianness {
|
||||
LittleEndian=0,
|
||||
BigEndian
|
||||
};
|
||||
|
||||
class SafeReader;
|
||||
|
||||
struct EndOfFileException {
|
||||
|
|
|
@ -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(); \
|
||||
\
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.val<song.sampleLen) {
|
||||
|
@ -599,7 +599,7 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
|
|||
}
|
||||
break;
|
||||
default:
|
||||
logW("write not handled!\n");
|
||||
logW("write not handled!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -620,7 +620,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) {
|
|||
int loopRow=0;
|
||||
int loopEnd=0;
|
||||
walkSong(loopOrder,loopRow,loopEnd);
|
||||
logI("loop point: %d %d\n",loopOrder,loopRow);
|
||||
logI("loop point: %d %d",loopOrder,loopRow);
|
||||
warnings="";
|
||||
|
||||
curOrder=0;
|
||||
|
@ -1162,7 +1162,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) {
|
|||
unsigned int sampleSeek=0;
|
||||
for (int i=0; i<song.sampleLen; i++) {
|
||||
DivSample* sample=song.sample[i];
|
||||
logI("setting seek to %d\n",sampleSeek);
|
||||
logI("setting seek to %d",sampleSeek);
|
||||
sample->off8=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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -8,6 +8,7 @@ bool FurnaceGUIFileDialog::openLoad(String header, std::vector<String> 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<String> 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();
|
||||
|
|
|
@ -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 && orderCursor<e->getTotalChannelCount()) {
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -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<UndoStep> undoHist;
|
||||
std::deque<UndoStep> redoHist;
|
||||
|
||||
|
@ -976,10 +1000,19 @@ 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);
|
||||
void drawAlgorithm(unsigned char alg, FurnaceGUIFMAlgs algType, 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);
|
||||
|
|
|
@ -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)),
|
||||
};
|
||||
|
|
|
@ -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) { \
|
||||
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(); \
|
||||
} \
|
||||
if (macroMode!=NULL) { \
|
||||
ImGui::Checkbox("Fixed##IMacroMode_" macroName,macroMode); \
|
||||
} \
|
||||
} \
|
||||
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<macroRel)) { \
|
||||
if (j+macroDragScroll>=macro.len || (j+macroDragScroll>macro.rel && macro.loop<macro.rel)) { \
|
||||
loopIndicator[j]=0; \
|
||||
} else { \
|
||||
loopIndicator[j]=((macroLoop!=-1 && (j+macroDragScroll)>=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<<macroAMax)-1):macroAMax,macroRel); \
|
||||
decodeMMLStr(mmlStr,macro.val,macro.len,macro.loop,macroAMin,(bitfield)?((1<<(bitfield?macroAMax:0))-1):macroAMax,macro.rel); \
|
||||
} \
|
||||
if (!ImGui::IsItemActive()) { \
|
||||
encodeMMLStr(mmlStr,macro,macroLen,macroLoop,macroRel); \
|
||||
encodeMMLStr(mmlStr,macro.val,macro.len,macro.loop,macro.rel); \
|
||||
} \
|
||||
} \
|
||||
ImGui::PopStyleVar();
|
||||
|
||||
#define OP_MACRO(macro,macroLen,macroLoop,macroRel,macroHeight,op,macroName,displayName,displayHeight,displayLoop,bitfield,bfVal,mmlStr) \
|
||||
#define OP_MACRO(macro,macroHeight,op,macroName,displayName,displayHeight,displayLoop,bitfield,bfVal,macroMode,macroModeMax,displayModeName,mmlStr) \
|
||||
ImGui::TableNextRow(); \
|
||||
ImGui::TableNextColumn(); \
|
||||
ImGui::Text("%s",displayName); \
|
||||
|
@ -1062,23 +1091,41 @@ void FurnaceGUI::drawFMEnv(unsigned char tl, unsigned char ar, unsigned char dr,
|
|||
} \
|
||||
if (displayLoop) { \
|
||||
ImGui::SetNextItemWidth(lenAvail); \
|
||||
if (ImGui::InputScalar("##IOPMacroLen_" #op macroName,ImGuiDataType_U8,¯oLen,&_ONE,&_THREE)) { MARK_MODIFIED \
|
||||
if (macroLen>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<macroRel)) { \
|
||||
if (j+macroDragScroll>=macro.len || (j+macroDragScroll>macro.rel && macro.loop<macro.rel)) { \
|
||||
loopIndicator[j]=0; \
|
||||
} else { \
|
||||
loopIndicator[j]=((macroLoop!=-1 && (j+macroDragScroll)>=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<<macroHeight)-1):(macroHeight),macroRel); \
|
||||
decodeMMLStr(mmlStr,macro.val,macro.len,macro.loop,0,bitfield?((1<<(bitfield?macroHeight:0))-1):(macroHeight),macro.rel); \
|
||||
} \
|
||||
if (!ImGui::IsItemActive()) { \
|
||||
encodeMMLStr(mmlStr,macro,macroLen,macroLoop,macroRel); \
|
||||
encodeMMLStr(mmlStr,macro.val,macro.len,macro.loop,macro.rel); \
|
||||
} \
|
||||
} \
|
||||
ImGui::PopStyleVar();
|
||||
|
@ -1262,7 +1309,7 @@ void FurnaceGUI::drawInsEdit() {
|
|||
ImGui::Text("Type");
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
if (ins->type<0 || ins->type>=DIV_INS_MAX) ins->type=DIV_INS_FM;
|
||||
if (ins->type>=DIV_INS_MAX) ins->type=DIV_INS_FM;
|
||||
int insType=ins->type;
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
if (ImGui::Combo("##Type",&insType,insTypes,DIV_INS_MAX,DIV_INS_MAX)) {
|
||||
|
@ -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,6 +2000,7 @@ void FurnaceGUI::drawInsEdit() {
|
|||
ImGui::TableNextColumn();
|
||||
ImGui::Text("%s",FM_NAME(FM_DT2));
|
||||
|
||||
if (ins->type==DIV_INS_FM) { // OPN only
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
|
@ -1962,6 +2010,7 @@ void FurnaceGUI::drawInsEdit() {
|
|||
ImGui::TableNextColumn();
|
||||
ImGui::Text("%s",FM_NAME(FM_SSG));
|
||||
}
|
||||
}
|
||||
|
||||
if (ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPZ) {
|
||||
ImGui::TableNextRow();
|
||||
|
@ -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);
|
||||
}
|
||||
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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
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; i<ins->std.volMacroLen; i++) {
|
||||
for (int i=0; i<ins->std.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; i<ins->std.arpMacroLen; i++) {
|
||||
asFloat[i]=ins->std.arpMacro[i];
|
||||
loopIndicator[i]=(ins->std.arpMacroLoop!=-1 && i>=ins->std.arpMacroLoop);
|
||||
for (int i=0; i<ins->std.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; i<ins->std.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; i<ins->std.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; i<ins->std.waveMacroLen; i++) {
|
||||
asFloat[i]=ins->std.waveMacro[i];
|
||||
for (int i=0; i<ins->std.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; i<ins->std.ex1MacroLen; i++) {
|
||||
asFloat[i]=ins->std.ex1Macro[i];
|
||||
loopIndicator[i]=(ins->std.ex1MacroLoop!=-1 && i>=ins->std.ex1MacroLoop);
|
||||
for (int i=0; i<ins->std.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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
77
src/gui/log.cpp
Normal file
77
src/gui/log.cpp
Normal file
|
@ -0,0 +1,77 @@
|
|||
#include "gui.h"
|
||||
#include "../ta-log.h"
|
||||
#include <imgui.h>
|
||||
|
||||
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<TA_LOG_SIZE; i++) {
|
||||
const LogEntry& logEntry=logEntries[(pos+i)&(TA_LOG_SIZE-1)];
|
||||
if (!logEntry.ready) continue;
|
||||
if (logLevel<logEntry.loglevel) continue;
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("%02d:%02d:%02d",logEntry.time.tm_hour,logEntry.time.tm_min,logEntry.time.tm_sec);
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextColored(uiColors[logColors[logEntry.loglevel]],"%s",logLevels[logEntry.loglevel]);
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextWrapped("%s",logEntry.text.c_str());
|
||||
}
|
||||
ImGui::PopFont();
|
||||
|
||||
if (followLog) {
|
||||
ImGui::SetScrollY(ImGui::GetScrollMaxY());
|
||||
}
|
||||
ImGui::EndTable();
|
||||
}
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
|
@ -64,7 +64,7 @@ int MIDIMap::at(const TAMidiMessage& where) {
|
|||
|
||||
#define UNDERSTAND_ARRAY_OPTION(x,yMax) if (optionNameS==#x) { \
|
||||
if (optionIndex<0 || optionIndex>=yMax) { \
|
||||
logW("MIDI map array option %d out of range (0-%d) at line %d: %s\n",optionIndex,yMax,curLine,line); \
|
||||
logW("MIDI map array option %d out of range (0-%d) at line %d: %s",optionIndex,yMax,curLine,line); \
|
||||
break; \
|
||||
} \
|
||||
x[optionIndex]=std::stoi(optionValueS); \
|
||||
|
@ -76,7 +76,7 @@ bool MIDIMap::read(String path) {
|
|||
FILE* f=fopen(path.c_str(),"rb");
|
||||
if (f==NULL) {
|
||||
if (errno!=ENOENT) {
|
||||
logE("error while loading MIDI mapping! %s\n",strerror(errno));
|
||||
logE("error while loading MIDI mapping! %s",strerror(errno));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -93,7 +93,7 @@ bool MIDIMap::read(String path) {
|
|||
|
||||
int result=sscanf(line,"aOption %255s %d %255s",optionName,&optionIndex,optionValue);
|
||||
if (result!=3) {
|
||||
logW("MIDI map garbage data at line %d: %s\n",curLine,line);
|
||||
logW("MIDI map garbage data at line %d: %s",curLine,line);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -105,12 +105,12 @@ bool MIDIMap::read(String path) {
|
|||
UNDERSTAND_ARRAY_OPTION(valueInputSpecificMSB,18) else
|
||||
UNDERSTAND_ARRAY_OPTION(valueInputSpecificLSB,18) else
|
||||
UNDERSTAND_ARRAY_OPTION(valueInputSpecificSingle,18) else {
|
||||
logW("MIDI map unknown array option %s at line %d: %s\n",optionName,curLine,line);
|
||||
logW("MIDI map unknown array option %s at line %d: %s",optionName,curLine,line);
|
||||
}
|
||||
} catch (std::out_of_range& e) {
|
||||
logW("MIDI map invalid value %s for array option %s at line %d: %s\n",optionValue,optionName,curLine,line);
|
||||
logW("MIDI map invalid value %s for array option %s at line %d: %s",optionValue,optionName,curLine,line);
|
||||
} catch (std::invalid_argument& e) {
|
||||
logW("MIDI map invalid value %s for array option %s at line %d: %s\n",optionValue,optionName,curLine,line);
|
||||
logW("MIDI map invalid value %s for array option %s at line %d: %s",optionValue,optionName,curLine,line);
|
||||
}
|
||||
|
||||
curLine++;
|
||||
|
@ -122,7 +122,7 @@ bool MIDIMap::read(String path) {
|
|||
String optionNameS, optionValueS;
|
||||
int result=sscanf(line,"option %255s %255s",optionName,optionValue);
|
||||
if (result!=2) {
|
||||
logW("MIDI map garbage data at line %d: %s\n",curLine,line);
|
||||
logW("MIDI map garbage data at line %d: %s",curLine,line);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -143,12 +143,12 @@ bool MIDIMap::read(String path) {
|
|||
UNDERSTAND_OPTION(valueInputControlLSB) else
|
||||
UNDERSTAND_OPTION(valueInputControlSingle) else
|
||||
UNDERSTAND_FLOAT_OPTION(volExp) else {
|
||||
logW("MIDI map unknown option %s at line %d: %s\n",optionName,curLine,line);
|
||||
logW("MIDI map unknown option %s at line %d: %s",optionName,curLine,line);
|
||||
}
|
||||
} catch (std::out_of_range& e) {
|
||||
logW("MIDI map invalid value %s for option %s at line %d: %s\n",optionValue,optionName,curLine,line);
|
||||
logW("MIDI map invalid value %s for option %s at line %d: %s",optionValue,optionName,curLine,line);
|
||||
} catch (std::invalid_argument& e) {
|
||||
logW("MIDI map invalid value %s for option %s at line %d: %s\n",optionValue,optionName,curLine,line);
|
||||
logW("MIDI map invalid value %s for option %s at line %d: %s",optionValue,optionName,curLine,line);
|
||||
}
|
||||
|
||||
curLine++;
|
||||
|
@ -159,7 +159,7 @@ bool MIDIMap::read(String path) {
|
|||
MIDIBind bind;
|
||||
int result=sscanf(line,"%d %d %d %d %255s",&bind.type,&bind.channel,&bind.data1,&bind.data2,bindAction);
|
||||
if (result!=5 || result==EOF) {
|
||||
logW("MIDI map garbage data at line %d: %s\n",curLine,line);
|
||||
logW("MIDI map garbage data at line %d: %s",curLine,line);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -172,7 +172,7 @@ bool MIDIMap::read(String path) {
|
|||
}
|
||||
}
|
||||
if (!foundAction) {
|
||||
logW("MIDI map unknown action %s at line %d: %s\n",bindAction,curLine,line);
|
||||
logW("MIDI map unknown action %s at line %d: %s",bindAction,curLine,line);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -191,7 +191,7 @@ bool MIDIMap::read(String path) {
|
|||
bool MIDIMap::write(String path) {
|
||||
FILE* f=fopen(path.c_str(),"wb");
|
||||
if (f==NULL) {
|
||||
logE("error while saving MIDI mapping! %s\n",strerror(errno));
|
||||
logE("error while saving MIDI mapping! %s",strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -218,7 +218,7 @@ bool MIDIMap::write(String path) {
|
|||
|
||||
for (MIDIBind& i: binds) {
|
||||
if (fprintf(f,"%d %d %d %d %s\n",i.type,i.channel,i.data1,i.data2,guiActions[i.action].name)<0) {
|
||||
logW("did not write MIDI mapping entirely! %s\n",strerror(errno));
|
||||
logW("did not write MIDI mapping entirely! %s",strerror(errno));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -274,6 +274,6 @@ void MIDIMap::compile() {
|
|||
}
|
||||
|
||||
map[i.type-8][i.channel][i.data1][i.data2]=i.action;
|
||||
logD("MIDI mapping %d %d %d %d to %d\n",i.type-8,i.channel,i.data1,i.data2,i.action);
|
||||
logD("MIDI mapping %d %d %d %d to %d",i.type-8,i.channel,i.data1,i.data2,i.action);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -102,10 +102,10 @@ void FurnaceGUI::drawOrders() {
|
|||
e->lockSave([this,i,j]() {
|
||||
if (changeAllOrders) {
|
||||
for (int k=0; k<e->getTotalChannelCount(); 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);
|
||||
|
|
153
src/gui/osc.cpp
153
src/gui/osc.cpp
|
@ -18,6 +18,52 @@
|
|||
*/
|
||||
|
||||
#include "gui.h"
|
||||
#include "imgui_internal.h"
|
||||
#include <imgui.h>
|
||||
#include <math.h>
|
||||
|
||||
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; j<total; j++) {
|
||||
int pos=(readPos+j)&0x7fff;
|
||||
if (fabs(e->oscBuf[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));
|
||||
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)) {
|
||||
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;
|
||||
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::SetCursorPos(ImVec2(0,0));
|
||||
ImGui::BeginDisabled();
|
||||
ImGui::PlotLines("##SingleOsc",values,512,0,NULL,-1.0f,1.0f,ImGui::GetContentRegionAvail());
|
||||
ImGui::EndDisabled();
|
||||
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; i<v1; i++) {
|
||||
ImDrawVert* v=&dl->VtxBuffer.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);
|
||||
}
|
||||
if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_OSCILLOSCOPE;
|
||||
ImGui::End();
|
||||
}
|
|
@ -17,8 +17,6 @@
|
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <SDL_timer.h>
|
||||
#include <imgui.h>
|
||||
#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));
|
||||
}
|
||||
|
||||
|
|
|
@ -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; i<availY; i++) {
|
||||
for (int j=0; j<availX; j++) {
|
||||
if (sample->loopStart>=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;
|
||||
|
|
|
@ -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; i<GUI_COLOR_MAX; i++) {
|
||||
|
@ -1621,14 +1669,14 @@ void FurnaceGUI::commitSettings() {
|
|||
|
||||
ImGui_ImplSDLRenderer_DestroyFontsTexture();
|
||||
if (!ImGui::GetIO().Fonts->Build()) {
|
||||
logE("error while building font atlas!\n");
|
||||
logE("error while building font atlas!");
|
||||
showError("error while loading fonts! please check your settings.");
|
||||
ImGui::GetIO().Fonts->Clear();
|
||||
mainFont=ImGui::GetIO().Fonts->AddFontDefault();
|
||||
patFont=mainFont;
|
||||
ImGui_ImplSDLRenderer_DestroyFontsTexture();
|
||||
if (!ImGui::GetIO().Fonts->Build()) {
|
||||
logE("error again while building font atlas!\n");
|
||||
logE("error again while building font atlas!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<GUI_COLOR_MAX; i++) {
|
||||
if (fprintf(f,"%s=%d\n",guiColors[i].name,ImGui::ColorConvertFloat4ToU32(uiColors[i]))<0) {
|
||||
logW("error while exporting colors: %s\n",strerror(errno));
|
||||
logW("error while exporting colors: %s",strerror(errno));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1703,7 +1752,7 @@ bool FurnaceGUI::exportColors(String path) {
|
|||
bool FurnaceGUI::importKeybinds(String path) {
|
||||
FILE* f=ps_fopen(path.c_str(),"rb");
|
||||
if (f==NULL) {
|
||||
logW("error while opening keybind file for import: %s\n",strerror(errno));
|
||||
logW("error while opening keybind file for import: %s",strerror(errno));
|
||||
return false;
|
||||
}
|
||||
resetKeybinds();
|
||||
|
@ -1744,7 +1793,7 @@ bool FurnaceGUI::importKeybinds(String path) {
|
|||
break;
|
||||
}
|
||||
}
|
||||
if (!found) logW("line invalid: %s\n",line);
|
||||
if (!found) logW("line invalid: %s",line);
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
|
@ -1754,13 +1803,13 @@ bool FurnaceGUI::importKeybinds(String path) {
|
|||
bool FurnaceGUI::exportKeybinds(String path) {
|
||||
FILE* f=ps_fopen(path.c_str(),"wb");
|
||||
if (f==NULL) {
|
||||
logW("error while opening keybind file for export: %s\n",strerror(errno));
|
||||
logW("error while opening keybind file for export: %s",strerror(errno));
|
||||
return false;
|
||||
}
|
||||
for (int i=0; i<GUI_ACTION_MAX; i++) {
|
||||
if (guiActions[i].defaultBind==-1) continue;
|
||||
if (fprintf(f,"%s=%d\n",guiActions[i].name,actionKeys[i])<0) {
|
||||
logW("error while exporting keybinds: %s\n",strerror(errno));
|
||||
logW("error while exporting keybinds: %s",strerror(errno));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1771,7 +1820,7 @@ bool FurnaceGUI::exportKeybinds(String path) {
|
|||
bool FurnaceGUI::importLayout(String path) {
|
||||
FILE* f=ps_fopen(path.c_str(),"rb");
|
||||
if (f==NULL) {
|
||||
logW("error while opening keybind file for import: %s\n",strerror(errno));
|
||||
logW("error while opening keybind file for import: %s",strerror(errno));
|
||||
return false;
|
||||
}
|
||||
if (fseek(f,0,SEEK_END)<0) {
|
||||
|
@ -1785,7 +1834,7 @@ bool FurnaceGUI::importLayout(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");
|
||||
|
@ -1818,13 +1867,13 @@ bool FurnaceGUI::importLayout(String path) {
|
|||
bool FurnaceGUI::exportLayout(String path) {
|
||||
FILE* f=ps_fopen(path.c_str(),"wb");
|
||||
if (f==NULL) {
|
||||
logW("error while opening layout file for export: %s\n",strerror(errno));
|
||||
logW("error while opening layout file for export: %s",strerror(errno));
|
||||
return false;
|
||||
}
|
||||
size_t dataSize=0;
|
||||
const char* data=ImGui::SaveIniSettingsToMemory(&dataSize);
|
||||
if (fwrite(data,1,dataSize,f)!=dataSize) {
|
||||
logW("error while exporting layout: %s\n",strerror(errno));
|
||||
logW("error while exporting layout: %s",strerror(errno));
|
||||
}
|
||||
fclose(f);
|
||||
return true;
|
||||
|
@ -1924,7 +1973,7 @@ void FurnaceGUI::parseKeybinds() {
|
|||
#define SYSTEM_PAT_FONT_PATH_3 "/usr/share/fonts/ubuntu/UbuntuMono-R.ttf"
|
||||
#endif
|
||||
|
||||
void FurnaceGUI::applyUISettings() {
|
||||
void FurnaceGUI::applyUISettings(bool updateFonts) {
|
||||
ImGuiStyle sty;
|
||||
if (settings.guiColorsBase) {
|
||||
ImGui::StyleColorsLight(&sty);
|
||||
|
@ -1935,9 +1984,11 @@ void FurnaceGUI::applyUISettings() {
|
|||
if (settings.dpiScale>=0.5f) dpiScale=settings.dpiScale;
|
||||
|
||||
// colors
|
||||
if (updateFonts) {
|
||||
for (int i=0; i<GUI_COLOR_MAX; i++) {
|
||||
uiColors[i]=ImGui::ColorConvertU32ToFloat4(e->getConfInt(guiColors[i].name,guiColors[i].defaultColor));
|
||||
}
|
||||
}
|
||||
|
||||
for (int i=0; i<64; i++) {
|
||||
ImVec4 col1=uiColors[GUI_COLOR_PATTERN_VOLUME_MIN];
|
||||
|
@ -2064,6 +2115,7 @@ void FurnaceGUI::applyUISettings() {
|
|||
sysCmd2Grad[i]=ImGui::GetColorU32(ImVec4(base.x,base.y,base.z,((float)i/255.0f)*base.w));
|
||||
}
|
||||
|
||||
if (updateFonts) {
|
||||
// set to 800 for now due to problems with unifont
|
||||
static const ImWchar upTo800[]={0x20,0x7e,0xa0,0x800,0};
|
||||
ImFontGlyphRangesBuilder range;
|
||||
|
@ -2088,11 +2140,11 @@ void FurnaceGUI::applyUISettings() {
|
|||
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");
|
||||
logW("UI font path is empty! reverting to default font");
|
||||
settings.mainFont=0;
|
||||
}
|
||||
if (settings.patFont==6 && settings.patFontPath.empty()) {
|
||||
logW("pattern font path is empty! reverting to default font\n");
|
||||
logW("pattern font path is empty! reverting to default font");
|
||||
settings.patFont=0;
|
||||
}
|
||||
|
||||
|
@ -2101,10 +2153,10 @@ void FurnaceGUI::applyUISettings() {
|
|||
|
||||
if (settings.mainFont==6) { // custom font
|
||||
if ((mainFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(settings.mainFontPath.c_str(),e->getConfInt("mainFontSize",18)*dpiScale,NULL,fontRange))==NULL) {
|
||||
logW("could not load UI font! reverting to default font\n");
|
||||
logW("could not load UI font! reverting to default font");
|
||||
settings.mainFont=0;
|
||||
if ((mainFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFont[settings.mainFont],builtinFontLen[settings.mainFont],e->getConfInt("mainFontSize",18)*dpiScale,NULL,fontRange))==NULL) {
|
||||
logE("could not load UI font! falling back to Proggy Clean.\n");
|
||||
logE("could not load UI font! falling back to Proggy Clean.");
|
||||
mainFont=ImGui::GetIO().Fonts->AddFontDefault();
|
||||
}
|
||||
}
|
||||
|
@ -2112,10 +2164,10 @@ void FurnaceGUI::applyUISettings() {
|
|||
if ((mainFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_FONT_PATH_1,e->getConfInt("mainFontSize",18)*dpiScale,NULL,fontRange))==NULL) {
|
||||
if ((mainFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_FONT_PATH_2,e->getConfInt("mainFontSize",18)*dpiScale,NULL,fontRange))==NULL) {
|
||||
if ((mainFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_FONT_PATH_3,e->getConfInt("mainFontSize",18)*dpiScale,NULL,fontRange))==NULL) {
|
||||
logW("could not load UI font! reverting to default font\n");
|
||||
logW("could not load UI font! reverting to default font");
|
||||
settings.mainFont=0;
|
||||
if ((mainFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFont[settings.mainFont],builtinFontLen[settings.mainFont],e->getConfInt("mainFontSize",18)*dpiScale,NULL,fontRange))==NULL) {
|
||||
logE("could not load UI font! falling back to Proggy Clean.\n");
|
||||
logE("could not load UI font! falling back to Proggy Clean.");
|
||||
mainFont=ImGui::GetIO().Fonts->AddFontDefault();
|
||||
}
|
||||
}
|
||||
|
@ -2123,7 +2175,7 @@ void FurnaceGUI::applyUISettings() {
|
|||
}
|
||||
} else {
|
||||
if ((mainFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFont[settings.mainFont],builtinFontLen[settings.mainFont],e->getConfInt("mainFontSize",18)*dpiScale,NULL,fontRange))==NULL) {
|
||||
logE("could not load UI font! falling back to Proggy Clean.\n");
|
||||
logE("could not load UI font! falling back to Proggy Clean.");
|
||||
mainFont=ImGui::GetIO().Fonts->AddFontDefault();
|
||||
}
|
||||
}
|
||||
|
@ -2137,18 +2189,18 @@ void FurnaceGUI::applyUISettings() {
|
|||
fc.GlyphMinAdvanceX=e->getConfInt("iconSize",16)*dpiScale;
|
||||
static const ImWchar fontRangeIcon[]={ICON_MIN_FA,ICON_MAX_FA,0};
|
||||
if ((iconFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(iconFont_compressed_data,iconFont_compressed_size,e->getConfInt("iconSize",16)*dpiScale,&fc,fontRangeIcon))==NULL) {
|
||||
logE("could not load icon font!\n");
|
||||
logE("could not load icon font!");
|
||||
}
|
||||
if (settings.mainFontSize==settings.patFontSize && settings.patFont<5 && builtinFontM[settings.patFont]==builtinFont[settings.mainFont]) {
|
||||
logD("using main font for pat font.\n");
|
||||
logD("using main font for pat font.");
|
||||
patFont=mainFont;
|
||||
} else {
|
||||
if (settings.patFont==6) { // custom font
|
||||
if ((patFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(settings.patFontPath.c_str(),e->getConfInt("patFontSize",18)*dpiScale,NULL,upTo800))==NULL) {
|
||||
logW("could not load pattern font! reverting to default font\n");
|
||||
logW("could not load pattern font! reverting to default font");
|
||||
settings.patFont=0;
|
||||
if ((patFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFontM[settings.patFont],builtinFontMLen[settings.patFont],e->getConfInt("patFontSize",18)*dpiScale,NULL,upTo800))==NULL) {
|
||||
logE("could not load pattern font! falling back to Proggy Clean.\n");
|
||||
logE("could not load pattern font! falling back to Proggy Clean.");
|
||||
patFont=ImGui::GetIO().Fonts->AddFontDefault();
|
||||
}
|
||||
}
|
||||
|
@ -2156,10 +2208,10 @@ void FurnaceGUI::applyUISettings() {
|
|||
if ((patFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_PAT_FONT_PATH_1,e->getConfInt("patFontSize",18)*dpiScale,NULL,upTo800))==NULL) {
|
||||
if ((patFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_PAT_FONT_PATH_2,e->getConfInt("patFontSize",18)*dpiScale,NULL,upTo800))==NULL) {
|
||||
if ((patFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_PAT_FONT_PATH_3,e->getConfInt("patFontSize",18)*dpiScale,NULL,upTo800))==NULL) {
|
||||
logW("could not load pattern font! reverting to default font\n");
|
||||
logW("could not load pattern font! reverting to default font");
|
||||
settings.patFont=0;
|
||||
if ((patFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFontM[settings.patFont],builtinFontMLen[settings.patFont],e->getConfInt("patFontSize",18)*dpiScale,NULL,upTo800))==NULL) {
|
||||
logE("could not load pattern font! falling back to Proggy Clean.\n");
|
||||
logE("could not load pattern font! falling back to Proggy Clean.");
|
||||
patFont=ImGui::GetIO().Fonts->AddFontDefault();
|
||||
}
|
||||
}
|
||||
|
@ -2167,17 +2219,18 @@ void FurnaceGUI::applyUISettings() {
|
|||
}
|
||||
} else {
|
||||
if ((patFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFontM[settings.patFont],builtinFontMLen[settings.patFont],e->getConfInt("patFontSize",18)*dpiScale,NULL,upTo800))==NULL) {
|
||||
logE("could not load pattern font!\n");
|
||||
logE("could not load pattern font!");
|
||||
patFont=ImGui::GetIO().Fonts->AddFontDefault();
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((bigFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(font_plexSans_compressed_data,font_plexSans_compressed_size,40*dpiScale))==NULL) {
|
||||
logE("could not load big UI font!\n");
|
||||
logE("could not load big UI font!");
|
||||
}
|
||||
|
||||
mainFont->FallbackChar='?';
|
||||
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 (updateFonts) {
|
||||
if (fileDialog!=NULL) delete fileDialog;
|
||||
fileDialog=new FurnaceGUIFileDialog(settings.sysFileDialog);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue