Merge branch 'tildearrow:master' into master

This commit is contained in:
BlastBrothers 2022-04-11 10:15:47 -04:00 committed by GitHub
commit 72632b9b72
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
105 changed files with 3745 additions and 3039 deletions

View file

@ -18,17 +18,16 @@ jobs:
strategy: strategy:
matrix: matrix:
config: config:
- { name: 'Windows MSVC', os: windows-latest, compiler: msvc, shell: bash } - { name: 'Windows MSVC x86', os: windows-latest, compiler: msvc, arch: x86 }
- { name: 'Windows MinGW', os: windows-latest, compiler: mingw, shell: 'msys2 {0}' } - { name: 'Windows MSVC x86_64', os: windows-latest, compiler: msvc, arch: x86_64 }
- { name: 'macOS', os: macos-latest, shell: bash } - { name: 'Windows MinGW x86', os: ubuntu-20.04, compiler: mingw, arch: x86 }
- { name: 'Ubuntu', os: ubuntu-18.04, shell: bash } - { 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 fail-fast: false
name: ${{ matrix.config.name }} name: ${{ matrix.config.name }}
runs-on: ${{ matrix.config.os }} runs-on: ${{ matrix.config.os }}
defaults:
run:
shell: ${{ matrix.config.shell }}
steps: steps:
- name: Checkout - name: Checkout
@ -36,53 +35,123 @@ jobs:
with: with:
submodules: recursive 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] - name: Setup Toolchain [Windows MSVC]
if: ${{ runner.os == 'Windows' && matrix.config.compiler == 'msvc' }} if: ${{ matrix.config.compiler == 'msvc' }}
uses: seanmiddleditch/gha-setup-vsdevenv@v3 uses: seanmiddleditch/gha-setup-vsdevenv@v3
with:
arch: ${{ steps.windows-identify.outputs.vswhere-target }}
- name: Setup Toolchain [Windows MinGW] - name: Setup Toolchain [Windows MinGW]
if: ${{ runner.os == 'Windows' && matrix.config.compiler == 'mingw' }} if: ${{ 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' }}
run: | run: |
export HOMEBREW_NO_INSTALL_CLEANUP=1 sudo apt update
brew update sudo apt install \
brew install \ mingw-w64 \
pkg-config \ mingw-w64-tools
sdl2 \
libsndfile \
zlib \
jack
- name: Install Dependencies [Ubuntu] - name: Install Dependencies [Ubuntu]
if: ${{ runner.os == 'Linux' }} if: ${{ runner.os == 'Linux' && matrix.config.compiler != 'mingw' }}
run: | run: |
sudo apt update sudo apt update
sudo apt install \ sudo apt install \
libsdl2-dev \ libsdl2-dev \
libfmt-dev \
librtmidi-dev \
libsndfile1-dev \ libsndfile1-dev \
zlib1g-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: | run: |
export USE_WAE=ON export USE_WAE=ON
export CMAKE_EXTRA_ARGS=() export CMAKE_EXTRA_ARGS=()
if [ '${{ runner.os }}' == 'Windows' ]; then if [ '${{ matrix.config.compiler }}' == 'msvc' ]; then
if [ '${{ matrix.config.compiler }}' == 'mingw' ]; then CMAKE_EXTRA_ARGS+=('-DCMAKE_GENERATOR_PLATFORM=${{ steps.windows-identify.outputs.msvc-target }}')
CMAKE_EXTRA_ARGS+=('-G' 'MSYS Makefiles') elif [ '${{ matrix.config.compiler }}' == 'mingw' ]; then
elif [ '${{ matrix.config.compiler }}' == 'msvc' ]; then CMAKE_EXTRA_ARGS+=('-DCMAKE_TOOLCHAIN_FILE=scripts/Cross-MinGW-${{ steps.windows-identify.outputs.mingw-target }}.cmake')
# We don't want all the MSVC warnings to cause errors yet else
export USE_WAE=OFF # 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
fi fi
@ -93,16 +162,122 @@ jobs:
-DWARNINGS_ARE_ERRORS=${USE_WAE} \ -DWARNINGS_ARE_ERRORS=${USE_WAE} \
"${CMAKE_EXTRA_ARGS[@]}" "${CMAKE_EXTRA_ARGS[@]}"
- name: Build - name: Build (System Libraries)
if: ${{ runner.os == 'Linux' && matrix.config.compiler != 'mingw' }}
run: | run: |
export VERBOSE=1
cmake \ cmake \
--build ${PWD}/build \ --build ${PWD}/build \
--config ${{ env.BUILD_TYPE }} \ --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: | run: |
cmake \ cmake \
--install ${PWD}/build \ --install ${PWD}/build \
--config ${{ env.BUILD_TYPE }} --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 }}

View file

@ -65,7 +65,7 @@ list(APPEND DEPENDENCIES_LIBRARIES ${CMAKE_THREAD_LIBS_INIT})
if (SYSTEM_FMT) if (SYSTEM_FMT)
if (PKG_CONFIG_FOUND) if (PKG_CONFIG_FOUND)
pkg_check_modules(FMT fmt) pkg_check_modules(FMT fmt>=7.1.0)
if (FMT_FOUND) if (FMT_FOUND)
list(APPEND DEPENDENCIES_INCLUDE_DIRS ${FMT_INCLUDE_DIRS}) list(APPEND DEPENDENCIES_INCLUDE_DIRS ${FMT_INCLUDE_DIRS})
list(APPEND DEPENDENCIES_COMPILE_OPTIONS ${FMT_CFLAGS_OTHER}) list(APPEND DEPENDENCIES_COMPILE_OPTIONS ${FMT_CFLAGS_OTHER})
@ -167,11 +167,20 @@ if (SYSTEM_SDL2)
endif() endif()
message(STATUS "Using system-installed SDL2") message(STATUS "Using system-installed SDL2")
else() else()
set(SDL_SHARED OFF) set(SDL_SHARED OFF CACHE BOOL "Force no dynamically-linked SDL" FORCE)
set(SDL_STATIC ON) 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) add_subdirectory(extern/SDL EXCLUDE_FROM_ALL)
list(APPEND DEPENDENCIES_INCLUDE_DIRS extern/SDL/include) list(APPEND DEPENDENCIES_INCLUDE_DIRS extern/SDL/include)
list(APPEND DEPENDENCIES_LIBRARIES SDL2-static) 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") message(STATUS "Using vendored SDL2")
endif() endif()
@ -385,6 +394,7 @@ src/gui/doAction.cpp
src/gui/editing.cpp src/gui/editing.cpp
src/gui/editControls.cpp src/gui/editControls.cpp
src/gui/insEdit.cpp src/gui/insEdit.cpp
src/gui/log.cpp
src/gui/mixer.cpp src/gui/mixer.cpp
src/gui/midiMap.cpp src/gui/midiMap.cpp
src/gui/newSong.cpp src/gui/newSong.cpp
@ -452,9 +462,13 @@ if (NOT MSVC)
list(APPEND WARNING_FLAGS -Werror) list(APPEND WARNING_FLAGS -Werror)
endif() endif()
else() else()
# /wd4100 == -Wno-unused-parameter add_compile_options("/utf-8")
add_compile_options("/source-charset:utf-8") set(WARNING_FLAGS /W2 /D_CRT_SECURE_NO_WARNINGS)
set(WARNING_FLAGS /W4 /wd4100 /D_CRT_SECURE_NO_WARNINGS) list(APPEND WARNING_FLAGS
/wd4244 # implicit type conversions
/wd4305 # truncations
/wd4309 # truncations of constant values
)
if (WARNINGS_ARE_ERRORS) if (WARNINGS_ARE_ERRORS)
list(APPEND WARNING_FLAGS /WX) list(APPEND WARNING_FLAGS /WX)
endif() endif()

Binary file not shown.

View file

@ -57,7 +57,7 @@
#ifndef PFD_HAS_IFILEDIALOG #ifndef PFD_HAS_IFILEDIALOG
# define PFD_HAS_IFILEDIALOG 1 # define PFD_HAS_IFILEDIALOG 1
# if (defined __MINGW64__ || defined __MINGW32__) && defined __GXX_ABI_VERSION # if (defined __MINGW64__ || defined __MINGW32__) && defined __GXX_ABI_VERSION
# if __GXX_ABI_VERSION <= 1013 # if __GXX_ABI_VERSION <= 1014
# undef PFD_HAS_IFILEDIALOG # undef PFD_HAS_IFILEDIALOG
# define PFD_HAS_IFILEDIALOG 0 # define PFD_HAS_IFILEDIALOG 0
# endif # endif
@ -1331,6 +1331,14 @@ inline std::string internal::file_dialog::select_folder_vista(IFileDialog *ifd,
// notify implementation // 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, inline notify::notify(std::string const &title,
std::string const &message, std::string const &message,
icon _icon /* = icon::info */) icon _icon /* = icon::info */)
@ -1383,14 +1391,8 @@ inline notify::notify(std::string const &title,
/* case icon::info: */ default: nid->dwInfoFlags = NIIF_INFO; break; /* 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); 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; nid->uTimeout = 5000;

View file

@ -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. 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. 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 # effects

View file

@ -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 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 # technical specifications
the YM2413 is equipped with the following features: the YM2413 is equipped with the following features:

View file

@ -1,6 +1,9 @@
# Philips SAA1099 # 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 # effects

View file

@ -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. 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. 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. 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). Furnace supports this routine for PCM playback, but it consumes a lot of CPU time in real hardware (even if conjunction with VRC6's integrated IRQ timer).
@ -13,4 +15,4 @@ Furnace supports this routine for PCM playback, but it consumes a lot of CPU tim
these effects only are effective in the pulse channels. these effects only are effective in the pulse channels.
- `12xx`: set duty cycle (0 to 7). - `12xx`: set duty cycle (0 to 7).
- `17xx`: toggle PCM mode. - `17xx`: toggle PCM mode.

View file

@ -29,6 +29,7 @@ furthermore, an `or reserved` indicates this field is always present, but is res
the format versions are: the format versions are:
- 80: Furnace dev80
- 79: Furnace dev79 - 79: Furnace dev79
- 78: Furnace dev78 - 78: Furnace dev78
- 77: Furnace dev77 - 77: Furnace dev77
@ -119,12 +120,17 @@ size | description
| - 60 is NTSC | - 60 is NTSC
| - 50 is PAL | - 50 is PAL
2 | pattern length 2 | pattern length
| - the limit is 256.
2 | orders length 2 | orders length
| - the limit is 256 (>=80) or 127 (<80).
1 | highlight A 1 | highlight A
1 | highlight B 1 | highlight B
2 | instrument count 2 | instrument count
| - the limit is 256.
2 | wavetable count 2 | wavetable count
| - the limit is 256.
2 | sample count 2 | sample count
| - the limit is 256.
4 | pattern count 4 | pattern count
32 | list of sound chips 32 | list of sound chips
| - possible soundchips: | - possible soundchips:
@ -230,6 +236,7 @@ size | description
| - a table of bytes | - a table of bytes
| - size=channels*ordLen | - size=channels*ordLen
| - read orders then channels | - read orders then channels
| - the maximum value of a cell is FF (>=80) or 7F (<80).
??? | effect columns ??? | effect columns
| - size=channels | - size=channels
1?? | channel hide status 1?? | channel hide status

View file

@ -0,0 +1,4 @@
set(CMAKE_SYSTEM_NAME Windows)
set(CMAKE_SYSTEM_PROCESSOR i686)
include(${CMAKE_CURRENT_LIST_DIR}/Cross-MinGW.cmake)

View 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
View 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)

View file

@ -44,18 +44,18 @@ bool TAMidiInRtMidi::gather() {
std::vector<String> TAMidiInRtMidi::listDevices() { std::vector<String> TAMidiInRtMidi::listDevices() {
std::vector<String> ret; std::vector<String> ret;
logD("listing devices.\n"); logD("listing devices.");
if (port==NULL) return ret; if (port==NULL) return ret;
try { try {
unsigned int count=port->getPortCount(); unsigned int count=port->getPortCount();
logD("got port count.\n"); logD("got port count.");
for (unsigned int i=0; i<count; i++) { for (unsigned int i=0; i<count; i++) {
String name=port->getPortName(i); String name=port->getPortName(i);
if (name!="") ret.push_back(name); if (name!="") ret.push_back(name);
} }
} catch (RtMidiError& e) { } catch (RtMidiError& e) {
logW("could not get MIDI inputs! %s\n",e.what()); logW("could not get MIDI inputs! %s",e.what());
} }
return ret; return ret;
} }
@ -78,10 +78,10 @@ bool TAMidiInRtMidi::openDevice(String name) {
} }
} }
isOpen=portOpen; isOpen=portOpen;
if (!portOpen) logW("could not find MIDI in device...\n"); if (!portOpen) logW("could not find MIDI in device...");
return portOpen; return portOpen;
} catch (RtMidiError& e) { } 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 false;
} }
return true; return true;
@ -93,7 +93,7 @@ bool TAMidiInRtMidi::closeDevice() {
try { try {
port->closePort(); port->closePort();
} catch (RtMidiError& e) { } 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 isOpen=false; // still
return false; return false;
} }
@ -106,7 +106,7 @@ bool TAMidiInRtMidi::init() {
try { try {
port=new RtMidiIn; port=new RtMidiIn;
} catch (RtMidiError& e) { } 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 false;
} }
return true; return true;
@ -176,10 +176,10 @@ bool TAMidiOutRtMidi::openDevice(String name) {
} }
} }
isOpen=portOpen; isOpen=portOpen;
if (!portOpen) logW("could not find MIDI out device...\n"); if (!portOpen) logW("could not find MIDI out device...");
return portOpen; return portOpen;
} catch (RtMidiError& e) { } 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 false;
} }
return true; return true;
@ -191,7 +191,7 @@ bool TAMidiOutRtMidi::closeDevice() {
try { try {
port->closePort(); port->closePort();
} catch (RtMidiError& e) { } 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 isOpen=false; // still
return false; return false;
} }
@ -210,7 +210,7 @@ std::vector<String> TAMidiOutRtMidi::listDevices() {
if (name!="") ret.push_back(name); if (name!="") ret.push_back(name);
} }
} catch (RtMidiError& e) { } catch (RtMidiError& e) {
logW("could not get MIDI outputs! %s\n",e.what()); logW("could not get MIDI outputs! %s",e.what());
} }
return ret; return ret;
} }
@ -220,7 +220,7 @@ bool TAMidiOutRtMidi::init() {
try { try {
port=new RtMidiOut; port=new RtMidiOut;
} catch (RtMidiError& e) { } 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 false;
} }
return true; return true;

View file

@ -75,7 +75,7 @@ std::vector<String> TAAudioSDL::listAudioDevices() {
std::vector<String> ret; std::vector<String> ret;
if (!audioSysStarted) { if (!audioSysStarted) {
if (SDL_Init(SDL_INIT_AUDIO)<0) { 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 { } else {
audioSysStarted=true; audioSysStarted=true;
} }
@ -96,12 +96,12 @@ std::vector<String> TAAudioSDL::listAudioDevices() {
bool TAAudioSDL::init(TAAudioDesc& request, TAAudioDesc& response) { bool TAAudioSDL::init(TAAudioDesc& request, TAAudioDesc& response) {
if (initialized) { if (initialized) {
logE("audio already initialized\n"); logE("audio already initialized");
return false; return false;
} }
if (!audioSysStarted) { if (!audioSysStarted) {
if (SDL_Init(SDL_INIT_AUDIO)<0) { if (SDL_Init(SDL_INIT_AUDIO)<0) {
logE("could not initialize SDL\n"); logE("could not initialize SDL");
return false; return false;
} }
audioSysStarted=true; 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); ai=SDL_OpenAudioDevice(request.deviceName.empty()?NULL:request.deviceName.c_str(),0,&ac,&ar,SDL_AUDIO_ALLOW_FREQUENCY_CHANGE);
if (ai==0) { if (ai==0) {
logE("could not open audio device: %s\n",SDL_GetError()); logE("could not open audio device: %s",SDL_GetError());
return false; return false;
} }

View file

@ -32,13 +32,13 @@ bool DivEngine::saveConf() {
configFile=configPath+String(CONFIG_FILE); configFile=configPath+String(CONFIG_FILE);
FILE* f=ps_fopen(configFile.c_str(),"wb"); FILE* f=ps_fopen(configFile.c_str(),"wb");
if (f==NULL) { if (f==NULL) {
logW("could not write config file! %s\n",strerror(errno)); logW("could not write config file! %s",strerror(errno));
return false; return false;
} }
for (auto& i: conf) { for (auto& i: conf) {
String toWrite=fmt::sprintf("%s=%s\n",i.first,i.second); String toWrite=fmt::sprintf("%s=%s\n",i.first,i.second);
if (fwrite(toWrite.c_str(),1,toWrite.size(),f)!=toWrite.size()) { 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); fclose(f);
return false; return false;
} }
@ -52,10 +52,10 @@ bool DivEngine::loadConf() {
configFile=configPath+String(CONFIG_FILE); configFile=configPath+String(CONFIG_FILE);
FILE* f=ps_fopen(configFile.c_str(),"rb"); FILE* f=ps_fopen(configFile.c_str(),"rb");
if (f==NULL) { if (f==NULL) {
logI("creating default config.\n"); logI("creating default config.");
return saveConf(); return saveConf();
} }
logI("loading config.\n"); logI("loading config.");
while (!feof(f)) { while (!feof(f)) {
String key=""; String key="";
String value=""; String value="";

View file

@ -56,6 +56,7 @@ enum DivDispatchCmds {
DIV_CMD_SAMPLE_BANK, DIV_CMD_SAMPLE_BANK,
DIV_CMD_SAMPLE_POS, DIV_CMD_SAMPLE_POS,
DIV_CMD_FM_HARD_RESET,
DIV_CMD_FM_LFO, DIV_CMD_FM_LFO,
DIV_CMD_FM_LFO_WAVE, DIV_CMD_FM_LFO_WAVE,
DIV_CMD_FM_TL, DIV_CMD_FM_TL,
@ -319,6 +320,18 @@ class DivDispatch {
*/ */
virtual int getPortaFloor(int ch); 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. * get a description of a dispatch-specific effect.
* @param effect the effect. * @param effect the effect.

View file

@ -79,6 +79,11 @@ void DivDispatchContainer::flush(size_t count) {
} }
void DivDispatchContainer::fillBuf(size_t runtotal, size_t offset, size_t size) { 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) { if (lowQuality) {
for (size_t i=0; i<runtotal; i++) { for (size_t i=0; i<runtotal; i++) {
temp[0]=bbIn[0][i]; temp[0]=bbIn[0][i];
@ -126,6 +131,9 @@ void DivDispatchContainer::clear() {
temp[1]=0; temp[1]=0;
prevSample[0]=0; prevSample[0]=0;
prevSample[1]=0; prevSample[1]=0;
if (dispatch->getDCOffRequired()) {
dcOffCompensation=true;
}
// run for one cycle to determine DC offset // run for one cycle to determine DC offset
// TODO: SAA1099 doesn't like that // TODO: SAA1099 doesn't like that
/*dispatch->acquire(bbIn[0],bbIn[1],0,1); /*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); bb[0]=blip_new(32768);
if (bb[0]==NULL) { if (bb[0]==NULL) {
logE("not enough memory!\n"); logE("not enough memory!");
return; return;
} }
bb[1]=blip_new(32768); bb[1]=blip_new(32768);
if (bb[1]==NULL) { if (bb[1]==NULL) {
logE("not enough memory!\n"); logE("not enough memory!");
return; return;
} }
@ -304,7 +312,7 @@ void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, do
dispatch=new DivPlatformMMC5; dispatch=new DivPlatformMMC5;
break; break;
default: 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; dispatch=new DivPlatformDummy;
break; break;
} }

View file

@ -17,9 +17,6 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#include "dataErrors.h"
#include "song.h"
#include <functional>
#define _USE_MATH_DEFINES #define _USE_MATH_DEFINES
#include "engine.h" #include "engine.h"
#include "instrument.h" #include "instrument.h"
@ -196,7 +193,7 @@ void DivEngine::runExportThread() {
sf=sf_open(exportPath.c_str(),SFM_WRITE,&si); sf=sf_open(exportPath.c_str(),SFM_WRITE,&si);
if (sf==NULL) { 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; exporting=false;
return; return;
} }
@ -210,7 +207,7 @@ void DivEngine::runExportThread() {
deinitAudioBackend(); deinitAudioBackend();
playSub(false); playSub(false);
logI("rendering to file...\n"); logI("rendering to file...");
while (playing) { while (playing) {
nextBuf(NULL,outBuf,0,2,EXPORT_BUFSIZE); 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])); outBuf[2][1+(i<<1)]=MAX(-1.0f,MIN(1.0f,outBuf[1][i]));
} }
if (totalProcessed>EXPORT_BUFSIZE) { 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) { 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; break;
} }
} }
@ -232,7 +229,7 @@ void DivEngine::runExportThread() {
delete[] outBuf[2]; delete[] outBuf[2];
if (sf_close(sf)!=0) { if (sf_close(sf)!=0) {
logE("could not close audio file!\n"); logE("could not close audio file!");
} }
exporting=false; exporting=false;
@ -242,10 +239,10 @@ void DivEngine::runExportThread() {
disCont[i].setQuality(lowQuality); disCont[i].setQuality(lowQuality);
} }
if (!output->setRun(true)) { if (!output->setRun(true)) {
logE("error while activating audio!\n"); logE("error while activating audio!");
} }
} }
logI("done!\n"); logI("done!");
break; break;
} }
case DIV_EXPORT_MODE_MANY_SYS: { case DIV_EXPORT_MODE_MANY_SYS: {
@ -265,10 +262,10 @@ void DivEngine::runExportThread() {
for (int i=0; i<song.systemLen; i++) { for (int i=0; i<song.systemLen; i++) {
fname[i]=fmt::sprintf("%s_s%02d.wav",exportPath,i+1); 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]); sf[i]=sf_open(fname[i].c_str(),SFM_WRITE,&si[i]);
if (sf[i]==NULL) { 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++) { for (int j=0; j<i; j++) {
sf_close(sf[i]); sf_close(sf[i]);
} }
@ -285,7 +282,7 @@ void DivEngine::runExportThread() {
deinitAudioBackend(); deinitAudioBackend();
playSub(false); playSub(false);
logI("rendering to files...\n"); logI("rendering to files...");
while (playing) { while (playing) {
nextBuf(NULL,outBuf,0,2,EXPORT_BUFSIZE); nextBuf(NULL,outBuf,0,2,EXPORT_BUFSIZE);
@ -299,10 +296,10 @@ void DivEngine::runExportThread() {
} }
} }
if (totalProcessed>EXPORT_BUFSIZE) { 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) { 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; break;
} }
} }
@ -314,7 +311,7 @@ void DivEngine::runExportThread() {
for (int i=0; i<song.systemLen; i++) { for (int i=0; i<song.systemLen; i++) {
if (sf_close(sf[i])!=0) { if (sf_close(sf[i])!=0) {
logE("could not close audio file!\n"); logE("could not close audio file!");
} }
} }
exporting=false; exporting=false;
@ -325,10 +322,10 @@ void DivEngine::runExportThread() {
disCont[i].setQuality(lowQuality); disCont[i].setQuality(lowQuality);
} }
if (!output->setRun(true)) { if (!output->setRun(true)) {
logE("error while activating audio!\n"); logE("error while activating audio!");
} }
} }
logI("done!\n"); logI("done!");
break; break;
} }
case DIV_EXPORT_MODE_MANY_CHAN: { case DIV_EXPORT_MODE_MANY_CHAN: {
@ -341,20 +338,20 @@ void DivEngine::runExportThread() {
outBuf[2]=new float[EXPORT_BUFSIZE*2]; outBuf[2]=new float[EXPORT_BUFSIZE*2];
int loopCount=remainingLoops; int loopCount=remainingLoops;
logI("rendering to files...\n"); logI("rendering to files...");
for (int i=0; i<chans; i++) { for (int i=0; i<chans; i++) {
SNDFILE* sf; SNDFILE* sf;
SF_INFO si; SF_INFO si;
String fname=fmt::sprintf("%s_c%02d.wav",exportPath,i+1); 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.samplerate=got.rate;
si.channels=2; si.channels=2;
si.format=SF_FORMAT_WAV|SF_FORMAT_PCM_16; si.format=SF_FORMAT_WAV|SF_FORMAT_PCM_16;
sf=sf_open(fname.c_str(),SFM_WRITE,&si); sf=sf_open(fname.c_str(),SFM_WRITE,&si);
if (sf==NULL) { 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; break;
} }
@ -377,16 +374,16 @@ void DivEngine::runExportThread() {
outBuf[2][1+(j<<1)]=MAX(-1.0f,MIN(1.0f,outBuf[1][j])); outBuf[2][1+(j<<1)]=MAX(-1.0f,MIN(1.0f,outBuf[1][j]));
} }
if (totalProcessed>EXPORT_BUFSIZE) { 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) { 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; break;
} }
} }
if (sf_close(sf)!=0) { if (sf_close(sf)!=0) {
logE("could not close audio file!\n"); logE("could not close audio file!");
} }
} }
exporting=false; exporting=false;
@ -408,10 +405,10 @@ void DivEngine::runExportThread() {
disCont[i].setQuality(lowQuality); disCont[i].setQuality(lowQuality);
} }
if (!output->setRun(true)) { if (!output->setRun(true)) {
logE("error while activating audio!\n"); logE("error while activating audio!");
} }
} }
logI("done!\n"); logI("done!");
break; break;
} }
} }
@ -482,12 +479,12 @@ void DivEngine::renderSamples() {
memPos=(memPos+0xfffff)&0xf00000; memPos=(memPos+0xfffff)&0xf00000;
} }
if (memPos>=16777216) { 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; break;
} }
if (memPos+paddedLen>=16777216) { if (memPos+paddedLen>=16777216) {
memcpy(adpcmAMem+memPos,s->dataA,16777216-memPos); 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 { } else {
memcpy(adpcmAMem+memPos,s->dataA,paddedLen); memcpy(adpcmAMem+memPos,s->dataA,paddedLen);
} }
@ -507,12 +504,12 @@ void DivEngine::renderSamples() {
memPos=(memPos+0xfffff)&0xf00000; memPos=(memPos+0xfffff)&0xf00000;
} }
if (memPos>=16777216) { 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; break;
} }
if (memPos+paddedLen>=16777216) { if (memPos+paddedLen>=16777216) {
memcpy(adpcmBMem+memPos,s->dataB,16777216-memPos); 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 { } else {
memcpy(adpcmBMem+memPos,s->dataB,paddedLen); memcpy(adpcmBMem+memPos,s->dataB,paddedLen);
} }
@ -536,14 +533,14 @@ void DivEngine::renderSamples() {
memPos=(memPos+0xffff)&0xff0000; memPos=(memPos+0xffff)&0xff0000;
} }
if (memPos>=16777216) { 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; break;
} }
if (memPos+length>=16777216) { if (memPos+length>=16777216) {
for (unsigned int i=0; i<16777216-(memPos+length); i++) { for (unsigned int i=0; i<16777216-(memPos+length); i++) {
qsoundMem[(memPos+i)^0x8000]=s->data8[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 { } else {
for (int i=0; i<length; i++) { for (int i=0; i<length; i++) {
qsoundMem[(memPos+i)^0x8000]=s->data8[i]; qsoundMem[(memPos+i)^0x8000]=s->data8[i];
@ -570,12 +567,12 @@ void DivEngine::renderSamples() {
memPos=(memPos+0x1ffff)&0xfe0000; memPos=(memPos+0x1ffff)&0xfe0000;
} }
if (memPos>=1048576) { 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; break;
} }
if (memPos+paddedLen>=1048576) { if (memPos+paddedLen>=1048576) {
memcpy(x1_010Mem+memPos,s->data8,1048576-memPos); 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 { } else {
memcpy(x1_010Mem+memPos,s->data8,paddedLen); 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) { 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); for (int i=0; i<song.systemLen; i++) disCont[i].dispatch->setSkipRegisterWrites(false);
reset(); reset();
if (preserveDrift && curOrder==0) return; if (preserveDrift && curOrder==0) return;
@ -825,6 +823,8 @@ void DivEngine::playSub(bool preserveDrift, int goalRow) {
} }
skipping=false; skipping=false;
cmdStream.clear(); 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++) { for (int i=0; i<DIV_MAX_CHANS; i++) {
keyHit[i]=false; 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; BUSY_END;
} }
@ -918,6 +923,14 @@ void DivEngine::stop() {
for (int i=0; i<song.systemLen; i++) { for (int i=0; i<song.systemLen; i++) {
disCont[i].dispatch->notifyPlaybackStop(); 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; BUSY_END;
} }
@ -1281,7 +1294,7 @@ void DivEngine::delInstrument(int index) {
song.ins.erase(song.ins.begin()+index); song.ins.erase(song.ins.begin()+index);
song.insLen=song.ins.size(); song.insLen=song.ins.size();
for (int i=0; i<chans; i++) { 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; if (song.pat[i].data[j]==NULL) continue;
for (int k=0; k<song.patLen; k++) { for (int k=0; k<song.patLen; k++) {
if (song.pat[i].data[j]->data[k][2]>index) { 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]; buf=new unsigned char[len];
if (fread(buf,1,len,f)!=(size_t)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; delete[] buf;
return false; return false;
} }
@ -1373,22 +1386,22 @@ bool DivEngine::addWaveFromFile(const char* path) {
wave->max=(unsigned char)reader.readC(); wave->max=(unsigned char)reader.readC();
if (wave->max==255) { // new wavetable format if (wave->max==255) { // new wavetable format
unsigned char waveVersion=reader.readC(); unsigned char waveVersion=reader.readC();
logI("reading modern .dmw...\n"); logI("reading modern .dmw...");
logD("wave version %d\n",waveVersion); logD("wave version %d",waveVersion);
wave->max=reader.readC(); wave->max=reader.readC();
for (int i=0; i<len; i++) { for (int i=0; i<len; i++) {
wave->data[i]=reader.readI(); wave->data[i]=reader.readI();
} }
} else if (reader.size()==(size_t)(len+5)) { } else if (reader.size()==(size_t)(len+5)) {
// read as .dmw // read as .dmw
logI("reading .dmw...\n"); logI("reading .dmw...");
if (len>256) len=256; if (len>256) len=256;
for (int i=0; i<len; i++) { for (int i=0; i<len; i++) {
wave->data[i]=(unsigned char)reader.readC(); wave->data[i]=(unsigned char)reader.readC();
} }
} else { } else {
// read as binary // read as binary
logI("reading binary...\n"); logI("reading binary...");
len=reader.size(); len=reader.size();
if (len>256) len=256; if (len>256) len=256;
reader.seek(0,SEEK_SET); reader.seek(0,SEEK_SET);
@ -1401,7 +1414,7 @@ bool DivEngine::addWaveFromFile(const char* path) {
} catch (EndOfFileException& e) { } catch (EndOfFileException& e) {
// read as binary // read as binary
len=reader.size(); len=reader.size();
logI("reading binary for being too small...\n"); logI("reading binary for being too small...");
if (len>256) len=256; if (len>256) len=256;
reader.seek(0,SEEK_SET); reader.seek(0,SEEK_SET);
for (int i=0; i<len; i++) { 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]; short* buf=new short[si.channels*si.frames];
if (sf_readf_short(f,buf,si.frames)!=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; DivSample* sample=new DivSample;
int sampleCount=(int)song.sample.size(); int sampleCount=(int)song.sample.size();
@ -1556,7 +1569,7 @@ void DivEngine::delSample(int index) {
void DivEngine::addOrder(bool duplicate, bool where) { void DivEngine::addOrder(bool duplicate, bool where) {
unsigned char order[DIV_MAX_CHANS]; unsigned char order[DIV_MAX_CHANS];
if (song.ordersLen>=0x7e) return; if (song.ordersLen>=0xff) return;
BUSY_BEGIN_SOFT; BUSY_BEGIN_SOFT;
if (duplicate) { if (duplicate) {
for (int i=0; i<DIV_MAX_CHANS; i++) { 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++) { for (int j=0; j<song.ordersLen; j++) {
used[song.orders.ord[i][j]]=true; used[song.orders.ord[i][j]]=true;
} }
order[i]=0x7e; order[i]=0xff;
for (int j=0; j<256; j++) { for (int j=0; j<256; j++) {
if (!used[j]) { if (!used[j]) {
order[i]=j; order[i]=j;
@ -1605,23 +1618,23 @@ void DivEngine::addOrder(bool duplicate, bool where) {
void DivEngine::deepCloneOrder(bool where) { void DivEngine::deepCloneOrder(bool where) {
unsigned char order[DIV_MAX_CHANS]; unsigned char order[DIV_MAX_CHANS];
if (song.ordersLen>=0x7e) return; if (song.ordersLen>=0xff) return;
warnings=""; warnings="";
BUSY_BEGIN_SOFT; BUSY_BEGIN_SOFT;
for (int i=0; i<chans; i++) { for (int i=0; i<chans; i++) {
bool didNotFind=true; bool didNotFind=true;
logD("channel %d\n",i); logD("channel %d",i);
order[i]=song.orders.ord[i][curOrder]; order[i]=song.orders.ord[i][curOrder];
// find free slot // find free slot
for (int j=0; j<128; j++) { for (int j=0; j<256; j++) {
logD("finding free slot in %d...\n",j); logD("finding free slot in %d...",j);
if (song.pat[i].data[j]==NULL) { if (song.pat[i].data[j]==NULL) {
int origOrd=order[i]; int origOrd=order[i];
order[i]=j; order[i]=j;
DivPattern* oldPat=song.pat[i].getPattern(origOrd,false); DivPattern* oldPat=song.pat[i].getPattern(origOrd,false);
DivPattern* pat=song.pat[i].getPattern(j,true); DivPattern* pat=song.pat[i].getPattern(j,true);
memcpy(pat->data,oldPat->data,256*32*sizeof(short)); memcpy(pat->data,oldPat->data,256*32*sizeof(short));
logD("found at %d\n",j); logD("found at %d",j);
didNotFind=false; didNotFind=false;
break; break;
} }
@ -1715,7 +1728,7 @@ void DivEngine::moveOrderDown() {
void DivEngine::exchangeIns(int one, int two) { void DivEngine::exchangeIns(int one, int two) {
for (int i=0; i<chans; i++) { 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; if (song.pat[i].data[j]==NULL) continue;
for (int k=0; k<song.patLen; k++) { for (int k=0; k<song.patLen; k++) {
if (song.pat[i].data[j]->data[k][2]==one) { if (song.pat[i].data[j]->data[k][2]==one) {
@ -1940,7 +1953,7 @@ bool DivEngine::switchMaster() {
disCont[i].setQuality(lowQuality); disCont[i].setQuality(lowQuality);
} }
if (!output->setRun(true)) { if (!output->setRun(true)) {
logE("error while activating audio!\n"); logE("error while activating audio!");
return false; return false;
} }
} else { } else {
@ -2058,9 +2071,9 @@ void DivEngine::quitDispatch() {
#define CHECK_CONFIG_DIR_MAC() \ #define CHECK_CONFIG_DIR_MAC() \
configPath+="/Library/Application Support/Furnace"; \ configPath+="/Library/Application Support/Furnace"; \
if (stat(configPath.c_str(),&st)<0) { \ if (stat(configPath.c_str(),&st)<0) { \
logI("creating config dir...\n"); \ logI("creating config dir..."); \
if (mkdir(configPath.c_str(),0755)<0) { \ 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="."; \ configPath="."; \
} \ } \
} }
@ -2068,18 +2081,18 @@ void DivEngine::quitDispatch() {
#define CHECK_CONFIG_DIR() \ #define CHECK_CONFIG_DIR() \
configPath+="/.config"; \ configPath+="/.config"; \
if (stat(configPath.c_str(),&st)<0) { \ 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) { \ 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="."; \ configPath="."; \
} \ } \
} \ } \
if (configPath!=".") { \ if (configPath!=".") { \
configPath+="/furnace"; \ configPath+="/furnace"; \
if (stat(configPath.c_str(),&st)<0) { \ if (stat(configPath.c_str(),&st)<0) { \
logI("creating config dir...\n"); \ logI("creating config dir..."); \
if (mkdir(configPath.c_str(),0755)<0) { \ 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="."; \ configPath="."; \
} \ } \
} \ } \
@ -2101,7 +2114,7 @@ bool DivEngine::initAudioBackend() {
switch (audioEngine) { switch (audioEngine) {
case DIV_AUDIO_JACK: case DIV_AUDIO_JACK:
#ifndef HAVE_JACK #ifndef HAVE_JACK
logE("Furnace was not compiled with JACK support!\n"); logE("Furnace was not compiled with JACK support!");
setConf("audioEngine","SDL"); setConf("audioEngine","SDL");
saveConf(); saveConf();
output=new TAAudioSDL; output=new TAAudioSDL;
@ -2116,7 +2129,7 @@ bool DivEngine::initAudioBackend() {
output=new TAAudio; output=new TAAudio;
break; break;
default: default:
logE("invalid audio engine!\n"); logE("invalid audio engine!");
return false; return false;
} }
@ -2134,7 +2147,7 @@ bool DivEngine::initAudioBackend() {
output->setCallback(process,this); output->setCallback(process,this);
if (!output->init(want,got)) { if (!output->init(want,got)) {
logE("error while initializing audio!\n"); logE("error while initializing audio!");
delete output; delete output;
output=NULL; output=NULL;
audioEngine=DIV_AUDIO_NULL; audioEngine=DIV_AUDIO_NULL;
@ -2145,15 +2158,15 @@ bool DivEngine::initAudioBackend() {
midiIns=output->midiIn->listDevices(); midiIns=output->midiIn->listDevices();
midiOuts=output->midiOut->listDevices(); midiOuts=output->midiOut->listDevices();
} else { } else {
logW("error while initializing MIDI!\n"); logW("error while initializing MIDI!");
} }
if (output->midiIn) { if (output->midiIn) {
String inName=getConfString("midiInDevice",""); String inName=getConfString("midiInDevice","");
if (!inName.empty()) { if (!inName.empty()) {
// try opening device // try opening device
logI("opening MIDI input.\n"); logI("opening MIDI input.");
if (!output->midiIn->openDevice(inName)) { 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",""); String outName=getConfString("midiOutDevice","");
if (!outName.empty()) { if (!outName.empty()) {
// try opening device // try opening device
logI("opening MIDI output.\n"); logI("opening MIDI output.");
if (!output->midiOut->openDevice(outName)) { 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!=NULL) {
if (output->midiIn) { if (output->midiIn) {
if (output->midiIn->isDeviceOpen()) { if (output->midiIn->isDeviceOpen()) {
logI("closing MIDI input.\n"); logI("closing MIDI input.");
output->midiIn->closeDevice(); output->midiIn->closeDevice();
} }
} }
if (output->midiOut) { if (output->midiOut) {
if (output->midiOut->isDeviceOpen()) { if (output->midiOut->isDeviceOpen()) {
logI("closing MIDI output.\n"); logI("closing MIDI output.");
output->midiOut->closeDevice(); output->midiOut->closeDevice();
} }
} }
@ -2209,7 +2222,7 @@ bool DivEngine::init() {
int uid=getuid(); int uid=getuid();
struct passwd* entry=getpwuid(uid); struct passwd* entry=getpwuid(uid);
if (entry==NULL) { if (entry==NULL) {
logW("unable to determine config directory! (%s)\n",strerror(errno)); logW("unable to determine config directory! (%s)",strerror(errno));
configPath="."; configPath=".";
} else { } else {
configPath=entry->pw_dir; configPath=entry->pw_dir;
@ -2228,21 +2241,21 @@ bool DivEngine::init() {
#endif #endif
} }
#endif #endif
logD("config path: %s\n",configPath.c_str()); logD("config path: %s",configPath.c_str());
loadConf(); loadConf();
// init the rest of engine // init the rest of engine
bool haveAudio=false; bool haveAudio=false;
if (!initAudioBackend()) { if (!initAudioBackend()) {
logE("no audio output available!\n"); logE("no audio output available!");
} else { } else {
haveAudio=true; haveAudio=true;
} }
samp_bb=blip_new(32768); samp_bb=blip_new(32768);
if (samp_bb==NULL) { if (samp_bb==NULL) {
logE("not enough memory!\n"); logE("not enough memory!");
return false; return false;
} }
@ -2277,7 +2290,7 @@ bool DivEngine::init() {
return false; return false;
} else { } else {
if (!output->setRun(true)) { if (!output->setRun(true)) {
logE("error while activating!\n"); logE("error while activating!");
return false; return false;
} }
} }
@ -2287,7 +2300,7 @@ bool DivEngine::init() {
bool DivEngine::quit() { bool DivEngine::quit() {
deinitAudioBackend(); deinitAudioBackend();
quitDispatch(); quitDispatch();
logI("saving config.\n"); logI("saving config.");
saveConf(); saveConf();
active=false; active=false;
delete[] oscBuf[0]; delete[] oscBuf[0];

View file

@ -42,8 +42,8 @@
#define BUSY_BEGIN_SOFT softLocked=true; isBusy.lock(); #define BUSY_BEGIN_SOFT softLocked=true; isBusy.lock();
#define BUSY_END isBusy.unlock(); softLocked=false; #define BUSY_END isBusy.unlock(); softLocked=false;
#define DIV_VERSION "dev79" #define DIV_VERSION "dev81"
#define DIV_ENGINE_VERSION 79 #define DIV_ENGINE_VERSION 81
// for imports // for imports
#define DIV_VERSION_MOD 0xff01 #define DIV_VERSION_MOD 0xff01
@ -86,7 +86,8 @@ struct DivChannelState {
bool doNote, legato, portaStop, keyOn, keyOff, nowYouCanStop, stopOnOff; bool doNote, legato, portaStop, keyOn, keyOff, nowYouCanStop, stopOnOff;
bool arpYield, delayLocked, inPorta, scheduledSlideReset, shorthandPorta, noteOnInhibit, resetArp; bool arpYield, delayLocked, inPorta, scheduledSlideReset, shorthandPorta, noteOnInhibit, resetArp;
int midiNote, curMidiNote; int midiNote, curMidiNote, midiPitch;
bool midiAftertouch;
DivChannelState(): DivChannelState():
note(-1), note(-1),
@ -130,7 +131,9 @@ struct DivChannelState {
noteOnInhibit(false), noteOnInhibit(false),
resetArp(false), resetArp(false),
midiNote(-1), midiNote(-1),
curMidiNote(-1) {} curMidiNote(-1),
midiPitch(-1),
midiAftertouch(false) {}
}; };
struct DivNoteEvent { struct DivNoteEvent {
@ -151,7 +154,7 @@ struct DivDispatchContainer {
int temp[2], prevSample[2]; int temp[2], prevSample[2];
short* bbIn[2]; short* bbIn[2];
short* bbOut[2]; short* bbOut[2];
bool lowQuality; bool lowQuality, dcOffCompensation;
void setRates(double gotRate); void setRates(double gotRate);
void setQuality(bool lowQual); void setQuality(bool lowQual);
@ -169,7 +172,8 @@ struct DivDispatchContainer {
prevSample{0,0}, prevSample{0,0},
bbIn{NULL,NULL}, bbIn{NULL,NULL},
bbOut{NULL,NULL}, bbOut{NULL,NULL},
lowQuality(false) {} lowQuality(false),
dcOffCompensation(false) {}
}; };
class DivEngine { class DivEngine {
@ -295,6 +299,7 @@ class DivEngine {
bool keyHit[DIV_MAX_CHANS]; bool keyHit[DIV_MAX_CHANS];
float* oscBuf[2]; float* oscBuf[2];
float oscSize; float oscSize;
int oscReadPos, oscWritePos;
void runExportThread(); void runExportThread();
void nextBuf(float** in, float** out, int inChans, int outChans, unsigned int size); void nextBuf(float** in, float** out, int inChans, int outChans, unsigned int size);
@ -769,6 +774,8 @@ class DivEngine {
totalProcessed(0), totalProcessed(0),
oscBuf{NULL,NULL}, oscBuf{NULL,NULL},
oscSize(1), oscSize(1),
oscReadPos(0),
oscWritePos(0),
adpcmAMem(NULL), adpcmAMem(NULL),
adpcmAMemLen(0), adpcmAMemLen(0),
adpcmBMem(NULL), adpcmBMem(NULL),

File diff suppressed because it is too large Load diff

View file

@ -41,10 +41,10 @@ void DivEngine::loadDMP(SafeReader& reader, std::vector<DivInstrument*>& ret, St
try { try {
reader.seek(0,SEEK_SET); reader.seek(0,SEEK_SET);
version=reader.readC(); version=reader.readC();
logD(".dmp version %d\n",version); logD(".dmp version %d",version);
} catch (EndOfFileException& e) { } catch (EndOfFileException& e) {
lastError="premature end of file"; lastError="premature end of file";
logE("premature end of file!\n"); logE("premature end of file!");
delete ins; delete ins;
return; return;
} }
@ -64,38 +64,38 @@ void DivEngine::loadDMP(SafeReader& reader, std::vector<DivInstrument*>& ret, St
switch (sys) { switch (sys) {
case 1: // YMU759 case 1: // YMU759
ins->type=DIV_INS_FM; ins->type=DIV_INS_FM;
logD("instrument type is YMU759\n"); logD("instrument type is YMU759");
break; break;
case 2: // Genesis case 2: // Genesis
ins->type=DIV_INS_FM; ins->type=DIV_INS_FM;
logD("instrument type is Genesis\n"); logD("instrument type is Genesis");
break; break;
case 3: // SMS case 3: // SMS
ins->type=DIV_INS_STD; ins->type=DIV_INS_STD;
logD("instrument type is SMS\n"); logD("instrument type is SMS");
break; break;
case 4: // Game Boy case 4: // Game Boy
ins->type=DIV_INS_GB; ins->type=DIV_INS_GB;
logD("instrument type is Game Boy\n"); logD("instrument type is Game Boy");
break; break;
case 5: // PC Engine case 5: // PC Engine
ins->type=DIV_INS_PCE; ins->type=DIV_INS_PCE;
logD("instrument type is PC Engine\n"); logD("instrument type is PC Engine");
break; break;
case 6: // NES case 6: // NES
ins->type=DIV_INS_STD; ins->type=DIV_INS_STD;
logD("instrument type is NES\n"); logD("instrument type is NES");
break; break;
case 7: case 0x17: // C64 case 7: case 0x17: // C64
ins->type=DIV_INS_C64; ins->type=DIV_INS_C64;
logD("instrument type is C64\n"); logD("instrument type is C64");
break; break;
case 8: // Arcade case 8: // Arcade
ins->type=DIV_INS_FM; ins->type=DIV_INS_FM;
logD("instrument type is Arcade\n"); logD("instrument type is Arcade");
break; break;
default: default:
logD("instrument type is unknown\n"); logD("instrument type is unknown");
lastError="unknown instrument type!"; lastError="unknown instrument type!";
delete ins; delete ins;
return; return;
@ -103,7 +103,7 @@ void DivEngine::loadDMP(SafeReader& reader, std::vector<DivInstrument*>& ret, St
} }
} catch (EndOfFileException& e) { } catch (EndOfFileException& e) {
lastError="premature end of file"; lastError="premature end of file";
logE("premature end of file!\n"); logE("premature end of file!");
delete ins; delete ins;
return; return;
} }
@ -113,7 +113,7 @@ void DivEngine::loadDMP(SafeReader& reader, std::vector<DivInstrument*>& ret, St
bool mode=true; bool mode=true;
if (version>1) { if (version>1) {
mode=reader.readC(); mode=reader.readC();
logD("instrument mode is %d\n",mode); logD("instrument mode is %d",mode);
if (mode==0) { if (mode==0) {
if (version<11) { if (version<11) {
ins->type=DIV_INS_STD; ins->type=DIV_INS_STD;
@ -126,7 +126,7 @@ void DivEngine::loadDMP(SafeReader& reader, std::vector<DivInstrument*>& ret, St
} }
if (mode) { // FM if (mode) { // FM
logD("reading FM data...\n"); logD("reading FM data...");
if (version<10) { if (version<10) {
if (version>1) { if (version>1) {
// bullcrap! no way to determine the instrument type other than a vague FM/STD! // 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(); if (sys!=1) ins->fm.ams=reader.readC();
for (int j=0; j<ins->fm.ops; j++) { 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].mult=reader.readC();
ins->fm.op[j].tl=reader.readC(); ins->fm.op[j].tl=reader.readC();
ins->fm.op[j].ar=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 } else { // STD
logD("reading STD data...\n"); logD("reading STD data...");
if (ins->type!=DIV_INS_GB) { if (ins->type!=DIV_INS_GB) {
ins->std.volMacroLen=reader.readC(); ins->std.volMacro.len=reader.readC();
if (version>5) { if (version>5) {
for (int i=0; i<ins->std.volMacroLen; i++) { for (int i=0; i<ins->std.volMacro.len; i++) {
ins->std.volMacro[i]=reader.readI(); ins->std.volMacro.val[i]=reader.readI();
} }
} else { } else {
for (int i=0; i<ins->std.volMacroLen; i++) { for (int i=0; i<ins->std.volMacro.len; i++) {
ins->std.volMacro[i]=reader.readC(); ins->std.volMacro.val[i]=reader.readC();
} }
} }
if (version<11) for (int i=0; i<ins->std.volMacroLen; i++) { if (version<11) for (int i=0; i<ins->std.volMacro.len; i++) {
if (ins->std.volMacro[i]>15 && ins->type==DIV_INS_STD) ins->type=DIV_INS_PCE; if (ins->std.volMacro.val[i]>15 && ins->type==DIV_INS_STD) ins->type=DIV_INS_PCE;
} }
if (ins->std.volMacroLen>0) { if (ins->std.volMacro.len>0) {
ins->std.volMacroOpen=true; ins->std.volMacro.open=true;
ins->std.volMacroLoop=reader.readC(); ins->std.volMacro.loop=reader.readC();
} else { } else {
ins->std.volMacroOpen=false; ins->std.volMacro.open=false;
} }
} }
ins->std.arpMacroLen=reader.readC(); ins->std.arpMacro.len=reader.readC();
if (version>5) { if (version>5) {
for (int i=0; i<ins->std.arpMacroLen; i++) { for (int i=0; i<ins->std.arpMacro.len; i++) {
ins->std.arpMacro[i]=reader.readI(); ins->std.arpMacro.val[i]=reader.readI();
} }
} else { } else {
for (int i=0; i<ins->std.arpMacroLen; i++) { for (int i=0; i<ins->std.arpMacro.len; i++) {
ins->std.arpMacro[i]=reader.readC(); ins->std.arpMacro.val[i]=reader.readC();
} }
} }
if (ins->std.arpMacroLen>0) { if (ins->std.arpMacro.len>0) {
ins->std.arpMacroOpen=true; ins->std.arpMacro.open=true;
ins->std.arpMacroLoop=reader.readC(); ins->std.arpMacro.loop=reader.readC();
} else { } else {
ins->std.arpMacroOpen=false; ins->std.arpMacro.open=false;
} }
if (version>8) { // TODO: when? 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) { if (version>5) {
for (int i=0; i<ins->std.dutyMacroLen; i++) { for (int i=0; i<ins->std.dutyMacro.len; i++) {
ins->std.dutyMacro[i]=reader.readI(); ins->std.dutyMacro.val[i]=reader.readI();
} }
} else { } else {
for (int i=0; i<ins->std.dutyMacroLen; i++) { for (int i=0; i<ins->std.dutyMacro.len; i++) {
ins->std.dutyMacro[i]=reader.readC(); ins->std.dutyMacro.val[i]=reader.readC();
} }
} }
if (ins->std.dutyMacroLen>0) { if (ins->std.dutyMacro.len>0) {
ins->std.dutyMacroOpen=true; ins->std.dutyMacro.open=true;
ins->std.dutyMacroLoop=reader.readC(); ins->std.dutyMacro.loop=reader.readC();
} else { } else {
ins->std.dutyMacroOpen=false; ins->std.dutyMacro.open=false;
} }
ins->std.waveMacroLen=reader.readC(); ins->std.waveMacro.len=reader.readC();
if (version>5) { if (version>5) {
for (int i=0; i<ins->std.waveMacroLen; i++) { for (int i=0; i<ins->std.waveMacro.len; i++) {
ins->std.waveMacro[i]=reader.readI(); ins->std.waveMacro.val[i]=reader.readI();
} }
} else { } else {
for (int i=0; i<ins->std.waveMacroLen; i++) { for (int i=0; i<ins->std.waveMacro.len; i++) {
ins->std.waveMacro[i]=reader.readC(); ins->std.waveMacro.val[i]=reader.readC();
} }
} }
if (ins->std.waveMacroLen>0) { if (ins->std.waveMacro.len>0) {
ins->std.waveMacroOpen=true; ins->std.waveMacro.open=true;
ins->std.waveMacroLoop=reader.readC(); ins->std.waveMacro.loop=reader.readC();
} else { } else {
ins->std.waveMacroOpen=false; ins->std.waveMacro.open=false;
} }
if (ins->type==DIV_INS_C64) { if (ins->type==DIV_INS_C64) {
@ -295,7 +295,7 @@ void DivEngine::loadDMP(SafeReader& reader, std::vector<DivInstrument*>& ret, St
} }
} catch (EndOfFileException& e) { } catch (EndOfFileException& e) {
lastError="premature end of file"; lastError="premature end of file";
logE("premature end of file!\n"); logE("premature end of file!");
delete ins; delete ins;
return; return;
} }
@ -330,7 +330,7 @@ void DivEngine::loadTFI(SafeReader& reader, std::vector<DivInstrument*>& ret, St
} }
} catch (EndOfFileException& e) { } catch (EndOfFileException& e) {
lastError="premature end of file"; lastError="premature end of file";
logE("premature end of file!\n"); logE("premature end of file!");
delete ins; delete ins;
return; return;
} }
@ -372,7 +372,7 @@ void DivEngine::loadVGI(SafeReader& reader, std::vector<DivInstrument*>& ret, St
} }
} catch (EndOfFileException& e) { } catch (EndOfFileException& e) {
lastError="premature end of file"; lastError="premature end of file";
logE("premature end of file!\n"); logE("premature end of file!");
delete ins; delete ins;
return; return;
} }
@ -453,7 +453,7 @@ void DivEngine::loadS3I(SafeReader& reader, std::vector<DivInstrument*>& ret, St
}; };
} catch (EndOfFileException& e) { } catch (EndOfFileException& e) {
lastError = "premature end of file"; lastError = "premature end of file";
logE("premature end of file!\n"); logE("premature end of file!");
delete ins; delete ins;
return; return;
} }
@ -623,7 +623,7 @@ void DivEngine::loadSBI(SafeReader& reader, std::vector<DivInstrument*>& ret, St
} catch (EndOfFileException& e) { } catch (EndOfFileException& e) {
lastError = "premature end of file"; lastError = "premature end of file";
logE("premature end of file!\n"); logE("premature end of file!");
delete ins; delete ins;
return; return;
} }
@ -640,7 +640,7 @@ void DivEngine::loadOPM(SafeReader& reader, std::vector<DivInstrument*>& ret, St
} catch (EndOfFileException& e) { } catch (EndOfFileException& e) {
lastError="premature end of file"; lastError="premature end of file";
logE("premature end of file!\n"); logE("premature end of file!");
return; return;
} }
} }
@ -695,7 +695,7 @@ std::vector<DivInstrument*> DivEngine::instrumentFromFile(const char* path) {
} }
buf=new unsigned char[len]; buf=new unsigned char[len];
if (fread(buf,1,len,f)!=(size_t)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!"; lastError="did not read entire instrument file!";
delete[] buf; delete[] buf;
return ret; return ret;
@ -738,7 +738,7 @@ std::vector<DivInstrument*> DivEngine::instrumentFromFile(const char* path) {
} }
} catch (EndOfFileException& e) { } catch (EndOfFileException& e) {
lastError="premature end of file"; lastError="premature end of file";
logE("premature end of file!\n"); logE("premature end of file!");
delete ins; delete ins;
delete[] buf; delete[] buf;
return ret; return ret;

View file

@ -17,7 +17,6 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#include <stddef.h>
#define _USE_MATH_DEFINES #define _USE_MATH_DEFINES
#include <math.h> #include <math.h>
#include "filter.h" #include "filter.h"
@ -31,7 +30,7 @@ float* DivFilterTables::sincIntegralTable=NULL;
// licensed under same license as this program. // licensed under same license as this program.
float* DivFilterTables::getCubicTable() { float* DivFilterTables::getCubicTable() {
if (cubicTable==NULL) { if (cubicTable==NULL) {
logD("initializing cubic spline table.\n"); logD("initializing cubic spline table.");
cubicTable=new float[4096]; cubicTable=new float[4096];
for (int i=0; i<1024; i++) { for (int i=0; i<1024; i++) {
@ -47,7 +46,7 @@ float* DivFilterTables::getCubicTable() {
float* DivFilterTables:: getSincTable() { float* DivFilterTables:: getSincTable() {
if (sincTable==NULL) { if (sincTable==NULL) {
logD("initializing sinc table.\n"); logD("initializing sinc table.");
sincTable=new float[65536]; sincTable=new float[65536];
sincTable[0]=1.0f; sincTable[0]=1.0f;
@ -67,7 +66,7 @@ float* DivFilterTables:: getSincTable() {
float* DivFilterTables::getSincIntegralTable() { float* DivFilterTables::getSincIntegralTable() {
if (sincIntegralTable==NULL) { if (sincIntegralTable==NULL) {
logD("initializing sinc integral table.\n"); logD("initializing sinc integral table.");
sincIntegralTable=new float[65536]; sincIntegralTable=new float[65536];
sincIntegralTable[0]=-0.5f; sincIntegralTable[0]=-0.5f;
@ -85,4 +84,4 @@ float* DivFilterTables::getSincIntegralTable() {
} }
} }
return sincIntegralTable; return sincIntegralTable;
} }

File diff suppressed because it is too large Load diff

View file

@ -26,7 +26,7 @@
// NOTICE! // NOTICE!
// before adding new instrument types to this struct, please ask me first. // before adding new instrument types to this struct, please ask me first.
// absolutely zero support granted to conflicting formats. // absolutely zero support granted to conflicting formats.
enum DivInstrumentType { enum DivInstrumentType: unsigned short {
DIV_INS_STD=0, DIV_INS_STD=0,
DIV_INS_FM=1, DIV_INS_FM=1,
DIV_INS_GB=2, DIV_INS_GB=2,
@ -77,9 +77,11 @@ struct DivInstrumentFM {
bool fixedDrums; bool fixedDrums;
unsigned short kickFreq, snareHatFreq, tomTopFreq; unsigned short kickFreq, snareHatFreq, tomTopFreq;
struct Operator { struct Operator {
bool enable;
unsigned char am, ar, dr, mult, rr, sl, tl, dt2, rs, dt, d2r, ssgEnv; 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 unsigned char dam, dvb, egt, ksl, sus, vib, ws, ksr; // YMU759/OPL/OPZ
Operator(): Operator():
enable(true),
am(0), am(0),
ar(0), ar(0),
dr(0), dr(0),
@ -151,248 +153,97 @@ struct DivInstrumentFM {
}; };
// this is getting out of hand // 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 { struct DivInstrumentSTD {
int volMacro[256]; DivInstrumentMacro volMacro;
int arpMacro[256]; DivInstrumentMacro arpMacro;
int dutyMacro[256]; DivInstrumentMacro dutyMacro;
int waveMacro[256]; DivInstrumentMacro waveMacro;
int pitchMacro[256]; DivInstrumentMacro pitchMacro;
int ex1Macro[256]; DivInstrumentMacro ex1Macro;
int ex2Macro[256]; DivInstrumentMacro ex2Macro;
int ex3Macro[256]; DivInstrumentMacro ex3Macro;
int algMacro[256]; DivInstrumentMacro algMacro;
int fbMacro[256]; DivInstrumentMacro fbMacro;
int fmsMacro[256]; DivInstrumentMacro fmsMacro;
int amsMacro[256]; DivInstrumentMacro amsMacro;
int panLMacro[256]; DivInstrumentMacro panLMacro;
int panRMacro[256]; DivInstrumentMacro panRMacro;
int phaseResetMacro[256]; DivInstrumentMacro phaseResetMacro;
int ex4Macro[256]; DivInstrumentMacro ex4Macro;
int ex5Macro[256]; DivInstrumentMacro ex5Macro;
int ex6Macro[256]; DivInstrumentMacro ex6Macro;
int ex7Macro[256]; DivInstrumentMacro ex7Macro;
int ex8Macro[256]; 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 { struct OpMacro {
// ar, dr, mult, rr, sl, tl, dt2, rs, dt, d2r, ssgEnv; // ar, dr, mult, rr, sl, tl, dt2, rs, dt, d2r, ssgEnv;
unsigned char amMacro[256]; DivInstrumentMacro amMacro;
unsigned char arMacro[256]; DivInstrumentMacro arMacro;
unsigned char drMacro[256]; DivInstrumentMacro drMacro;
unsigned char multMacro[256]; DivInstrumentMacro multMacro;
unsigned char rrMacro[256]; DivInstrumentMacro rrMacro;
unsigned char slMacro[256]; DivInstrumentMacro slMacro;
unsigned char tlMacro[256]; DivInstrumentMacro tlMacro;
unsigned char dt2Macro[256]; DivInstrumentMacro dt2Macro;
unsigned char rsMacro[256]; DivInstrumentMacro rsMacro;
unsigned char dtMacro[256]; DivInstrumentMacro dtMacro;
unsigned char d2rMacro[256]; DivInstrumentMacro d2rMacro;
unsigned char ssgMacro[256]; DivInstrumentMacro ssgMacro;
unsigned char damMacro[256]; DivInstrumentMacro damMacro;
unsigned char dvbMacro[256]; DivInstrumentMacro dvbMacro;
unsigned char egtMacro[256]; DivInstrumentMacro egtMacro;
unsigned char kslMacro[256]; DivInstrumentMacro kslMacro;
unsigned char susMacro[256]; DivInstrumentMacro susMacro;
unsigned char vibMacro[256]; DivInstrumentMacro vibMacro;
unsigned char wsMacro[256]; DivInstrumentMacro wsMacro;
unsigned char ksrMacro[256]; DivInstrumentMacro ksrMacro;
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;
OpMacro(): OpMacro():
amMacroOpen(false), arMacroOpen(false), drMacroOpen(false), multMacroOpen(false), amMacro("am"), arMacro("ar"), drMacro("dr"), multMacro("mult"),
rrMacroOpen(false), slMacroOpen(false), tlMacroOpen(true), dt2MacroOpen(false), rrMacro("rr"), slMacro("sl"), tlMacro("tl",true), dt2Macro("dt2"),
rsMacroOpen(false), dtMacroOpen(false), d2rMacroOpen(false), ssgMacroOpen(false), rsMacro("rs"), dtMacro("dt"), d2rMacro("d2r"), ssgMacro("ssg"),
damMacroOpen(false), dvbMacroOpen(false), egtMacroOpen(false), kslMacroOpen(false), damMacro("dam"), dvbMacro("dvb"), egtMacro("egt"), kslMacro("ksl"),
susMacroOpen(false), vibMacroOpen(false), wsMacroOpen(false), ksrMacroOpen(false), susMacro("sus"), vibMacro("vib"), wsMacro("ws"), ksrMacro("ksr") {}
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);
}
} opMacros[4]; } opMacros[4];
DivInstrumentSTD(): DivInstrumentSTD():
arpMacroMode(false), volMacro("vol",true),
volMacroHeight(15), arpMacro("arp"),
dutyMacroHeight(3), dutyMacro("duty"),
waveMacroHeight(63), waveMacro("wave"),
volMacroOpen(true), pitchMacro("pitch"),
arpMacroOpen(false), ex1Macro("ex1"),
dutyMacroOpen(false), ex2Macro("ex2"),
waveMacroOpen(false), ex3Macro("ex3"),
pitchMacroOpen(false), algMacro("alg"),
ex1MacroOpen(false), fbMacro("fb"),
ex2MacroOpen(false), fmsMacro("fms"),
ex3MacroOpen(false), amsMacro("ams"),
algMacroOpen(false), panLMacro("panL"),
fbMacroOpen(false), panRMacro("panR"),
fmsMacroOpen(false), phaseResetMacro("phaseReset"),
amsMacroOpen(false), ex4Macro("ex4"),
panLMacroOpen(false), ex5Macro("ex5"),
panRMacroOpen(false), ex6Macro("ex6"),
phaseResetMacroOpen(false), ex7Macro("ex7"),
ex4MacroOpen(false), ex8Macro("ex8") {}
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));
}
}; };
struct DivInstrumentGB { struct DivInstrumentGB {

View file

@ -20,85 +20,41 @@
#include "macroInt.h" #include "macroInt.h"
#include "instrument.h" #include "instrument.h"
#define doMacro(finished,had,has,val,pos,source,sourceLen,sourceLoop,sourceRel) \ void DivMacroStruct::doMacro(DivInstrumentMacro& source, bool released) {
if (finished) finished=false; \ if (finished) {
if (had!=has) { \ finished=false;
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; \
} \
} \
} }
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() { void DivMacroInt::next() {
if (ins==NULL) return; if (ins==NULL) return;
// run macros
doMacro(finishedVol,hadVol,hasVol,vol,volPos,ins->std.volMacro,ins->std.volMacroLen,ins->std.volMacroLoop,ins->std.volMacroRel); // TODO: potentially get rid of list to avoid allocations
doMacro(finishedArp,hadArp,hasArp,arp,arpPos,ins->std.arpMacro,ins->std.arpMacroLen,ins->std.arpMacroLoop,ins->std.arpMacroRel); for (size_t i=0; i<macroListLen; i++) {
doMacro(finishedDuty,hadDuty,hasDuty,duty,dutyPos,ins->std.dutyMacro,ins->std.dutyMacroLen,ins->std.dutyMacroLoop,ins->std.dutyMacroRel); if (macroList[i]!=NULL && macroSource[i]!=NULL) {
doMacro(finishedWave,hadWave,hasWave,wave,wavePos,ins->std.waveMacro,ins->std.waveMacroLen,ins->std.waveMacroLoop,ins->std.waveMacroRel); macroList[i]->doMacro(*macroSource[i],released);
}
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);
} }
} }
@ -106,316 +62,155 @@ void DivMacroInt::release() {
released=true; released=true;
} }
#define ADD_MACRO(m,s) \
macroList[macroListLen]=&m; \
macroSource[macroListLen++]=&s;
void DivMacroInt::init(DivInstrument* which) { void DivMacroInt::init(DivInstrument* which) {
ins=which; ins=which;
volPos=0; // initialize
arpPos=0; for (size_t i=0; i<macroListLen; i++) {
dutyPos=0; if (macroList[i]!=NULL) macroList[i]->init();
wavePos=0; }
pitchPos=0; macroListLen=0;
ex1Pos=0;
ex2Pos=0;
ex3Pos=0;
algPos=0;
fbPos=0;
fmsPos=0;
amsPos=0;
panLPos=0;
panRPos=0;
phaseResetPos=0;
ex4Pos=0;
ex5Pos=0;
ex6Pos=0;
ex7Pos=0;
ex8Pos=0;
released=false; 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==NULL) return;
if (ins->std.volMacroLen>0) { // prepare common macro
hadVol=true; if (ins->std.volMacro.len>0) {
hasVol=true; ADD_MACRO(vol,ins->std.volMacro);
willVol=true;
} }
if (ins->std.arpMacroLen>0) { if (ins->std.arpMacro.len>0) {
hadArp=true; ADD_MACRO(arp,ins->std.arpMacro);
hasArp=true;
willArp=true;
} }
if (ins->std.dutyMacroLen>0) { if (ins->std.dutyMacro.len>0) {
hadDuty=true; ADD_MACRO(duty,ins->std.dutyMacro);
hasDuty=true;
willDuty=true;
} }
if (ins->std.waveMacroLen>0) { if (ins->std.waveMacro.len>0) {
hadWave=true; ADD_MACRO(wave,ins->std.waveMacro);
hasWave=true;
willWave=true;
} }
if (ins->std.pitchMacroLen>0) { if (ins->std.pitchMacro.len>0) {
hadPitch=true; ADD_MACRO(pitch,ins->std.pitchMacro);
hasPitch=true;
willPitch=true;
} }
if (ins->std.ex1MacroLen>0) { if (ins->std.ex1Macro.len>0) {
hadEx1=true; ADD_MACRO(ex1,ins->std.ex1Macro);
hasEx1=true;
willEx1=true;
} }
if (ins->std.ex2MacroLen>0) { if (ins->std.ex2Macro.len>0) {
hadEx2=true; ADD_MACRO(ex2,ins->std.ex2Macro);
hasEx2=true;
willEx2=true;
} }
if (ins->std.ex3MacroLen>0) { if (ins->std.ex3Macro.len>0) {
hadEx3=true; ADD_MACRO(ex3,ins->std.ex3Macro);
hasEx3=true;
willEx3=true;
} }
if (ins->std.algMacroLen>0) { if (ins->std.algMacro.len>0) {
hadAlg=true; ADD_MACRO(alg,ins->std.algMacro);
hasAlg=true;
willAlg=true;
} }
if (ins->std.fbMacroLen>0) { if (ins->std.fbMacro.len>0) {
hadFb=true; ADD_MACRO(fb,ins->std.fbMacro);
hasFb=true;
willFb=true;
} }
if (ins->std.fmsMacroLen>0) { if (ins->std.fmsMacro.len>0) {
hadFms=true; ADD_MACRO(fms,ins->std.fmsMacro);
hasFms=true;
willFms=true;
} }
if (ins->std.amsMacroLen>0) { if (ins->std.amsMacro.len>0) {
hadAms=true; ADD_MACRO(ams,ins->std.amsMacro);
hasAms=true;
willAms=true;
} }
// TODO: other macros if (ins->std.panLMacro.len>0) {
if (ins->std.panLMacroLen>0) { ADD_MACRO(panL,ins->std.panLMacro);
hadPanL=true;
hasPanL=true;
willPanL=true;
} }
if (ins->std.panRMacroLen>0) { if (ins->std.panRMacro.len>0) {
hadPanR=true; ADD_MACRO(panR,ins->std.panRMacro);
hasPanR=true;
willPanR=true;
} }
if (ins->std.phaseResetMacroLen>0) { if (ins->std.phaseResetMacro.len>0) {
hadPhaseReset=true; ADD_MACRO(phaseReset,ins->std.phaseResetMacro);
hasPhaseReset=true;
willPhaseReset=true;
} }
if (ins->std.ex4MacroLen>0) { if (ins->std.ex4Macro.len>0) {
hadEx4=true; ADD_MACRO(ex4,ins->std.ex4Macro);
hasEx4=true;
willEx4=true;
} }
if (ins->std.ex5MacroLen>0) { if (ins->std.ex5Macro.len>0) {
hadEx5=true; ADD_MACRO(ex5,ins->std.ex5Macro);
hasEx5=true;
willEx5=true;
} }
if (ins->std.ex6MacroLen>0) { if (ins->std.ex6Macro.len>0) {
hadEx6=true; ADD_MACRO(ex6,ins->std.ex6Macro);
hasEx6=true;
willEx6=true;
} }
if (ins->std.ex7MacroLen>0) { if (ins->std.ex7Macro.len>0) {
hadEx7=true; ADD_MACRO(ex7,ins->std.ex7Macro);
hasEx7=true;
willEx7=true;
} }
if (ins->std.ex8MacroLen>0) { if (ins->std.ex8Macro.len>0) {
hadEx8=true; ADD_MACRO(ex8,ins->std.ex8Macro);
hasEx8=true;
willEx8=true;
}
if (ins->std.arpMacroMode) {
arpMode=true;
} }
// prepare FM operator macros
for (int i=0; i<4; i++) { for (int i=0; i<4; i++) {
DivInstrumentSTD::OpMacro& m=ins->std.opMacros[i]; DivInstrumentSTD::OpMacro& m=ins->std.opMacros[i];
IntOp& o=op[i]; IntOp& o=op[i];
if (m.amMacro.len>0) {
if (m.amMacroLen>0) { ADD_MACRO(o.am,m.amMacro);
o.hadAm=true;
o.hasAm=true;
o.willAm=true;
} }
if (m.arMacroLen>0) { if (m.arMacro.len>0) {
o.hadAr=true; ADD_MACRO(o.ar,m.arMacro);
o.hasAr=true;
o.willAr=true;
} }
if (m.drMacroLen>0) { if (m.drMacro.len>0) {
o.hadDr=true; ADD_MACRO(o.dr,m.drMacro);
o.hasDr=true;
o.willDr=true;
} }
if (m.multMacroLen>0) { if (m.multMacro.len>0) {
o.hadMult=true; ADD_MACRO(o.mult,m.multMacro);
o.hasMult=true;
o.willMult=true;
} }
if (m.rrMacroLen>0) { if (m.rrMacro.len>0) {
o.hadRr=true; ADD_MACRO(o.rr,m.rrMacro);
o.hasRr=true;
o.willRr=true;
} }
if (m.slMacroLen>0) { if (m.slMacro.len>0) {
o.hadSl=true; ADD_MACRO(o.sl,m.slMacro);
o.hasSl=true;
o.willSl=true;
} }
if (m.tlMacroLen>0) { if (m.tlMacro.len>0) {
o.hadTl=true; ADD_MACRO(o.tl,m.tlMacro);
o.hasTl=true;
o.willTl=true;
} }
if (m.dt2MacroLen>0) { if (m.dt2Macro.len>0) {
o.hadDt2=true; ADD_MACRO(o.dt2,m.dt2Macro);
o.hasDt2=true;
o.willDt2=true;
} }
if (m.rsMacroLen>0) { if (m.rsMacro.len>0) {
o.hadRs=true; ADD_MACRO(o.rs,m.rsMacro);
o.hasRs=true;
o.willRs=true;
} }
if (m.dtMacroLen>0) { if (m.dtMacro.len>0) {
o.hadDt=true; ADD_MACRO(o.dt,m.dtMacro);
o.hasDt=true;
o.willDt=true;
} }
if (m.d2rMacroLen>0) { if (m.d2rMacro.len>0) {
o.hadD2r=true; ADD_MACRO(o.d2r,m.d2rMacro);
o.hasD2r=true;
o.willD2r=true;
} }
if (m.ssgMacroLen>0) { if (m.ssgMacro.len>0) {
o.hadSsg=true; ADD_MACRO(o.ssg,m.ssgMacro);
o.hasSsg=true;
o.willSsg=true;
} }
if (m.damMacroLen>0) { if (m.damMacro.len>0) {
o.hadDam=true; ADD_MACRO(o.dam,m.damMacro);
o.hasDam=true;
o.willDam=true;
} }
if (m.dvbMacroLen>0) { if (m.dvbMacro.len>0) {
o.hadDvb=true; ADD_MACRO(o.dvb,m.dvbMacro);
o.hasDvb=true;
o.willDvb=true;
} }
if (m.egtMacroLen>0) { if (m.egtMacro.len>0) {
o.hadEgt=true; ADD_MACRO(o.egt,m.egtMacro);
o.hasEgt=true;
o.willEgt=true;
} }
if (m.kslMacroLen>0) { if (m.kslMacro.len>0) {
o.hadKsl=true; ADD_MACRO(o.ksl,m.kslMacro);
o.hasKsl=true;
o.willKsl=true;
} }
if (m.susMacroLen>0) { if (m.susMacro.len>0) {
o.hadSus=true; ADD_MACRO(o.sus,m.susMacro);
o.hasSus=true;
o.willSus=true;
} }
if (m.vibMacroLen>0) { if (m.vibMacro.len>0) {
o.hadVib=true; ADD_MACRO(o.vib,m.vibMacro);
o.hasVib=true;
o.willVib=true;
} }
if (m.wsMacroLen>0) { if (m.wsMacro.len>0) {
o.hadWs=true; ADD_MACRO(o.ws,m.wsMacro);
o.hasWs=true;
o.willWs=true;
} }
if (m.ksrMacroLen>0) { if (m.ksrMacro.len>0) {
o.hadKsr=true; ADD_MACRO(o.ksr,m.ksrMacro);
o.hasKsr=true;
o.willKsr=true;
} }
} }
for (size_t i=0; i<macroListLen; i++) {
macroList[i]->prepare(*macroSource[i]);
}
} }
void DivMacroInt::notifyInsDeletion(DivInstrument* which) { void DivMacroInt::notifyInsDeletion(DivInstrument* which) {

View file

@ -22,125 +22,72 @@
#include "instrument.h" #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 { class DivMacroInt {
DivInstrument* ins; DivInstrument* ins;
int volPos, arpPos, dutyPos, wavePos, pitchPos, ex1Pos, ex2Pos, ex3Pos; DivMacroStruct* macroList[128];
int algPos, fbPos, fmsPos, amsPos; DivInstrumentMacro* macroSource[128];
int panLPos, panRPos, phaseResetPos, ex4Pos, ex5Pos, ex6Pos, ex7Pos, ex8Pos; size_t macroListLen;
bool released; bool released;
public: public:
int vol; // common macro
int arp; DivMacroStruct vol;
int duty, wave, pitch, ex1, ex2, ex3; DivMacroStruct arp;
int alg, fb, fms, ams; DivMacroStruct duty, wave, pitch, ex1, ex2, ex3;
int panL, panR, phaseReset, ex4, ex5, ex6, ex7, ex8; DivMacroStruct alg, fb, fms, ams;
bool hasVol, hasArp, hasDuty, hasWave, hasPitch, hasEx1, hasEx2, hasEx3, hasAlg, hasFb, hasFms, hasAms; DivMacroStruct panL, panR, phaseReset, ex4, ex5, ex6, ex7, ex8;
bool hasPanL, hasPanR, hasPhaseReset, hasEx4, hasEx5, hasEx6, hasEx7, hasEx8;
bool hadVol, hadArp, hadDuty, hadWave, hadPitch, hadEx1, hadEx2, hadEx3, hadAlg, hadFb, hadFms, hadAms; // FM operator macro
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;
struct IntOp { struct IntOp {
int amPos, arPos, drPos, multPos; DivMacroStruct am, ar, dr, mult;
int rrPos, slPos, tlPos, dt2Pos; DivMacroStruct rr, sl, tl, dt2;
int rsPos, dtPos, d2rPos, ssgPos; DivMacroStruct rs, dt, d2r, ssg;
int damPos, dvbPos, egtPos, kslPos; DivMacroStruct dam, dvb, egt, ksl;
int susPos, vibPos, wsPos, ksrPos; DivMacroStruct sus, vib, ws, ksr;
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;
IntOp(): IntOp():
amPos(0), am(),
arPos(0), ar(),
drPos(0), dr(),
multPos(0), mult(),
rrPos(0), rr(),
slPos(0), sl(),
tlPos(0), tl(),
dt2Pos(0), dt2(),
rsPos(0), rs(),
dtPos(0), dt(),
d2rPos(0), d2r(),
ssgPos(0), ssg(),
damPos(0), dam(),
dvbPos(0), dvb(),
egtPos(0), egt(),
kslPos(0), ksl(),
susPos(0), sus(),
vibPos(0), vib(),
wsPos(0), ws(),
ksrPos(0), ksr() {}
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) {}
} op[4]; } op[4];
/** /**
@ -167,128 +114,31 @@ class DivMacroInt {
DivMacroInt(): DivMacroInt():
ins(NULL), ins(NULL),
volPos(0), macroListLen(0),
arpPos(0),
dutyPos(0),
wavePos(0),
pitchPos(0),
ex1Pos(0),
ex2Pos(0),
ex3Pos(0),
algPos(0),
fbPos(0),
fmsPos(0),
amsPos(0),
panLPos(0),
panRPos(0),
phaseResetPos(0),
ex4Pos(0),
ex5Pos(0),
ex6Pos(0),
ex7Pos(0),
ex8Pos(0),
released(false), released(false),
vol(0), vol(),
arp(0), arp(),
duty(0), duty(),
wave(0), wave(),
pitch(0), pitch(),
ex1(0), ex1(),
ex2(0), ex2(),
ex3(0), ex3(),
alg(0), alg(),
fb(0), fb(),
fms(0), fms(),
ams(0), ams(),
panL(0), panL(),
panR(0), panR(),
phaseReset(0), phaseReset(),
ex4(0), ex4(),
ex5(0), ex5(),
ex6(0), ex6(),
ex7(0), ex7(),
ex8(0), ex8() {
hasVol(false), memset(macroList,0,128*sizeof(void*));
hasArp(false), memset(macroSource,0,128*sizeof(void*));
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) {}
}; };
#endif #endif

View file

@ -21,10 +21,10 @@
#define _ORDERS_H #define _ORDERS_H
struct DivOrders { struct DivOrders {
unsigned char ord[DIV_MAX_CHANS][128]; unsigned char ord[DIV_MAX_CHANS][256];
DivOrders() { DivOrders() {
memset(ord,0,DIV_MAX_CHANS*128); memset(ord,0,DIV_MAX_CHANS*256);
} }
}; };

View file

@ -41,7 +41,7 @@ DivPattern* DivChannelData::getPattern(int index, bool create) {
} }
void DivChannelData::wipePatterns() { void DivChannelData::wipePatterns() {
for (int i=0; i<128; i++) { for (int i=0; i<256; i++) {
if (data[i]!=NULL) { if (data[i]!=NULL) {
delete data[i]; delete data[i];
data[i]=NULL; data[i]=NULL;
@ -131,5 +131,5 @@ SafeReader* DivPattern::compile(int len, int fxRows) {
DivChannelData::DivChannelData(): DivChannelData::DivChannelData():
effectRows(1) { effectRows(1) {
memset(data,0,128*sizeof(void*)); memset(data,0,256*sizeof(void*));
} }

View file

@ -49,7 +49,7 @@ struct DivChannelData {
// 3: volume // 3: volume
// 4-5+: effect/effect value // 4-5+: effect/effect value
// do NOT access directly unless you know what you're doing! // 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. * get a pattern from this channel, or the empty pattern if not initialized.

View file

@ -74,6 +74,14 @@ int DivDispatch::getPortaFloor(int ch) {
return 0x00; return 0x00;
} }
float DivDispatch::getPostAmp() {
return 1.0f;
}
bool DivDispatch::getDCOffRequired() {
return false;
}
const char* DivDispatch::getEffectName(unsigned char effect) { const char* DivDispatch::getEffectName(unsigned char effect) {
return NULL; return NULL;
} }

View file

@ -147,8 +147,8 @@ void DivPlatformAmiga::acquire(short* bufL, short* bufR, size_t start, size_t le
void DivPlatformAmiga::tick() { void DivPlatformAmiga::tick() {
for (int i=0; i<4; i++) { for (int i=0; i<4; i++) {
chan[i].std.next(); chan[i].std.next();
if (chan[i].std.hadVol) { if (chan[i].std.vol.had) {
chan[i].outVol=((chan[i].vol%65)*MIN(64,chan[i].std.vol))>>6; chan[i].outVol=((chan[i].vol%65)*MIN(64,chan[i].std.vol.val))>>6;
} }
double off=1.0; double off=1.0;
if (chan[i].sample>=0 && chan[i].sample<parent->song.sampleLen) { if (chan[i].sample>=0 && chan[i].sample<parent->song.sampleLen) {
@ -159,24 +159,24 @@ void DivPlatformAmiga::tick() {
off=8363.0/(double)s->centerRate; off=8363.0/(double)s->centerRate;
} }
} }
if (chan[i].std.hadArp) { if (chan[i].std.arp.had) {
if (!chan[i].inPorta) { if (!chan[i].inPorta) {
if (chan[i].std.arpMode) { if (chan[i].std.arp.mode) {
chan[i].baseFreq=round(off*NOTE_PERIODIC_NOROUND(chan[i].std.arp)); chan[i].baseFreq=round(off*NOTE_PERIODIC_NOROUND(chan[i].std.arp.val));
} else { } 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; chan[i].freqChanged=true;
} else { } 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].baseFreq=round(off*NOTE_PERIODIC_NOROUND(chan[i].note));
chan[i].freqChanged=true; chan[i].freqChanged=true;
} }
} }
if (chan[i].std.hadWave) { if (chan[i].std.wave.had) {
if (chan[i].wave!=chan[i].std.wave) { if (chan[i].wave!=chan[i].std.wave.val) {
chan[i].wave=chan[i].std.wave; chan[i].wave=chan[i].std.wave.val;
if (!chan[i].keyOff) chan[i].keyOn=true; if (!chan[i].keyOff) chan[i].keyOn=true;
} }
} }
@ -252,13 +252,13 @@ int DivPlatformAmiga::dispatch(DivCommand c) {
case DIV_CMD_VOLUME: case DIV_CMD_VOLUME:
if (chan[c.chan].vol!=c.value) { if (chan[c.chan].vol!=c.value) {
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].outVol=c.value;
} }
} }
break; break;
case DIV_CMD_GET_VOLUME: 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].vol;
} }
return chan[c.chan].outVol; return chan[c.chan].outVol;
@ -315,7 +315,7 @@ int DivPlatformAmiga::dispatch(DivCommand c) {
off=8363.0/(double)s->centerRate; 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].freqChanged=true;
chan[c.chan].note=c.value; chan[c.chan].note=c.value;
break; break;

View file

@ -132,6 +132,9 @@ const char* DivPlatformArcade::getEffectName(unsigned char effect) {
case 0x1f: case 0x1f:
return "1Fxx: Set PM depth (0 to 7F)"; return "1Fxx: Set PM depth (0 to 7F)";
break; break;
case 0x30:
return "30xx: Toggle hard envelope reset on new notes";
break;
} }
return NULL; return NULL;
} }
@ -220,8 +223,8 @@ void DivPlatformArcade::tick() {
for (int i=0; i<8; i++) { for (int i=0; i<8; i++) {
chan[i].std.next(); chan[i].std.next();
if (chan[i].std.hadVol) { if (chan[i].std.vol.had) {
chan[i].outVol=(chan[i].vol*MIN(127,chan[i].std.vol))/127; chan[i].outVol=(chan[i].vol*MIN(127,chan[i].std.vol.val))/127;
for (int j=0; j<4; j++) { for (int j=0; j<4; j++) {
unsigned short baseAddr=chanOffs[i]|opOffs[j]; unsigned short baseAddr=chanOffs[i]|opOffs[j];
DivInstrumentFM::Operator& op=chan[i].state.op[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].inPorta) {
if (chan[i].std.arpMode) { if (chan[i].std.arp.mode) {
chan[i].baseFreq=NOTE_LINEAR(chan[i].std.arp); chan[i].baseFreq=NOTE_LINEAR(chan[i].std.arp.val);
} else { } 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; chan[i].freqChanged=true;
} else { } 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].baseFreq=NOTE_LINEAR(chan[i].note);
chan[i].freqChanged=true; chan[i].freqChanged=true;
} }
} }
if (chan[i].std.hadDuty) { if (chan[i].std.duty.had) {
if (chan[i].std.duty>0) { if (chan[i].std.duty.val>0) {
rWrite(0x0f,0x80|(0x20-chan[i].std.duty)); rWrite(0x0f,0x80|(0x20-chan[i].std.duty.val));
} else { } else {
rWrite(0x0f,0); rWrite(0x0f,0);
} }
} }
if (chan[i].std.hadWave) { if (chan[i].std.wave.had) {
rWrite(0x1b,chan[i].std.wave&3); rWrite(0x1b,chan[i].std.wave.val&3);
} }
if (chan[i].std.hadEx1) { if (chan[i].std.ex1.had) {
amDepth=chan[i].std.ex1; amDepth=chan[i].std.ex1.val;
immWrite(0x19,amDepth); immWrite(0x19,amDepth);
} }
if (chan[i].std.hadEx2) { if (chan[i].std.ex2.had) {
pmDepth=chan[i].std.ex2; pmDepth=chan[i].std.ex2.val;
immWrite(0x19,0x80|pmDepth); immWrite(0x19,0x80|pmDepth);
} }
if (chan[i].std.hadEx3) { if (chan[i].std.ex3.had) {
immWrite(0x18,chan[i].std.ex3); immWrite(0x18,chan[i].std.ex3.val);
} }
if (chan[i].std.hadAlg) { if (chan[i].std.alg.had) {
chan[i].state.alg=chan[i].std.alg; chan[i].state.alg=chan[i].std.alg.val;
if (isMuted[i]) { if (isMuted[i]) {
rWrite(chanOffs[i]+ADDR_LR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3)); rWrite(chanOffs[i]+ADDR_LR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3));
} else { } else {
@ -296,77 +299,94 @@ void DivPlatformArcade::tick() {
} }
} }
} }
if (chan[i].std.hadFb) { if (chan[i].std.fb.had) {
chan[i].state.fb=chan[i].std.fb; chan[i].state.fb=chan[i].std.fb.val;
if (isMuted[i]) { if (isMuted[i]) {
rWrite(chanOffs[i]+ADDR_LR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3)); rWrite(chanOffs[i]+ADDR_LR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3));
} else { } 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)); 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) { if (chan[i].std.fms.had) {
chan[i].state.fms=chan[i].std.fms; 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)); rWrite(chanOffs[i]+ADDR_FMS_AMS,((chan[i].state.fms&7)<<4)|(chan[i].state.ams&3));
} }
if (chan[i].std.hadAms) { if (chan[i].std.ams.had) {
chan[i].state.ams=chan[i].std.ams; 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)); rWrite(chanOffs[i]+ADDR_FMS_AMS,((chan[i].state.fms&7)<<4)|(chan[i].state.ams&3));
} }
for (int j=0; j<4; j++) { for (int j=0; j<4; j++) {
unsigned short baseAddr=chanOffs[i]|opOffs[j]; unsigned short baseAddr=chanOffs[i]|opOffs[j];
DivInstrumentFM::Operator& op=chan[i].state.op[j]; DivInstrumentFM::Operator& op=chan[i].state.op[j];
DivMacroInt::IntOp& m=chan[i].std.op[j]; DivMacroInt::IntOp& m=chan[i].std.op[j];
if (m.hadAm) { if (m.am.had) {
op.am=m.am; op.am=m.am.val;
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7)); rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
} }
if (m.hadAr) { if (m.ar.had) {
op.ar=m.ar; op.ar=m.ar.val;
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6)); rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6));
} }
if (m.hadDr) { if (m.dr.had) {
op.dr=m.dr; op.dr=m.dr.val;
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7)); rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
} }
if (m.hadMult) { if (m.mult.had) {
op.mult=m.mult; op.mult=m.mult.val;
rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4)); rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4));
} }
if (m.hadRr) { if (m.rr.had) {
op.rr=m.rr; op.rr=m.rr.val;
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4)); rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
} }
if (m.hadSl) { if (m.sl.had) {
op.sl=m.sl; op.sl=m.sl.val;
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4)); rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
} }
if (m.hadTl) { if (m.tl.had) {
op.tl=127-m.tl; op.tl=127-m.tl.val;
if (isOutput[chan[i].state.alg][j]) { if (isOutput[chan[i].state.alg][j]) {
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127)); rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127));
} else { } else {
rWrite(baseAddr+ADDR_TL,op.tl); rWrite(baseAddr+ADDR_TL,op.tl);
} }
} }
if (m.hadRs) { if (m.rs.had) {
op.rs=m.rs; op.rs=m.rs.val;
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6)); rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6));
} }
if (m.hadDt) { if (m.dt.had) {
op.dt=m.dt; op.dt=m.dt.val;
rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4)); rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4));
} }
if (m.hadD2r) { if (m.d2r.had) {
op.d2r=m.d2r; op.d2r=m.d2r.val;
rWrite(baseAddr+ADDR_DT2_D2R,(op.d2r&31)|(op.dt2<<6)); rWrite(baseAddr+ADDR_DT2_D2R,(op.d2r&31)|(op.dt2<<6));
} }
if (m.hadDt2) { if (m.dt2.had) {
op.dt2=m.dt2; op.dt2=m.dt2.val;
rWrite(baseAddr+ADDR_DT2_D2R,(op.d2r&31)|(op.dt2<<6)); rWrite(baseAddr+ADDR_DT2_D2R,(op.d2r&31)|(op.dt2<<6));
} }
} }
if (chan[i].keyOn || chan[i].keyOff) { 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); 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; chan[i].keyOff=false;
} }
} }
@ -413,7 +433,7 @@ int DivPlatformArcade::dispatch(DivCommand c) {
} }
chan[c.chan].std.init(ins); 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; chan[c.chan].outVol=chan[c.chan].vol;
} }
@ -472,7 +492,7 @@ int DivPlatformArcade::dispatch(DivCommand c) {
break; break;
case DIV_CMD_VOLUME: { case DIV_CMD_VOLUME: {
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].outVol=c.value;
} }
for (int i=0; i<4; i++) { for (int i=0; i<4; i++) {
@ -602,6 +622,9 @@ int DivPlatformArcade::dispatch(DivCommand c) {
immWrite(0x19,0x80|pmDepth); immWrite(0x19,0x80|pmDepth);
break; break;
} }
case DIV_CMD_FM_HARD_RESET:
chan[c.chan].hardReset=c.value;
break;
case DIV_CMD_STD_NOISE_FREQ: { case DIV_CMD_STD_NOISE_FREQ: {
if (c.chan!=7) break; if (c.chan!=7) break;
if (c.value) { if (c.value) {

View file

@ -39,10 +39,30 @@ class DivPlatformArcade: public DivDispatch {
int freq, baseFreq, pitch, note; int freq, baseFreq, pitch, note;
unsigned char ins; unsigned char ins;
signed char konCycles; 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; int vol, outVol;
unsigned char chVolL, chVolR; 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]; Channel chan[8];
struct QueuedWrite { struct QueuedWrite {

View file

@ -176,8 +176,8 @@ void DivPlatformAY8910::tick() {
// PSG // PSG
for (int i=0; i<3; i++) { for (int i=0; i<3; i++) {
chan[i].std.next(); chan[i].std.next();
if (chan[i].std.hadVol) { if (chan[i].std.vol.had) {
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 (chan[i].outVol<0) chan[i].outVol=0;
if (isMuted[i]) { if (isMuted[i]) {
rWrite(0x08+i,0); rWrite(0x08+i,0);
@ -187,26 +187,26 @@ void DivPlatformAY8910::tick() {
rWrite(0x08+i,(chan[i].outVol&15)|((chan[i].psgMode&4)<<2)); 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].inPorta) {
if (chan[i].std.arpMode) { if (chan[i].std.arp.mode) {
chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp); chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val);
} else { } 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; chan[i].freqChanged=true;
} else { } 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].baseFreq=NOTE_PERIODIC(chan[i].note);
chan[i].freqChanged=true; chan[i].freqChanged=true;
} }
} }
if (chan[i].std.hadDuty) { if (chan[i].std.duty.had) {
rWrite(0x06,31-chan[i].std.duty); rWrite(0x06,31-chan[i].std.duty.val);
} }
if (chan[i].std.hadWave) { if (chan[i].std.wave.had) {
chan[i].psgMode=(chan[i].std.wave+1)&7; chan[i].psgMode=(chan[i].std.wave.val+1)&7;
if (isMuted[i]) { if (isMuted[i]) {
rWrite(0x08+i,0); rWrite(0x08+i,0);
} else if (intellivision && (chan[i].psgMode&4)) { } 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)); rWrite(0x08+i,(chan[i].outVol&15)|((chan[i].psgMode&4)<<2));
} }
} }
if (chan[i].std.hadEx2) { if (chan[i].std.ex2.had) {
ayEnvMode=chan[i].std.ex2; ayEnvMode=chan[i].std.ex2.val;
rWrite(0x0d,ayEnvMode); rWrite(0x0d,ayEnvMode);
} }
if (chan[i].std.hadEx3) { if (chan[i].std.ex3.had) {
chan[i].autoEnvNum=chan[i].std.ex3; chan[i].autoEnvNum=chan[i].std.ex3.val;
chan[i].freqChanged=true; 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) { if (chan[i].std.alg.had) {
chan[i].autoEnvDen=chan[i].std.alg; chan[i].autoEnvDen=chan[i].std.alg.val;
chan[i].freqChanged=true; 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) { if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true); chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true);
@ -314,7 +314,7 @@ int DivPlatformAY8910::dispatch(DivCommand c) {
break; break;
case DIV_CMD_VOLUME: { case DIV_CMD_VOLUME: {
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].outVol=c.value;
} }
if (isMuted[c.chan]) { if (isMuted[c.chan]) {
@ -431,11 +431,11 @@ int DivPlatformAY8910::dispatch(DivCommand c) {
if (c.value) { // port B if (c.value) { // port B
ioPortB=true; ioPortB=true;
portBVal=c.value2; 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 } else { // port A
ioPortA=true; ioPortA=true;
portAVal=c.value2; portAVal=c.value2;
logI("AY I/O port A write: %x\n",portAVal); logI("AY I/O port A write: %x",portAVal);
} }
updateOutSel(true); updateOutSel(true);
immWrite(14+(c.value?1:0),(c.value?portBVal:portAVal)); immWrite(14+(c.value?1:0),(c.value?portBVal:portAVal));
@ -497,6 +497,10 @@ void DivPlatformAY8910::flushWrites() {
while (!writes.empty()) writes.pop(); while (!writes.empty()) writes.pop();
} }
bool DivPlatformAY8910::getDCOffRequired() {
return true;
}
void DivPlatformAY8910::reset() { void DivPlatformAY8910::reset() {
while (!writes.empty()) writes.pop(); while (!writes.empty()) writes.pop();
ay->device_reset(); ay->device_reset();

View file

@ -95,6 +95,7 @@ class DivPlatformAY8910: public DivDispatch {
void setFlags(unsigned int flags); void setFlags(unsigned int flags);
bool isStereo(); bool isStereo();
bool keyOffAffectsArp(int ch); bool keyOffAffectsArp(int ch);
bool getDCOffRequired();
void notifyInsDeletion(void* ins); void notifyInsDeletion(void* ins);
void poke(unsigned int addr, unsigned short val); void poke(unsigned int addr, unsigned short val);
void poke(std::vector<DivRegWrite>& wlist); void poke(std::vector<DivRegWrite>& wlist);

View file

@ -123,7 +123,7 @@ void DivPlatformAY8930::acquire(short* bufL, short* bufR, size_t start, size_t l
} }
while (!writes.empty()) { while (!writes.empty()) {
QueuedWrite w=writes.front(); QueuedWrite w=writes.front();
if (bank!=(w.addr>>4)) { if ((int)bank!=(w.addr>>4)) {
bank=w.addr>>4; bank=w.addr>>4;
ay->address_w(0x0d); ay->address_w(0x0d);
ay->data_w(0xa0|(bank<<4)|ayEnvMode[0]); ay->data_w(0xa0|(bank<<4)|ayEnvMode[0]);
@ -191,8 +191,8 @@ void DivPlatformAY8930::tick() {
// PSG // PSG
for (int i=0; i<3; i++) { for (int i=0; i<3; i++) {
chan[i].std.next(); chan[i].std.next();
if (chan[i].std.hadVol) { if (chan[i].std.vol.had) {
chan[i].outVol=MIN(31,chan[i].std.vol)-(31-(chan[i].vol&31)); 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 (chan[i].outVol<0) chan[i].outVol=0;
if (isMuted[i]) { if (isMuted[i]) {
rWrite(0x08+i,0); rWrite(0x08+i,0);
@ -200,55 +200,55 @@ void DivPlatformAY8930::tick() {
rWrite(0x08+i,(chan[i].outVol&31)|((chan[i].psgMode&4)<<3)); 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].inPorta) {
if (chan[i].std.arpMode) { if (chan[i].std.arp.mode) {
chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp); chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val);
} else { } 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; chan[i].freqChanged=true;
} else { } 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].baseFreq=NOTE_PERIODIC(chan[i].note);
chan[i].freqChanged=true; chan[i].freqChanged=true;
} }
} }
if (chan[i].std.hadDuty) { if (chan[i].std.duty.had) {
rWrite(0x06,chan[i].std.duty); rWrite(0x06,chan[i].std.duty.val);
} }
if (chan[i].std.hadWave) { if (chan[i].std.wave.had) {
chan[i].psgMode=(chan[i].std.wave+1)&7; chan[i].psgMode=(chan[i].std.wave.val+1)&7;
if (isMuted[i]) { if (isMuted[i]) {
rWrite(0x08+i,0); rWrite(0x08+i,0);
} else { } else {
rWrite(0x08+i,(chan[i].outVol&31)|((chan[i].psgMode&4)<<3)); rWrite(0x08+i,(chan[i].outVol&31)|((chan[i].psgMode&4)<<3));
} }
} }
if (chan[i].std.hadEx1) { // duty if (chan[i].std.ex1.had) { // duty
rWrite(0x16+i,chan[i].std.ex1); rWrite(0x16+i,chan[i].std.ex1.val);
} }
if (chan[i].std.hadEx2) { if (chan[i].std.ex2.had) {
ayEnvMode[i]=chan[i].std.ex2; ayEnvMode[i]=chan[i].std.ex2.val;
rWrite(regMode[i],ayEnvMode[i]); rWrite(regMode[i],ayEnvMode[i]);
} }
if (chan[i].std.hadEx3) { if (chan[i].std.ex3.had) {
chan[i].autoEnvNum=chan[i].std.ex3; chan[i].autoEnvNum=chan[i].std.ex3.val;
chan[i].freqChanged=true; 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) { if (chan[i].std.alg.had) {
chan[i].autoEnvDen=chan[i].std.alg; chan[i].autoEnvDen=chan[i].std.alg.val;
chan[i].freqChanged=true; 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) { if (chan[i].std.fb.had) {
ayNoiseAnd=chan[i].std.fb; ayNoiseAnd=chan[i].std.fb.val;
immWrite(0x19,ayNoiseAnd); immWrite(0x19,ayNoiseAnd);
} }
if (chan[i].std.hadFms) { if (chan[i].std.fms.had) {
ayNoiseOr=chan[i].std.fms; ayNoiseOr=chan[i].std.fms.val;
immWrite(0x1a,ayNoiseOr); immWrite(0x1a,ayNoiseOr);
} }
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { 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].freq>65535) chan[i].freq=65535;
if (chan[i].keyOn) { if (chan[i].keyOn) {
if (chan[i].insChanged) { 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; chan[i].insChanged=false;
} }
} }
@ -336,7 +336,7 @@ int DivPlatformAY8930::dispatch(DivCommand c) {
break; break;
case DIV_CMD_VOLUME: { case DIV_CMD_VOLUME: {
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].outVol=c.value;
} }
if (isMuted[c.chan]) { if (isMuted[c.chan]) {
@ -456,11 +456,11 @@ int DivPlatformAY8930::dispatch(DivCommand c) {
if (c.value) { // port B if (c.value) { // port B
ioPortB=true; ioPortB=true;
portBVal=c.value2; 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 } else { // port A
ioPortA=true; ioPortA=true;
portAVal=c.value2; portAVal=c.value2;
logI("AY I/O port A write: %x\n",portAVal); logI("AY I/O port A write: %x",portAVal);
} }
updateOutSel(true); updateOutSel(true);
immWrite(14+(c.value?1:0),(c.value?portBVal:portAVal)); immWrite(14+(c.value?1:0),(c.value?portBVal:portAVal));

View file

@ -84,28 +84,28 @@ void DivPlatformBubSysWSG::updateWave(int ch) {
void DivPlatformBubSysWSG::tick() { void DivPlatformBubSysWSG::tick() {
for (int i=0; i<2; i++) { for (int i=0; i<2; i++) {
chan[i].std.next(); chan[i].std.next();
if (chan[i].std.hadVol) { if (chan[i].std.vol.had) {
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;
rWrite(2+i,(chan[i].wave<<5)|chan[i].outVol); 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].inPorta) {
if (chan[i].std.arpMode) { if (chan[i].std.arp.mode) {
chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp); chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val);
} else { } 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; chan[i].freqChanged=true;
} else { } 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].baseFreq=NOTE_PERIODIC(chan[i].note);
chan[i].freqChanged=true; chan[i].freqChanged=true;
} }
} }
if (chan[i].std.hadWave) { if (chan[i].std.wave.had) {
if (chan[i].wave!=chan[i].std.wave || chan[i].ws.activeChanged()) { if (chan[i].wave!=chan[i].std.wave.val || chan[i].ws.activeChanged()) {
chan[i].wave=chan[i].std.wave; chan[i].wave=chan[i].std.wave.val;
chan[i].ws.changeWave1(chan[i].wave); chan[i].ws.changeWave1(chan[i].wave);
if (!chan[i].keyOff) chan[i].keyOn=true; if (!chan[i].keyOff) chan[i].keyOn=true;
} }
@ -174,14 +174,14 @@ int DivPlatformBubSysWSG::dispatch(DivCommand c) {
case DIV_CMD_VOLUME: case DIV_CMD_VOLUME:
if (chan[c.chan].vol!=c.value) { if (chan[c.chan].vol!=c.value) {
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].outVol=c.value;
if (chan[c.chan].active) rWrite(2+c.chan,(chan[c.chan].wave<<5)|chan[c.chan].outVol); if (chan[c.chan].active) rWrite(2+c.chan,(chan[c.chan].wave<<5)|chan[c.chan].outVol);
} }
} }
break; break;
case DIV_CMD_GET_VOLUME: 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].vol;
} }
return chan[c.chan].outVol; return chan[c.chan].outVol;
@ -219,7 +219,7 @@ int DivPlatformBubSysWSG::dispatch(DivCommand c) {
break; break;
} }
case DIV_CMD_LEGATO: 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].freqChanged=true;
chan[c.chan].note=c.value; chan[c.chan].note=c.value;
break; break;

View file

@ -118,50 +118,50 @@ void DivPlatformC64::acquire(short* bufL, short* bufR, size_t start, size_t len)
void DivPlatformC64::updateFilter() { void DivPlatformC64::updateFilter() {
rWrite(0x15,filtCut&7); rWrite(0x15,filtCut&7);
rWrite(0x16,filtCut>>3); 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); rWrite(0x18,(filtControl<<4)|vol);
} }
void DivPlatformC64::tick() { void DivPlatformC64::tick() {
for (int i=0; i<3; i++) { for (int i=0; i<3; i++) {
chan[i].std.next(); chan[i].std.next();
if (chan[i].std.hadVol) { if (chan[i].std.vol.had) {
DivInstrument* ins=parent->getIns(chan[i].ins); DivInstrument* ins=parent->getIns(chan[i].ins);
if (ins->c64.volIsCutoff) { if (ins->c64.volIsCutoff) {
if (ins->c64.filterIsAbs) { if (ins->c64.filterIsAbs) {
filtCut=MIN(2047,chan[i].std.vol); filtCut=MIN(2047,chan[i].std.vol.val);
} else { } 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>2047) filtCut=2047;
if (filtCut<0) filtCut=0; if (filtCut<0) filtCut=0;
} }
updateFilter(); updateFilter();
} else { } else {
vol=MIN(15,chan[i].std.vol); vol=MIN(15,chan[i].std.vol.val);
updateFilter(); updateFilter();
} }
} }
if (chan[i].std.hadArp) { if (chan[i].std.arp.had) {
if (!chan[i].inPorta) { if (!chan[i].inPorta) {
if (chan[i].std.arpMode) { if (chan[i].std.arp.mode) {
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].std.arp); chan[i].baseFreq=NOTE_FREQUENCY(chan[i].std.arp.val);
} else { } 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; chan[i].freqChanged=true;
} else { } 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].baseFreq=NOTE_FREQUENCY(chan[i].note);
chan[i].freqChanged=true; chan[i].freqChanged=true;
} }
} }
if (chan[i].std.hadDuty) { if (chan[i].std.duty.had) {
DivInstrument* ins=parent->getIns(chan[i].ins); DivInstrument* ins=parent->getIns(chan[i].ins);
if (ins->c64.dutyIsAbs) { if (ins->c64.dutyIsAbs) {
chan[i].duty=chan[i].std.duty; chan[i].duty=chan[i].std.duty.val;
} else { } 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+2,chan[i].duty&0xff);
rWrite(i*7+3,chan[i].duty>>8); rWrite(i*7+3,chan[i].duty>>8);
@ -175,21 +175,21 @@ void DivPlatformC64::tick() {
} }
} }
} }
if (chan[i].std.hadWave) { if (chan[i].std.wave.had) {
chan[i].wave=chan[i].std.wave; chan[i].wave=chan[i].std.wave.val;
rWrite(i*7+4,(isMuted[i]?8:(chan[i].wave<<4))|(chan[i].ring<<2)|(chan[i].sync<<1)|chan[i].active); 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) { if (chan[i].std.ex1.had) {
filtControl=chan[i].std.ex1&15; filtControl=chan[i].std.ex1.val&15;
updateFilter(); updateFilter();
} }
if (chan[i].std.hadEx2) { if (chan[i].std.ex2.had) {
filtRes=chan[i].std.ex2&15; filtRes=chan[i].std.ex2.val&15;
updateFilter(); updateFilter();
} }
if (chan[i].std.hadEx3) { if (chan[i].std.ex3.had) {
chan[i].sync=chan[i].std.ex3&1; chan[i].sync=chan[i].std.ex3.val&1;
chan[i].ring=chan[i].std.ex3&2; chan[i].ring=chan[i].std.ex3.val&2;
chan[i].freqChanged=true; chan[i].freqChanged=true;
} }
@ -226,13 +226,13 @@ int DivPlatformC64::dispatch(DivCommand c) {
} }
chan[c.chan].active=true; chan[c.chan].active=true;
chan[c.chan].keyOn=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; chan[c.chan].duty=ins->c64.duty;
rWrite(c.chan*7+2,chan[c.chan].duty&0xff); rWrite(c.chan*7+2,chan[c.chan].duty&0xff);
rWrite(c.chan*7+3,chan[c.chan].duty>>8); rWrite(c.chan*7+3,chan[c.chan].duty>>8);
} }
if (chan[c.chan].insChanged) { 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].attack=ins->c64.a;
chan[c.chan].decay=(ins->c64.s==15)?0:ins->c64.d; chan[c.chan].decay=(ins->c64.s==15)?0:ins->c64.d;
chan[c.chan].sustain=ins->c64.s; chan[c.chan].sustain=ins->c64.s;
@ -245,7 +245,7 @@ int DivPlatformC64::dispatch(DivCommand c) {
if (ins->c64.initFilter) { if (ins->c64.initFilter) {
filtCut=ins->c64.cut; filtCut=ins->c64.cut;
filtRes=ins->c64.res; 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(); updateFilter();
} }
@ -279,7 +279,7 @@ int DivPlatformC64::dispatch(DivCommand c) {
case DIV_CMD_VOLUME: case DIV_CMD_VOLUME:
if (chan[c.chan].vol!=c.value) { if (chan[c.chan].vol!=c.value) {
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].outVol=c.value;
vol=chan[c.chan].outVol; vol=chan[c.chan].outVol;
} else { } else {
@ -330,10 +330,10 @@ int DivPlatformC64::dispatch(DivCommand c) {
break; break;
case DIV_CMD_WAVE: case DIV_CMD_WAVE:
chan[c.chan].wave=c.value; 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; break;
case DIV_CMD_LEGATO: 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].freqChanged=true;
chan[c.chan].note=c.value; chan[c.chan].note=c.value;
break; break;
@ -411,11 +411,11 @@ int DivPlatformC64::dispatch(DivCommand c) {
break; break;
case 4: case 4:
chan[c.chan].ring=c.value; 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; break;
case 5: case 5:
chan[c.chan].sync=c.value; 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; break;
case 6: case 6:
filtControl&=7; filtControl&=7;
@ -434,7 +434,7 @@ int DivPlatformC64::dispatch(DivCommand c) {
void DivPlatformC64::muteChannel(int ch, bool mute) { void DivPlatformC64::muteChannel(int ch, bool mute) {
isMuted[ch]=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() { void DivPlatformC64::forceIns() {

View file

@ -100,40 +100,40 @@ void DivPlatformFDS::updateWave() {
void DivPlatformFDS::tick() { void DivPlatformFDS::tick() {
for (int i=0; i<1; i++) { for (int i=0; i<1; i++) {
chan[i].std.next(); chan[i].std.next();
if (chan[i].std.hadVol) { if (chan[i].std.vol.had) {
// ok, why are the volumes like that? // 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; if (chan[i].outVol<0) chan[i].outVol=0;
rWrite(0x4080,0x80|chan[i].outVol); rWrite(0x4080,0x80|chan[i].outVol);
} }
if (chan[i].std.hadArp) { if (chan[i].std.arp.had) {
if (i==3) { // noise if (i==3) { // noise
if (chan[i].std.arpMode) { if (chan[i].std.arp.mode) {
chan[i].baseFreq=chan[i].std.arp; chan[i].baseFreq=chan[i].std.arp.val;
} else { } 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>255) chan[i].baseFreq=255;
if (chan[i].baseFreq<0) chan[i].baseFreq=0; if (chan[i].baseFreq<0) chan[i].baseFreq=0;
} else { } else {
if (!chan[i].inPorta) { if (!chan[i].inPorta) {
if (chan[i].std.arpMode) { if (chan[i].std.arp.mode) {
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].std.arp); chan[i].baseFreq=NOTE_FREQUENCY(chan[i].std.arp.val);
} else { } 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; chan[i].freqChanged=true;
} else { } 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].baseFreq=NOTE_FREQUENCY(chan[i].note);
chan[i].freqChanged=true; chan[i].freqChanged=true;
} }
} }
/* /*
if (chan[i].std.hadDuty) { if (chan[i].std.duty.had) {
chan[i].duty=chan[i].std.duty; chan[i].duty=chan[i].std.duty.val;
if (i==3) { if (i==3) {
if (parent->song.properNoiseLayout) { if (parent->song.properNoiseLayout) {
chan[i].duty&=1; chan[i].duty&=1;
@ -148,9 +148,9 @@ void DivPlatformFDS::tick() {
chan[i].freqChanged=true; chan[i].freqChanged=true;
} }
}*/ }*/
if (chan[i].std.hadWave) { if (chan[i].std.wave.had) {
if (chan[i].wave!=chan[i].std.wave || ws.activeChanged()) { if (chan[i].wave!=chan[i].std.wave.val || ws.activeChanged()) {
chan[i].wave=chan[i].std.wave; chan[i].wave=chan[i].std.wave.val;
ws.changeWave1(chan[i].wave); ws.changeWave1(chan[i].wave);
//if (!chan[i].keyOff) chan[i].keyOn=true; //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].keyOff) chan[i].keyOn=true;
} }
} }
if (chan[i].std.hadEx1) { // mod depth if (chan[i].std.ex1.had) { // mod depth
chan[i].modOn=chan[i].std.ex1; chan[i].modOn=chan[i].std.ex1.val;
chan[i].modDepth=chan[i].std.ex1; chan[i].modDepth=chan[i].std.ex1.val;
rWrite(0x4084,(chan[i].modOn<<7)|0x40|chan[i].modDepth); rWrite(0x4084,(chan[i].modOn<<7)|0x40|chan[i].modDepth);
} }
if (chan[i].std.hadEx2) { // mod speed if (chan[i].std.ex2.had) { // mod speed
chan[i].modFreq=chan[i].std.ex2; chan[i].modFreq=chan[i].std.ex2.val;
rWrite(0x4086,chan[i].modFreq&0xff); rWrite(0x4086,chan[i].modFreq&0xff);
rWrite(0x4087,chan[i].modFreq>>8); rWrite(0x4087,chan[i].modFreq>>8);
} }
if (chan[i].std.hadEx3) { // mod position if (chan[i].std.ex3.had) { // mod position
chan[i].modPos=chan[i].std.ex3; chan[i].modPos=chan[i].std.ex3.val;
rWrite(0x4087,0x80|chan[i].modFreq>>8); rWrite(0x4087,0x80|chan[i].modFreq>>8);
rWrite(0x4085,chan[i].modPos); rWrite(0x4085,chan[i].modPos);
rWrite(0x4087,chan[i].modFreq>>8); rWrite(0x4087,chan[i].modFreq>>8);
@ -276,7 +276,7 @@ int DivPlatformFDS::dispatch(DivCommand c) {
case DIV_CMD_VOLUME: case DIV_CMD_VOLUME:
if (chan[c.chan].vol!=c.value) { if (chan[c.chan].vol!=c.value) {
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].outVol=c.value;
} }
rWrite(0x4080,0x80|chan[c.chan].vol); rWrite(0x4080,0x80|chan[c.chan].vol);
@ -359,7 +359,7 @@ int DivPlatformFDS::dispatch(DivCommand c) {
} }
case DIV_CMD_LEGATO: case DIV_CMD_LEGATO:
if (c.chan==3) break; 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].freqChanged=true;
chan[c.chan].note=c.value; chan[c.chan].note=c.value;
break; break;

View file

@ -149,45 +149,45 @@ static unsigned char noiseTable[256]={
void DivPlatformGB::tick() { void DivPlatformGB::tick() {
for (int i=0; i<4; i++) { for (int i=0; i<4; i++) {
chan[i].std.next(); chan[i].std.next();
if (chan[i].std.hadArp) { if (chan[i].std.arp.had) {
if (i==3) { // noise if (i==3) { // noise
if (chan[i].std.arpMode) { if (chan[i].std.arp.mode) {
chan[i].baseFreq=chan[i].std.arp+24; chan[i].baseFreq=chan[i].std.arp.val+24;
} else { } 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>255) chan[i].baseFreq=255;
if (chan[i].baseFreq<0) chan[i].baseFreq=0; if (chan[i].baseFreq<0) chan[i].baseFreq=0;
} else { } else {
if (!chan[i].inPorta) { if (!chan[i].inPorta) {
if (chan[i].std.arpMode) { if (chan[i].std.arp.mode) {
chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp+24); chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val+24);
} else { } 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; chan[i].freqChanged=true;
} else { } 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].baseFreq=NOTE_PERIODIC(chan[i].note);
chan[i].freqChanged=true; chan[i].freqChanged=true;
} }
} }
if (chan[i].std.hadDuty) { if (chan[i].std.duty.had) {
chan[i].duty=chan[i].std.duty; chan[i].duty=chan[i].std.duty.val;
DivInstrument* ins=parent->getIns(chan[i].ins); DivInstrument* ins=parent->getIns(chan[i].ins);
if (i!=2) { if (i!=2) {
rWrite(16+i*5+1,((chan[i].duty&3)<<6)|(63-(ins->gb.soundLen&63))); rWrite(16+i*5+1,((chan[i].duty&3)<<6)|(63-(ins->gb.soundLen&63)));
} else { } else {
if (parent->song.waveDutyIsVol) { 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 (i==2 && chan[i].std.wave.had) {
if (chan[i].wave!=chan[i].std.wave || ws.activeChanged()) { if (chan[i].wave!=chan[i].std.wave.val || ws.activeChanged()) {
chan[i].wave=chan[i].std.wave; chan[i].wave=chan[i].std.wave.val;
ws.changeWave1(chan[i].wave); ws.changeWave1(chan[i].wave);
if (!chan[i].keyOff) chan[i].keyOn=true; if (!chan[i].keyOff) chan[i].keyOn=true;
} }
@ -359,7 +359,7 @@ int DivPlatformGB::dispatch(DivCommand c) {
} }
case DIV_CMD_LEGATO: case DIV_CMD_LEGATO:
if (c.chan==3) break; 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].freqChanged=true;
chan[c.chan].note=c.value; chan[c.chan].note=c.value;
break; break;

View file

@ -74,9 +74,9 @@ const char* DivPlatformGenesis::getEffectName(unsigned char effect) {
case 0x1d: case 0x1d:
return "1Dxx: Set attack of operator 4 (0 to 1F)"; return "1Dxx: Set attack of operator 4 (0 to 1F)";
break; break;
case 0x20: case 0x30:
return "20xy: Set PSG noise mode (x: preset freq/ch3 freq; y: thin pulse/noise)"; return "30xx: Toggle hard envelope reset on new notes";
break; break;
} }
return NULL; return NULL;
} }
@ -225,8 +225,8 @@ void DivPlatformGenesis::tick() {
if (i==2 && extMode) continue; if (i==2 && extMode) continue;
chan[i].std.next(); chan[i].std.next();
if (chan[i].std.hadVol) { if (chan[i].std.vol.had) {
chan[i].outVol=(chan[i].vol*MIN(127,chan[i].std.vol))/127; chan[i].outVol=(chan[i].vol*MIN(127,chan[i].std.vol.val))/127;
for (int j=0; j<4; j++) { for (int j=0; j<4; j++) {
unsigned short baseAddr=chanOffs[i]|opOffs[j]; unsigned short baseAddr=chanOffs[i]|opOffs[j];
DivInstrumentFM::Operator& op=chan[i].state.op[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].inPorta) {
if (chan[i].std.arpMode) { if (chan[i].std.arp.mode) {
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].std.arp); chan[i].baseFreq=NOTE_FREQUENCY(chan[i].std.arp.val);
} else { } 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; chan[i].freqChanged=true;
} else { } 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].baseFreq=NOTE_FREQUENCY(chan[i].note);
chan[i].freqChanged=true; chan[i].freqChanged=true;
} }
} }
if (chan[i].std.hadAlg) { if (chan[i].std.alg.had) {
chan[i].state.alg=chan[i].std.alg; 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)); 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++) { if (!parent->song.algMacroBehavior) for (int j=0; j<4; j++) {
unsigned short baseAddr=chanOffs[i]|opOffs[j]; unsigned short baseAddr=chanOffs[i]|opOffs[j];
@ -275,48 +275,48 @@ void DivPlatformGenesis::tick() {
} }
} }
} }
if (chan[i].std.hadFb) { if (chan[i].std.fb.had) {
chan[i].state.fb=chan[i].std.fb; 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)); rWrite(chanOffs[i]+ADDR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3));
} }
if (chan[i].std.hadFms) { if (chan[i].std.fms.had) {
chan[i].state.fms=chan[i].std.fms; 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)); 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) { if (chan[i].std.ams.had) {
chan[i].state.ams=chan[i].std.ams; 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)); 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++) { for (int j=0; j<4; j++) {
unsigned short baseAddr=chanOffs[i]|opOffs[j]; unsigned short baseAddr=chanOffs[i]|opOffs[j];
DivInstrumentFM::Operator& op=chan[i].state.op[j]; DivInstrumentFM::Operator& op=chan[i].state.op[j];
DivMacroInt::IntOp& m=chan[i].std.op[j]; DivMacroInt::IntOp& m=chan[i].std.op[j];
if (m.hadAm) { if (m.am.had) {
op.am=m.am; op.am=m.am.val;
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7)); rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
} }
if (m.hadAr) { if (m.ar.had) {
op.ar=m.ar; op.ar=m.ar.val;
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6)); rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6));
} }
if (m.hadDr) { if (m.dr.had) {
op.dr=m.dr; op.dr=m.dr.val;
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7)); rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
} }
if (m.hadMult) { if (m.mult.had) {
op.mult=m.mult; op.mult=m.mult.val;
rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4)); rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4));
} }
if (m.hadRr) { if (m.rr.had) {
op.rr=m.rr; op.rr=m.rr.val;
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4)); rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
} }
if (m.hadSl) { if (m.sl.had) {
op.sl=m.sl; op.sl=m.sl.val;
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4)); rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
} }
if (m.hadTl) { if (m.tl.had) {
op.tl=127-m.tl; op.tl=127-m.tl.val;
if (isMuted[i]) { if (isMuted[i]) {
rWrite(baseAddr+ADDR_TL,127); rWrite(baseAddr+ADDR_TL,127);
} else { } else {
@ -327,26 +327,44 @@ void DivPlatformGenesis::tick() {
} }
} }
} }
if (m.hadRs) { if (m.rs.had) {
op.rs=m.rs; op.rs=m.rs.val;
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6)); rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6));
} }
if (m.hadDt) { if (m.dt.had) {
op.dt=m.dt; op.dt=m.dt.val;
rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4)); rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4));
} }
if (m.hadD2r) { if (m.d2r.had) {
op.d2r=m.d2r; op.d2r=m.d2r.val;
rWrite(baseAddr+ADDR_DT2_D2R,op.d2r&31); rWrite(baseAddr+ADDR_DT2_D2R,op.d2r&31);
} }
if (m.hadSsg) { if (m.ssg.had) {
op.ssgEnv=m.ssg; op.ssgEnv=m.ssg.val;
rWrite(baseAddr+ADDR_SSG,op.ssgEnv&15); rWrite(baseAddr+ADDR_SSG,op.ssgEnv&15);
} }
} }
if (chan[i].keyOn || chan[i].keyOff) { 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]); 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; chan[i].keyOff=false;
} }
} }
@ -505,7 +523,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
} }
chan[c.chan].std.init(ins); 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; chan[c.chan].outVol=chan[c.chan].vol;
} }
@ -578,7 +596,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
break; break;
case DIV_CMD_VOLUME: { case DIV_CMD_VOLUME: {
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].outVol=c.value;
} }
for (int i=0; i<4; i++) { 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]]; unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6)); rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6));
} }
break; break;
} }
case DIV_CMD_FM_HARD_RESET:
chan[c.chan].hardReset=c.value;
break;
case DIV_ALWAYS_SET_VOLUME: case DIV_ALWAYS_SET_VOLUME:
return 0; return 0;
break; break;

View file

@ -38,7 +38,7 @@ class DivPlatformGenesis: public DivDispatch {
unsigned char freqH, freqL; unsigned char freqH, freqL;
int freq, baseFreq, pitch, note; int freq, baseFreq, pitch, note;
unsigned char ins; 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; int vol, outVol;
unsigned char pan; unsigned char pan;
Channel(): Channel():
@ -57,6 +57,7 @@ class DivPlatformGenesis: public DivDispatch {
portaPause(false), portaPause(false),
furnaceDac(false), furnaceDac(false),
inPorta(false), inPorta(false),
hardReset(false),
vol(0), vol(0),
pan(3) {} pan(3) {}
}; };

View file

@ -148,23 +148,23 @@ void DivPlatformLynx::acquire(short* bufL, short* bufR, size_t start, size_t len
void DivPlatformLynx::tick() { void DivPlatformLynx::tick() {
for (int i=0; i<4; i++) { for (int i=0; i<4; i++) {
chan[i].std.next(); chan[i].std.next();
if (chan[i].std.hadVol) { if (chan[i].std.vol.had) {
chan[i].outVol=((chan[i].vol&127)*MIN(127,chan[i].std.vol))>>7; 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))); 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].inPorta) {
if (chan[i].std.arpMode) { if (chan[i].std.arp.mode) {
chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp); chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val);
chan[i].actualNote=chan[i].std.arp; chan[i].actualNote=chan[i].std.arp.val;
} else { } 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].actualNote=chan[i].note+chan[i].std.arp; chan[i].actualNote=chan[i].note+chan[i].std.arp.val;
} }
chan[i].freqChanged=true; chan[i].freqChanged=true;
} }
} else { } 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].baseFreq=NOTE_PERIODIC(chan[i].note);
chan[i].actualNote=chan[i].note; chan[i].actualNote=chan[i].note;
chan[i].freqChanged=true; chan[i].freqChanged=true;
@ -178,15 +178,15 @@ void DivPlatformLynx::tick() {
chan[i].lfsr=-1; chan[i].lfsr=-1;
} }
chan[i].fd=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true); chan[i].fd=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true);
if (chan[i].std.hadDuty) { if (chan[i].std.duty.had) {
chan[i].duty=chan[i].std.duty; chan[i].duty=chan[i].std.duty.val;
WRITE_FEEDBACK(i, chan[i].duty.feedback); WRITE_FEEDBACK(i, chan[i].duty.feedback);
} }
WRITE_CONTROL(i, (chan[i].fd.clockDivider|0x18|chan[i].duty.int_feedback7)); WRITE_CONTROL(i, (chan[i].fd.clockDivider|0x18|chan[i].duty.int_feedback7));
WRITE_BACKUP( i, chan[i].fd.backup ); WRITE_BACKUP( i, chan[i].fd.backup );
} }
else if (chan[i].std.hadDuty) { else if (chan[i].std.duty.had) {
chan[i].duty = chan[i].std.duty; chan[i].duty = chan[i].std.duty.val;
WRITE_FEEDBACK(i, chan[i].duty.feedback); WRITE_FEEDBACK(i, chan[i].duty.feedback);
WRITE_CONTROL(i, (chan[i].fd.clockDivider|0x18|chan[i].duty.int_feedback7)); 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: case DIV_CMD_VOLUME:
if (chan[c.chan].vol!=c.value) { if (chan[c.chan].vol!=c.value) {
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].outVol=c.value;
} }
if (chan[c.chan].active) WRITE_VOLUME(c.chan,(isMuted[c.chan]?0:(chan[c.chan].vol&127))); 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); WRITE_ATTEN(c.chan,chan[c.chan].pan);
break; break;
case DIV_CMD_GET_VOLUME: 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].vol;
} }
return chan[c.chan].outVol; return chan[c.chan].outVol;
@ -272,7 +272,7 @@ int DivPlatformLynx::dispatch(DivCommand c) {
break; break;
} }
case DIV_CMD_LEGATO: 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].freqChanged=true;
chan[c.chan].note=c.value; chan[c.chan].note=c.value;
chan[c.chan].actualNote=c.value; chan[c.chan].actualNote=c.value;

View file

@ -89,7 +89,6 @@ void DivPlatformMMC5::acquire(short* bufL, short* bufR, size_t start, size_t len
if (!isMuted[2]) { if (!isMuted[2]) {
sample+=mmc5->pcm.output*2; sample+=mmc5->pcm.output*2;
} }
sample=(sample-128)<<6;
if (sample>32767) sample=32767; if (sample>32767) sample=32767;
if (sample<-32768) sample=-32768; if (sample<-32768) sample=-32768;
bufL[i]=sample; bufL[i]=sample;
@ -99,29 +98,29 @@ void DivPlatformMMC5::acquire(short* bufL, short* bufR, size_t start, size_t len
void DivPlatformMMC5::tick() { void DivPlatformMMC5::tick() {
for (int i=0; i<2; i++) { for (int i=0; i<2; i++) {
chan[i].std.next(); chan[i].std.next();
if (chan[i].std.hadVol) { if (chan[i].std.vol.had) {
// ok, why are the volumes like that? // 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 (chan[i].outVol<0) chan[i].outVol=0;
rWrite(0x5000+i*4,0x30|chan[i].outVol|((chan[i].duty&3)<<6)); 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].inPorta) {
if (chan[i].std.arpMode) { if (chan[i].std.arp.mode) {
chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp); chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val);
} else { } 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; chan[i].freqChanged=true;
} else { } 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].baseFreq=NOTE_PERIODIC(chan[i].note);
chan[i].freqChanged=true; chan[i].freqChanged=true;
} }
} }
if (chan[i].std.hadDuty) { if (chan[i].std.duty.had) {
chan[i].duty=chan[i].std.duty; chan[i].duty=chan[i].std.duty.val;
rWrite(0x5000+i*4,0x30|chan[i].outVol|((chan[i].duty&3)<<6)); rWrite(0x5000+i*4,0x30|chan[i].outVol|((chan[i].duty&3)<<6));
} }
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
@ -243,7 +242,7 @@ int DivPlatformMMC5::dispatch(DivCommand c) {
case DIV_CMD_VOLUME: case DIV_CMD_VOLUME:
if (chan[c.chan].vol!=c.value) { if (chan[c.chan].vol!=c.value) {
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].outVol=c.value;
} }
if (chan[c.chan].active) { if (chan[c.chan].active) {
@ -291,7 +290,7 @@ int DivPlatformMMC5::dispatch(DivCommand c) {
} }
break; break;
case DIV_CMD_LEGATO: 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].freqChanged=true;
chan[c.chan].note=c.value; chan[c.chan].note=c.value;
break; break;
@ -336,6 +335,10 @@ int DivPlatformMMC5::getRegisterPoolSize() {
return 32; return 32;
} }
float DivPlatformMMC5::getPostAmp() {
return 64.0f;
}
void DivPlatformMMC5::reset() { void DivPlatformMMC5::reset() {
for (int i=0; i<3; i++) { for (int i=0; i<3; i++) {
chan[i]=DivPlatformMMC5::Channel(); chan[i]=DivPlatformMMC5::Channel();

View file

@ -74,6 +74,7 @@ class DivPlatformMMC5: public DivDispatch {
void tick(); void tick();
void muteChannel(int ch, bool mute); void muteChannel(int ch, bool mute);
bool keyOffAffectsArp(int ch); bool keyOffAffectsArp(int ch);
float getPostAmp();
void setFlags(unsigned int flags); void setFlags(unsigned int flags);
void notifyInsDeletion(void* ins); void notifyInsDeletion(void* ins);
void poke(unsigned int addr, unsigned short val); void poke(unsigned int addr, unsigned short val);

View file

@ -203,8 +203,8 @@ void DivPlatformN163::updateWaveCh(int ch) {
void DivPlatformN163::tick() { void DivPlatformN163::tick() {
for (int i=0; i<=chanMax; i++) { for (int i=0; i<=chanMax; i++) {
chan[i].std.next(); chan[i].std.next();
if (chan[i].std.hadVol) { if (chan[i].std.vol.had) {
chan[i].outVol=(MIN(15,chan[i].std.vol)*(chan[i].vol&15))/15; 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<0) chan[i].outVol=0;
if (chan[i].outVol>15) chan[i].outVol=15; if (chan[i].outVol>15) chan[i].outVol=15;
if (chan[i].resVol!=chan[i].outVol) { 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].inPorta) {
if (chan[i].std.arpMode) { if (chan[i].std.arp.mode) {
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].std.arp); chan[i].baseFreq=NOTE_FREQUENCY(chan[i].std.arp.val);
} else { } 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; chan[i].freqChanged=true;
} else { } 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].baseFreq=NOTE_FREQUENCY(chan[i].note);
chan[i].freqChanged=true; chan[i].freqChanged=true;
} }
} }
if (chan[i].std.hadDuty) { if (chan[i].std.duty.had) {
if (chan[i].wavePos!=chan[i].std.duty) { if (chan[i].wavePos!=chan[i].std.duty.val) {
chan[i].wavePos=chan[i].std.duty; chan[i].wavePos=chan[i].std.duty.val;
if (chan[i].waveMode&0x2) { if (chan[i].waveMode&0x2) {
chan[i].waveUpdated=true; chan[i].waveUpdated=true;
} }
chan[i].waveChanged=true; chan[i].waveChanged=true;
} }
} }
if (chan[i].std.hadWave) { if (chan[i].std.wave.had) {
if (chan[i].wave!=chan[i].std.wave) { if (chan[i].wave!=chan[i].std.wave.val) {
chan[i].wave=chan[i].std.wave; chan[i].wave=chan[i].std.wave.val;
if (chan[i].waveMode&0x2) { if (chan[i].waveMode&0x2) {
chan[i].waveUpdated=true; chan[i].waveUpdated=true;
} }
} }
} }
if (chan[i].std.hadEx1) { if (chan[i].std.ex1.had) {
if (chan[i].waveLen!=(chan[i].std.ex1&0xfc)) { if (chan[i].waveLen!=(chan[i].std.ex1.val&0xfc)) {
chan[i].waveLen=chan[i].std.ex1&0xfc; chan[i].waveLen=chan[i].std.ex1.val&0xfc;
if (chan[i].waveMode&0x2) { if (chan[i].waveMode&0x2) {
chan[i].waveUpdated=true; chan[i].waveUpdated=true;
} }
chan[i].freqChanged=true; chan[i].freqChanged=true;
} }
} }
if (chan[i].std.hadEx2) { if (chan[i].std.ex2.had) {
if ((chan[i].waveMode&0x2)!=(chan[i].std.ex2&0x2)) { // update when every waveform changed 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&0x2); chan[i].waveMode=(chan[i].waveMode&~0x2)|(chan[i].std.ex2.val&0x2);
if (chan[i].waveMode&0x2) { if (chan[i].waveMode&0x2) {
chan[i].waveUpdated=true; chan[i].waveUpdated=true;
chan[i].waveChanged=true; chan[i].waveChanged=true;
} }
} }
if ((chan[i].waveMode&0x1)!=(chan[i].std.ex2&0x1)) { // update waveform now 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&0x1); chan[i].waveMode=(chan[i].waveMode&~0x1)|(chan[i].std.ex2.val&0x1);
if (chan[i].waveMode&0x1) { // rising edge if (chan[i].waveMode&0x1) { // rising edge
chan[i].waveUpdated=true; chan[i].waveUpdated=true;
chan[i].waveChanged=true; chan[i].waveChanged=true;
} }
} }
} }
if (chan[i].std.hadEx3) { if (chan[i].std.ex3.had) {
if (chan[i].loadWave!=chan[i].std.ex3) { if (chan[i].loadWave!=chan[i].std.ex3.val) {
chan[i].loadWave=chan[i].std.ex3; chan[i].loadWave=chan[i].std.ex3.val;
if (chan[i].loadMode&0x2) { if (chan[i].loadMode&0x2) {
updateWave(chan[i].loadWave,chan[i].loadPos,chan[i].loadLen&0xfc); updateWave(chan[i].loadWave,chan[i].loadPos,chan[i].loadLen&0xfc);
} }
} }
} }
if (chan[i].std.hadAlg) { if (chan[i].std.alg.had) {
if (chan[i].loadPos!=chan[i].std.alg) { if (chan[i].loadPos!=chan[i].std.alg.val) {
chan[i].loadPos=chan[i].std.alg; chan[i].loadPos=chan[i].std.alg.val;
} }
} }
if (chan[i].std.hadFb) { if (chan[i].std.fb.had) {
if (chan[i].loadLen!=(chan[i].std.fb&0xfc)) { if (chan[i].loadLen!=(chan[i].std.fb.val&0xfc)) {
chan[i].loadLen=chan[i].std.fb&0xfc; chan[i].loadLen=chan[i].std.fb.val&0xfc;
} }
} }
if (chan[i].std.hadFms) { if (chan[i].std.fms.had) {
if ((chan[i].loadMode&0x2)!=(chan[i].std.fms&0x2)) { // load when every waveform changes 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&0x2); 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 if ((chan[i].loadMode&0x1)!=(chan[i].std.fms.val&0x1)) { // load now
chan[i].loadMode=(chan[i].loadMode&~0x1)|(chan[i].std.fms&0x1); chan[i].loadMode=(chan[i].loadMode&~0x1)|(chan[i].std.fms.val&0x1);
if (chan[i].loadMode&0x1) { // rising edge if (chan[i].loadMode&0x1) { // rising edge
updateWave(chan[i].loadWave,chan[i].loadPos,chan[i].loadLen&0xfc); updateWave(chan[i].loadWave,chan[i].loadPos,chan[i].loadLen&0xfc);
} }
@ -400,7 +400,7 @@ int DivPlatformN163::dispatch(DivCommand c) {
case DIV_CMD_VOLUME: case DIV_CMD_VOLUME:
if (chan[c.chan].vol!=c.value) { if (chan[c.chan].vol!=c.value) {
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].outVol=c.value;
chan[c.chan].resVol=chan[c.chan].outVol; chan[c.chan].resVol=chan[c.chan].outVol;
} else { } else {
@ -513,7 +513,7 @@ int DivPlatformN163::dispatch(DivCommand c) {
} }
break; break;
case DIV_CMD_LEGATO: 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].freqChanged=true;
chan[c.chan].note=c.value; chan[c.chan].note=c.value;
break; break;
@ -607,6 +607,7 @@ void DivPlatformN163::reset() {
memset(regPool,0,128); memset(regPool,0,128);
n163.set_disable(false); n163.set_disable(false);
n163.set_multiplex(multiplex);
chanMax=initChanMax; chanMax=initChanMax;
loadWave=-1; loadWave=-1;
loadPos=0; loadPos=0;
@ -636,8 +637,10 @@ void DivPlatformN163::setFlags(unsigned int flags) {
break; break;
} }
initChanMax=chanMax=(flags>>4)&7; initChanMax=chanMax=(flags>>4)&7;
multiplex=((flags>>7)&1)?false:true; // not accurate in real hardware
chipClock=rate; chipClock=rate;
rate/=15; rate/=15;
n163.set_multiplex(multiplex);
rWrite(0x7f,initChanMax<<4); rWrite(0x7f,initChanMax<<4);
} }

View file

@ -75,6 +75,7 @@ class DivPlatformN163: public DivDispatch {
unsigned char chanMax; unsigned char chanMax;
short loadWave, loadPos, loadLen; short loadWave, loadPos, loadLen;
unsigned char loadMode; unsigned char loadMode;
bool multiplex;
n163_core n163; n163_core n163;
unsigned char regPool[128]; unsigned char regPool[128];

View file

@ -80,7 +80,14 @@ void DivPlatformNES::acquire(short* bufL, short* bufR, size_t start, size_t len)
DivSample* s=parent->getSample(dacSample); DivSample* s=parent->getSample(dacSample);
if (s->samples>0) { if (s->samples>0) {
if (!isMuted[4]) { 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 (++dacPos>=s->samples) {
if (s->loopStart>=0 && s->loopStart<(int)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) { if (nes->apu.clocked) {
nes->apu.clocked=false; 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>32767) sample=32767;
if (sample<-32768) sample=-32768; if (sample<-32768) sample=-32768;
bufL[i]=sample; bufL[i]=sample;
@ -136,9 +143,9 @@ static unsigned char noiseTable[253]={
void DivPlatformNES::tick() { void DivPlatformNES::tick() {
for (int i=0; i<4; i++) { for (int i=0; i<4; i++) {
chan[i].std.next(); chan[i].std.next();
if (chan[i].std.hadVol) { if (chan[i].std.vol.had) {
// ok, why are the volumes like that? // 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 (chan[i].outVol<0) chan[i].outVol=0;
if (i==2) { // triangle if (i==2) { // triangle
rWrite(0x4000+i*4,(chan[i].outVol==0)?0:255); 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)); 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 (i==3) { // noise
if (chan[i].std.arpMode) { if (chan[i].std.arp.mode) {
chan[i].baseFreq=chan[i].std.arp; chan[i].baseFreq=chan[i].std.arp.val;
} else { } 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>255) chan[i].baseFreq=255;
if (chan[i].baseFreq<0) chan[i].baseFreq=0; if (chan[i].baseFreq<0) chan[i].baseFreq=0;
} else { } else {
if (!chan[i].inPorta) { if (!chan[i].inPorta) {
if (chan[i].std.arpMode) { if (chan[i].std.arp.mode) {
chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp); chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val);
} else { } 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; chan[i].freqChanged=true;
} else { } 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].baseFreq=NOTE_PERIODIC(chan[i].note);
chan[i].freqChanged=true; chan[i].freqChanged=true;
} }
} }
if (chan[i].std.hadDuty) { if (chan[i].std.duty.had) {
chan[i].duty=chan[i].std.duty; chan[i].duty=chan[i].std.duty.val;
if (i==3) { if (i==3) {
if (parent->song.properNoiseLayout) { if (parent->song.properNoiseLayout) {
chan[i].duty&=1; chan[i].duty&=1;
@ -337,7 +344,7 @@ int DivPlatformNES::dispatch(DivCommand c) {
case DIV_CMD_VOLUME: case DIV_CMD_VOLUME:
if (chan[c.chan].vol!=c.value) { if (chan[c.chan].vol!=c.value) {
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].outVol=c.value;
} }
if (chan[c.chan].active) { if (chan[c.chan].active) {
@ -406,7 +413,7 @@ int DivPlatformNES::dispatch(DivCommand c) {
break; break;
case DIV_CMD_LEGATO: case DIV_CMD_LEGATO:
if (c.chan==3) break; 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].freqChanged=true;
chan[c.chan].note=c.value; chan[c.chan].note=c.value;
break; break;
@ -454,6 +461,10 @@ int DivPlatformNES::getRegisterPoolSize() {
return 32; return 32;
} }
float DivPlatformNES::getPostAmp() {
return 128.0f;
}
void DivPlatformNES::reset() { void DivPlatformNES::reset() {
for (int i=0; i<5; i++) { for (int i=0; i<5; i++) {
chan[i]=DivPlatformNES::Channel(); chan[i]=DivPlatformNES::Channel();
@ -476,6 +487,9 @@ void DivPlatformNES::reset() {
rWrite(0x4015,0x1f); rWrite(0x4015,0x1f);
rWrite(0x4001,chan[0].sweep); rWrite(0x4001,chan[0].sweep);
rWrite(0x4005,chan[1].sweep); rWrite(0x4005,chan[1].sweep);
dacAntiClickOn=true;
dacAntiClick=0;
} }
bool DivPlatformNES::keyOffAffectsArp(int ch) { bool DivPlatformNES::keyOffAffectsArp(int ch) {

View file

@ -54,10 +54,11 @@ class DivPlatformNES: public DivDispatch {
Channel chan[5]; Channel chan[5];
bool isMuted[5]; bool isMuted[5];
int dacPeriod, dacRate; int dacPeriod, dacRate;
unsigned int dacPos; unsigned int dacPos, dacAntiClick;
int dacSample; int dacSample;
unsigned char sampleBank; unsigned char sampleBank;
unsigned char apuType; unsigned char apuType;
bool dacAntiClickOn;
struct NESAPU* nes; struct NESAPU* nes;
unsigned char regPool[128]; unsigned char regPool[128];
@ -74,6 +75,7 @@ class DivPlatformNES: public DivDispatch {
void tick(); void tick();
void muteChannel(int ch, bool mute); void muteChannel(int ch, bool mute);
bool keyOffAffectsArp(int ch); bool keyOffAffectsArp(int ch);
float getPostAmp();
void setFlags(unsigned int flags); void setFlags(unsigned int flags);
void notifyInsDeletion(void* ins); void notifyInsDeletion(void* ins);
void poke(unsigned int addr, unsigned short val); void poke(unsigned int addr, unsigned short val);

View file

@ -233,8 +233,8 @@ void DivPlatformOPL::tick() {
int ops=(slots[3][i]!=255 && chan[i].state.ops==4 && oplType==3)?4:2; int ops=(slots[3][i]!=255 && chan[i].state.ops==4 && oplType==3)?4:2;
chan[i].std.next(); chan[i].std.next();
if (chan[i].std.hadVol) { if (chan[i].std.vol.had) {
chan[i].outVol=(chan[i].vol*MIN(63,chan[i].std.vol))/63; chan[i].outVol=(chan[i].vol*MIN(63,chan[i].std.vol.val))/63;
for (int j=0; j<ops; j++) { for (int j=0; j<ops; j++) {
unsigned char slot=slots[j][i]; unsigned char slot=slots[j][i];
if (slot==255) continue; 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].inPorta) {
if (chan[i].std.arpMode) { if (chan[i].std.arp.mode) {
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].std.arp); chan[i].baseFreq=NOTE_FREQUENCY(chan[i].std.arp.val);
} else { } 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; chan[i].freqChanged=true;
} else { } 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].baseFreq=NOTE_FREQUENCY(chan[i].note);
chan[i].freqChanged=true; chan[i].freqChanged=true;
} }
} }
if (chan[i].std.hadAlg) { if (chan[i].std.alg.had) {
chan[i].state.alg=chan[i].std.alg; chan[i].state.alg=chan[i].std.alg.val;
} }
if (chan[i].std.hadFb) { if (chan[i].std.fb.had) {
chan[i].state.fb=chan[i].std.fb; 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]) { if (isMuted[i]) {
rWrite(chanMap[i]+ADDR_LR_FB_ALG,(chan[i].state.alg&1)|(chan[i].state.fb<<1)); rWrite(chanMap[i]+ADDR_LR_FB_ALG,(chan[i].state.alg&1)|(chan[i].state.fb<<1));
if (ops==4) { if (ops==4) {
@ -296,58 +296,58 @@ void DivPlatformOPL::tick() {
unsigned short baseAddr=slotMap[slot]; unsigned short baseAddr=slotMap[slot];
DivInstrumentFM::Operator& op=chan[i].state.op[(ops==4)?orderedOpsL[j]:j]; DivInstrumentFM::Operator& op=chan[i].state.op[(ops==4)?orderedOpsL[j]:j];
DivMacroInt::IntOp& m=chan[i].std.op[(ops==4)?orderedOpsL[j]:j]; DivMacroInt::IntOp& m=chan[i].std.op[(ops==4)?orderedOpsL[j]:j];
if (m.hadAm) { if (m.am.had) {
op.am=m.am; 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); 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) { if (m.vib.had) {
op.vib=m.vib; 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); 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) { if (m.sus.had) {
op.sus=m.sus; 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); 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) { if (m.ksr.had) {
op.ksr=m.ksr; 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); 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) { if (m.mult.had) {
op.mult=m.mult; 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); 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) { if (m.ar.had) {
op.ar=m.ar; op.ar=m.ar.val;
rWrite(baseAddr+ADDR_AR_DR,(op.ar<<4)|op.dr); rWrite(baseAddr+ADDR_AR_DR,(op.ar<<4)|op.dr);
} }
if (m.hadDr) { if (m.dr.had) {
op.dr=m.dr; op.dr=m.dr.val;
rWrite(baseAddr+ADDR_AR_DR,(op.ar<<4)|op.dr); rWrite(baseAddr+ADDR_AR_DR,(op.ar<<4)|op.dr);
} }
if (m.hadSl) { if (m.sl.had) {
op.sl=m.sl; op.sl=m.sl.val;
rWrite(baseAddr+ADDR_SL_RR,(op.sl<<4)|op.rr); rWrite(baseAddr+ADDR_SL_RR,(op.sl<<4)|op.rr);
} }
if (m.hadRr) { if (m.rr.had) {
op.rr=m.rr; op.rr=m.rr.val;
rWrite(baseAddr+ADDR_SL_RR,(op.sl<<4)|op.rr); rWrite(baseAddr+ADDR_SL_RR,(op.sl<<4)|op.rr);
} }
if (oplType>1) { if (oplType>1) {
if (m.hadWs) { if (m.ws.had) {
op.ws=m.ws; op.ws=m.ws.val;
rWrite(baseAddr+ADDR_WS,op.ws&((oplType==3)?7:3)); rWrite(baseAddr+ADDR_WS,op.ws&((oplType==3)?7:3));
} }
} }
if (m.hadTl) { if (m.tl.had) {
op.tl=63-m.tl; op.tl=63-m.tl.val;
} }
if (m.hadKsl) { if (m.ksl.had) {
op.ksl=m.ksl; op.ksl=m.ksl.val;
} }
if (m.hadTl || m.hadKsl) { if (m.tl.had || m.ksl.had) {
if (isMuted[i]) { if (isMuted[i]) {
rWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6)); rWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6));
} else { } else {
@ -371,7 +371,7 @@ void DivPlatformOPL::tick() {
if (update4OpMask) { if (update4OpMask) {
update4OpMask=false; update4OpMask=false;
if (oplType==3) { 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); immWrite(0x104,opMask);
//printf("updating opMask to %.2x\n",opMask); //printf("updating opMask to %.2x\n",opMask);
} }
@ -528,7 +528,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
} }
chan[c.chan].std.init(ins); 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; chan[c.chan].outVol=chan[c.chan].vol;
} }
if (chan[c.chan].insChanged) { if (chan[c.chan].insChanged) {
@ -620,7 +620,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
if (c.value>63) c.value=63; if (c.value>63) c.value=63;
} }
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].outVol=c.value;
} }
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2; 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; chipClock=COLOR_NTSC;
rate=chipClock/72; rate=chipClock/72;
} }
if (pretendYMU) {
rate=48000;
chipClock=rate*288;
}
} }
int DivPlatformOPL::init(DivEngine* p, int channels, int sugRate, unsigned int flags) { int DivPlatformOPL::init(DivEngine* p, int channels, int sugRate, unsigned int flags) {

View file

@ -115,51 +115,51 @@ void DivPlatformOPLL::tick() {
for (int i=0; i<11; i++) { for (int i=0; i<11; i++) {
chan[i].std.next(); chan[i].std.next();
if (chan[i].std.hadVol) { if (chan[i].std.vol.had) {
chan[i].outVol=(chan[i].vol*MIN(15,chan[i].std.vol))/15; chan[i].outVol=(chan[i].vol*MIN(15,chan[i].std.vol.val))/15;
if (i<9) { if (i<9) {
rWrite(0x30+i,((15-(chan[i].outVol*(15-chan[i].state.op[1].tl))/15)&15)|(chan[i].state.opllPreset<<4)); 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].inPorta) {
if (chan[i].std.arpMode) { if (chan[i].std.arp.mode) {
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].std.arp); chan[i].baseFreq=NOTE_FREQUENCY(chan[i].std.arp.val);
} else { } 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; chan[i].freqChanged=true;
} else { } 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].baseFreq=NOTE_FREQUENCY(chan[i].note);
chan[i].freqChanged=true; chan[i].freqChanged=true;
} }
} }
if (chan[i].std.hadWave && chan[i].state.opllPreset!=16) { if (chan[i].std.wave.had && chan[i].state.opllPreset!=16) {
chan[i].state.opllPreset=chan[i].std.wave; chan[i].state.opllPreset=chan[i].std.wave.val;
if (i<9) { if (i<9) {
rWrite(0x30+i,((15-(chan[i].outVol*(15-chan[i].state.op[1].tl))/15)&15)|(chan[i].state.opllPreset<<4)); 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].state.opllPreset==0) {
if (chan[i].std.hadAlg) { // SUS if (chan[i].std.alg.had) { // SUS
chan[i].state.alg=chan[i].std.alg; chan[i].state.alg=chan[i].std.alg.val;
chan[i].freqChanged=true; chan[i].freqChanged=true;
} }
if (chan[i].std.hadFb) { if (chan[i].std.fb.had) {
chan[i].state.fb=chan[i].std.fb; 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); 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) { if (chan[i].std.fms.had) {
chan[i].state.fms=chan[i].std.fms; 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); 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) { if (chan[i].std.ams.had) {
chan[i].state.ams=chan[i].std.ams; 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); 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]; DivInstrumentFM::Operator& op=chan[i].state.op[j];
DivMacroInt::IntOp& m=chan[i].std.op[j]; DivMacroInt::IntOp& m=chan[i].std.op[j];
if (m.hadAm) { if (m.am.had) {
op.am=m.am; op.am=m.am.val;
rWrite(0x00+j,(op.am<<7)|(op.vib<<6)|((op.ssgEnv&8)<<2)|(op.ksr<<4)|(op.mult)); rWrite(0x00+j,(op.am<<7)|(op.vib<<6)|((op.ssgEnv&8)<<2)|(op.ksr<<4)|(op.mult));
} }
if (m.hadAr) { if (m.ar.had) {
op.ar=m.ar; op.ar=m.ar.val;
rWrite(0x04+j,(op.ar<<4)|(op.dr)); rWrite(0x04+j,(op.ar<<4)|(op.dr));
} }
if (m.hadDr) { if (m.dr.had) {
op.dr=m.dr; op.dr=m.dr.val;
rWrite(0x04+j,(op.ar<<4)|(op.dr)); rWrite(0x04+j,(op.ar<<4)|(op.dr));
} }
if (m.hadMult) { if (m.mult.had) {
op.mult=m.mult; op.mult=m.mult.val;
rWrite(0x00+j,(op.am<<7)|(op.vib<<6)|((op.ssgEnv&8)<<2)|(op.ksr<<4)|(op.mult)); rWrite(0x00+j,(op.am<<7)|(op.vib<<6)|((op.ssgEnv&8)<<2)|(op.ksr<<4)|(op.mult));
} }
if (m.hadRr) { if (m.rr.had) {
op.rr=m.rr; op.rr=m.rr.val;
rWrite(0x06+j,(op.sl<<4)|(op.rr)); rWrite(0x06+j,(op.sl<<4)|(op.rr));
} }
if (m.hadSl) { if (m.sl.had) {
op.sl=m.sl; op.sl=m.sl.val;
rWrite(0x06+j,(op.sl<<4)|(op.rr)); rWrite(0x06+j,(op.sl<<4)|(op.rr));
} }
if (m.hadTl) { if (m.tl.had) {
op.tl=((j==1)?15:63)-m.tl; op.tl=((j==1)?15:63)-m.tl.val;
if (j==1) { if (j==1) {
if (i<9) { if (i<9) {
rWrite(0x30+i,((15-(chan[i].outVol*(15-chan[i].state.op[1].tl))/15)&15)|(chan[i].state.opllPreset<<4)); 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) { if (m.egt.had) {
op.ssgEnv=(m.egt&1)?8:0; 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)); rWrite(0x00+j,(op.am<<7)|(op.vib<<6)|((op.ssgEnv&8)<<2)|(op.ksr<<4)|(op.mult));
} }
if (m.hadKsl) { if (m.ksl.had) {
op.ksl=m.ksl; op.ksl=m.ksl.val;
if (j==1) { if (j==1) {
rWrite(0x02,(chan[i].state.op[0].ksl<<6)|(chan[i].state.op[0].tl&63)); rWrite(0x02,(chan[i].state.op[0].ksl<<6)|(chan[i].state.op[0].tl&63));
} else { } 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); 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) { if (m.ksr.had) {
op.ksr=m.ksr; op.ksr=m.ksr.val;
rWrite(0x00+j,(op.am<<7)|(op.vib<<6)|((op.ssgEnv&8)<<2)|(op.ksr<<4)|(op.mult)); rWrite(0x00+j,(op.am<<7)|(op.vib<<6)|((op.ssgEnv&8)<<2)|(op.ksr<<4)|(op.mult));
} }
if (m.hadVib) { if (m.vib.had) {
op.vib=m.vib; op.vib=m.vib.val;
rWrite(0x00+j,(op.am<<7)|(op.vib<<6)|((op.ssgEnv&8)<<2)|(op.ksr<<4)|(op.mult)); 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); 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; chan[c.chan].outVol=chan[c.chan].vol;
} }
@ -490,7 +490,7 @@ int DivPlatformOPLL::dispatch(DivCommand c) {
case DIV_CMD_VOLUME: { case DIV_CMD_VOLUME: {
if (c.chan>=9 && !properDrums) return 0; if (c.chan>=9 && !properDrums) return 0;
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].outVol=c.value;
} }
if (c.chan>=6 && properDrums) { if (c.chan>=6 && properDrums) {
@ -620,7 +620,7 @@ int DivPlatformOPLL::dispatch(DivCommand c) {
} }
case DIV_CMD_FM_EXTCH: case DIV_CMD_FM_EXTCH:
if (!properDrumsSys) break; if (!properDrumsSys) break;
if (properDrums==c.value) break; if ((int)properDrums==c.value) break;
if (c.value) { if (c.value) {
properDrums=true; properDrums=true;
immWrite(0x0e,0x20); immWrite(0x0e,0x20);

View file

@ -149,39 +149,39 @@ static unsigned char noiseFreq[12]={
void DivPlatformPCE::tick() { void DivPlatformPCE::tick() {
for (int i=0; i<6; i++) { for (int i=0; i<6; i++) {
chan[i].std.next(); chan[i].std.next();
if (chan[i].std.hadVol) { if (chan[i].std.vol.had) {
chan[i].outVol=((chan[i].vol&31)*MIN(31,chan[i].std.vol))>>5; chan[i].outVol=((chan[i].vol&31)*MIN(31,chan[i].std.vol.val))>>5;
if (chan[i].furnaceDac) { if (chan[i].furnaceDac) {
// ignore for now // ignore for now
} else { } else {
chWrite(i,0x04,0x80|chan[i].outVol); chWrite(i,0x04,0x80|chan[i].outVol);
} }
} }
if (chan[i].std.hadDuty && i>=4) { if (chan[i].std.duty.had && i>=4) {
chan[i].noise=chan[i].std.duty; chan[i].noise=chan[i].std.duty.val;
chan[i].freqChanged=true; chan[i].freqChanged=true;
int noiseSeek=chan[i].note; int noiseSeek=chan[i].note;
if (noiseSeek<0) noiseSeek=0; if (noiseSeek<0) noiseSeek=0;
chWrite(i,0x07,chan[i].noise?(0x80|(parent->song.properNoiseLayout?(noiseSeek&31):noiseFreq[noiseSeek%12])):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].inPorta) {
if (chan[i].std.arpMode) { if (chan[i].std.arp.mode) {
chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp); chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val);
// noise // noise
int noiseSeek=chan[i].std.arp; int noiseSeek=chan[i].std.arp.val;
if (noiseSeek<0) noiseSeek=0; if (noiseSeek<0) noiseSeek=0;
chWrite(i,0x07,chan[i].noise?(0x80|(parent->song.properNoiseLayout?(noiseSeek&31):noiseFreq[noiseSeek%12])):0); chWrite(i,0x07,chan[i].noise?(0x80|(parent->song.properNoiseLayout?(noiseSeek&31):noiseFreq[noiseSeek%12])):0);
} else { } 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);
int noiseSeek=chan[i].note+chan[i].std.arp; int noiseSeek=chan[i].note+chan[i].std.arp.val;
if (noiseSeek<0) noiseSeek=0; if (noiseSeek<0) noiseSeek=0;
chWrite(i,0x07,chan[i].noise?(0x80|(parent->song.properNoiseLayout?(noiseSeek&31):noiseFreq[noiseSeek%12])):0); chWrite(i,0x07,chan[i].noise?(0x80|(parent->song.properNoiseLayout?(noiseSeek&31):noiseFreq[noiseSeek%12])):0);
} }
} }
chan[i].freqChanged=true; chan[i].freqChanged=true;
} else { } 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].baseFreq=NOTE_PERIODIC(chan[i].note);
int noiseSeek=chan[i].note; int noiseSeek=chan[i].note;
if (noiseSeek<0) noiseSeek=0; if (noiseSeek<0) noiseSeek=0;
@ -189,9 +189,9 @@ void DivPlatformPCE::tick() {
chan[i].freqChanged=true; chan[i].freqChanged=true;
} }
} }
if (chan[i].std.hadWave && !chan[i].pcm) { if (chan[i].std.wave.had && !chan[i].pcm) {
if (chan[i].wave!=chan[i].std.wave || chan[i].ws.activeChanged()) { if (chan[i].wave!=chan[i].std.wave.val || chan[i].ws.activeChanged()) {
chan[i].wave=chan[i].std.wave; chan[i].wave=chan[i].std.wave.val;
chan[i].ws.changeWave1(chan[i].wave); chan[i].ws.changeWave1(chan[i].wave);
if (!chan[i].keyOff) chan[i].keyOn=true; if (!chan[i].keyOff) chan[i].keyOn=true;
} }
@ -332,14 +332,14 @@ int DivPlatformPCE::dispatch(DivCommand c) {
case DIV_CMD_VOLUME: case DIV_CMD_VOLUME:
if (chan[c.chan].vol!=c.value) { if (chan[c.chan].vol!=c.value) {
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].outVol=c.value;
if (chan[c.chan].active) chWrite(c.chan,0x04,0x80|chan[c.chan].outVol); if (chan[c.chan].active) chWrite(c.chan,0x04,0x80|chan[c.chan].outVol);
} }
} }
break; break;
case DIV_CMD_GET_VOLUME: 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].vol;
} }
return chan[c.chan].outVol; return chan[c.chan].outVol;
@ -409,7 +409,7 @@ int DivPlatformPCE::dispatch(DivCommand c) {
break; break;
} }
case DIV_CMD_LEGATO: 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].freqChanged=true;
chan[c.chan].note=c.value; chan[c.chan].note=c.value;
break; break;

View file

@ -167,21 +167,21 @@ void DivPlatformPCSpeaker::acquire(short* bufL, short* bufR, size_t start, size_
void DivPlatformPCSpeaker::tick() { void DivPlatformPCSpeaker::tick() {
for (int i=0; i<1; i++) { for (int i=0; i<1; i++) {
chan[i].std.next(); chan[i].std.next();
if (chan[i].std.hadVol) { if (chan[i].std.vol.had) {
chan[i].outVol=(chan[i].vol && chan[i].std.vol); chan[i].outVol=(chan[i].vol && chan[i].std.vol.val);
on=chan[i].outVol; on=chan[i].outVol;
} }
if (chan[i].std.hadArp) { if (chan[i].std.arp.had) {
if (!chan[i].inPorta) { if (!chan[i].inPorta) {
if (chan[i].std.arpMode) { if (chan[i].std.arp.mode) {
chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp); chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val);
} else { } 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; chan[i].freqChanged=true;
} else { } 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].baseFreq=NOTE_PERIODIC(chan[i].note);
chan[i].freqChanged=true; chan[i].freqChanged=true;
} }
@ -233,7 +233,7 @@ int DivPlatformPCSpeaker::dispatch(DivCommand c) {
case DIV_CMD_VOLUME: case DIV_CMD_VOLUME:
if (chan[c.chan].vol!=c.value) { if (chan[c.chan].vol!=c.value) {
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].outVol=c.value;
} }
if (chan[c.chan].active) { if (chan[c.chan].active) {
@ -273,7 +273,7 @@ int DivPlatformPCSpeaker::dispatch(DivCommand c) {
} }
case DIV_CMD_LEGATO: case DIV_CMD_LEGATO:
if (c.chan==3) break; 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].freqChanged=true;
chan[c.chan].note=c.value; chan[c.chan].note=c.value;
break; break;

View file

@ -87,28 +87,28 @@ void DivPlatformPET::writeOutVol() {
void DivPlatformPET::tick() { void DivPlatformPET::tick() {
chan.std.next(); chan.std.next();
if (chan.std.hadVol) { if (chan.std.vol.had) {
chan.outVol=chan.std.vol&chan.vol; chan.outVol=chan.std.vol.val&chan.vol;
writeOutVol(); writeOutVol();
} }
if (chan.std.hadArp) { if (chan.std.arp.had) {
if (!chan.inPorta) { if (!chan.inPorta) {
if (chan.std.arpMode) { if (chan.std.arp.mode) {
chan.baseFreq=NOTE_PERIODIC(chan.std.arp); chan.baseFreq=NOTE_PERIODIC(chan.std.arp.val);
} else { } else {
chan.baseFreq=NOTE_PERIODIC(chan.note+chan.std.arp); chan.baseFreq=NOTE_PERIODIC(chan.note+chan.std.arp.val);
} }
} }
chan.freqChanged=true; chan.freqChanged=true;
} else { } else {
if (chan.std.arpMode && chan.std.finishedArp) { if (chan.std.arp.mode && chan.std.arp.finished) {
chan.baseFreq=NOTE_PERIODIC(chan.note); chan.baseFreq=NOTE_PERIODIC(chan.note);
chan.freqChanged=true; chan.freqChanged=true;
} }
} }
if (chan.std.hadWave) { if (chan.std.wave.had) {
if (chan.wave!=chan.std.wave) { if (chan.wave!=chan.std.wave.val) {
chan.wave=chan.std.wave; chan.wave=chan.std.wave.val;
rWrite(10,chan.wave); rWrite(10,chan.wave);
} }
} }
@ -118,7 +118,7 @@ void DivPlatformPET::tick() {
if (chan.freq<2) chan.freq=2; if (chan.freq<2) chan.freq=2;
rWrite(8,chan.freq-2); rWrite(8,chan.freq-2);
if (chan.keyOn) { if (chan.keyOn) {
if (!chan.std.willVol) { if (!chan.std.vol.will) {
chan.outVol=chan.vol; chan.outVol=chan.vol;
writeOutVol(); writeOutVol();
} }
@ -163,7 +163,7 @@ int DivPlatformPET::dispatch(DivCommand c) {
case DIV_CMD_VOLUME: case DIV_CMD_VOLUME:
if (chan.vol!=c.value) { if (chan.vol!=c.value) {
chan.vol=c.value; chan.vol=c.value;
if (!chan.std.hadVol) { if (!chan.std.vol.had) {
chan.outVol=chan.vol; chan.outVol=chan.vol;
writeOutVol(); writeOutVol();
} }
@ -204,7 +204,7 @@ int DivPlatformPET::dispatch(DivCommand c) {
break; break;
} }
case DIV_CMD_LEGATO: 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.freqChanged=true;
chan.note=c.value; chan.note=c.value;
break; break;

View file

@ -277,8 +277,8 @@ void DivPlatformQSound::acquire(short* bufL, short* bufR, size_t start, size_t l
void DivPlatformQSound::tick() { void DivPlatformQSound::tick() {
for (int i=0; i<16; i++) { for (int i=0; i<16; i++) {
chan[i].std.next(); chan[i].std.next();
if (chan[i].std.hadVol) { if (chan[i].std.vol.had) {
chan[i].outVol=((chan[i].vol&0xff)*chan[i].std.vol)>>6; chan[i].outVol=((chan[i].vol&0xff)*chan[i].std.vol.val)>>6;
// Check if enabled and write volume // Check if enabled and write volume
if (chan[i].active) { if (chan[i].active) {
rWrite(q1_reg_map[Q1V_VOL][i], chan[i].outVol << 4); rWrite(q1_reg_map[Q1V_VOL][i], chan[i].outVol << 4);
@ -311,17 +311,17 @@ void DivPlatformQSound::tick() {
qsound_loop = length - s->loopStart; qsound_loop = length - s->loopStart;
} }
} }
if (chan[i].std.hadArp) { if (chan[i].std.arp.had) {
if (!chan[i].inPorta) { if (!chan[i].inPorta) {
if (chan[i].std.arpMode) { if (chan[i].std.arp.mode) {
chan[i].baseFreq=off*QS_NOTE_FREQUENCY(chan[i].std.arp); chan[i].baseFreq=off*QS_NOTE_FREQUENCY(chan[i].std.arp.val);
} else { } 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; chan[i].freqChanged=true;
} else { } 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].baseFreq=off*QS_NOTE_FREQUENCY(chan[i].note);
chan[i].freqChanged=true; 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_LOOP][i], qsound_loop);
rWrite(q1_reg_map[Q1V_START][i], qsound_addr); rWrite(q1_reg_map[Q1V_START][i], qsound_addr);
rWrite(q1_reg_map[Q1V_PHASE][i], 0x8000); 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 // 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); 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_VOL][i], 0);
rWrite(q1_reg_map[Q1V_FREQ][i], 0); rWrite(q1_reg_map[Q1V_FREQ][i], 0);
} else if (chan[i].active) { } 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); rWrite(q1_reg_map[Q1V_FREQ][i], chan[i].freq);
} }
if (chan[i].keyOn) chan[i].keyOn=false; if (chan[i].keyOn) chan[i].keyOn=false;
@ -404,7 +404,7 @@ int DivPlatformQSound::dispatch(DivCommand c) {
case DIV_CMD_VOLUME: case DIV_CMD_VOLUME:
if (chan[c.chan].vol!=c.value) { if (chan[c.chan].vol!=c.value) {
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 // Check if enabled and write volume
chan[c.chan].outVol=c.value; chan[c.chan].outVol=c.value;
if (chan[c.chan].active && c.chan < 16) { if (chan[c.chan].active && c.chan < 16) {
@ -414,7 +414,7 @@ int DivPlatformQSound::dispatch(DivCommand c) {
} }
break; break;
case DIV_CMD_GET_VOLUME: 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].vol;
} }
return chan[c.chan].outVol; return chan[c.chan].outVol;
@ -477,7 +477,7 @@ int DivPlatformQSound::dispatch(DivCommand c) {
off=(double)s->centerRate/24038.0/16.0; 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].freqChanged=true;
chan[c.chan].note=c.value; chan[c.chan].note=c.value;
break; break;

View file

@ -135,8 +135,8 @@ inline unsigned char applyPan(unsigned char vol, unsigned char pan) {
void DivPlatformSAA1099::tick() { void DivPlatformSAA1099::tick() {
for (int i=0; i<6; i++) { for (int i=0; i<6; i++) {
chan[i].std.next(); chan[i].std.next();
if (chan[i].std.hadVol) { if (chan[i].std.vol.had) {
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 (chan[i].outVol<0) chan[i].outVol=0;
if (isMuted[i]) { if (isMuted[i]) {
rWrite(i,0); rWrite(i,0);
@ -144,30 +144,30 @@ void DivPlatformSAA1099::tick() {
rWrite(i,applyPan(chan[i].outVol&15,chan[i].pan)); 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].inPorta) {
if (chan[i].std.arpMode) { if (chan[i].std.arp.mode) {
chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp); chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val);
} else { } 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; chan[i].freqChanged=true;
} else { } 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].baseFreq=NOTE_PERIODIC(chan[i].note);
chan[i].freqChanged=true; chan[i].freqChanged=true;
} }
} }
if (chan[i].std.hadDuty) { if (chan[i].std.duty.had) {
saaNoise[i/3]=chan[i].std.duty&3; saaNoise[i/3]=chan[i].std.duty.val&3;
rWrite(0x16,saaNoise[0]|(saaNoise[1]<<4)); rWrite(0x16,saaNoise[0]|(saaNoise[1]<<4));
} }
if (chan[i].std.hadWave) { if (chan[i].std.wave.had) {
chan[i].psgMode=chan[i].std.wave&3; chan[i].psgMode=chan[i].std.wave.val&3;
} }
if (chan[i].std.hadEx1) { if (chan[i].std.ex1.had) {
saaEnv[i/3]=chan[i].std.ex1; saaEnv[i/3]=chan[i].std.ex1.val;
rWrite(0x18+(i/3),saaEnv[i/3]); rWrite(0x18+(i/3),saaEnv[i/3]);
} }
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
@ -253,7 +253,7 @@ int DivPlatformSAA1099::dispatch(DivCommand c) {
break; break;
case DIV_CMD_VOLUME: { case DIV_CMD_VOLUME: {
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].outVol=c.value;
} }
if (isMuted[c.chan]) { if (isMuted[c.chan]) {
@ -414,6 +414,16 @@ void DivPlatformSAA1099::reset() {
extMode=false; 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); rWrite(0x1c,1);
} }

View file

@ -80,21 +80,21 @@ void DivPlatformSegaPCM::tick() {
for (int i=0; i<16; i++) { for (int i=0; i<16; i++) {
chan[i].std.next(); chan[i].std.next();
if (chan[i].std.hadVol) { if (chan[i].std.vol.had) {
chan[i].outVol=(chan[i].vol*MIN(127,chan[i].std.vol))/127; 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].inPorta) {
if (chan[i].std.arpMode) { if (chan[i].std.arp.mode) {
chan[i].baseFreq=(chan[i].std.arp<<6); chan[i].baseFreq=(chan[i].std.arp.val<<6);
} else { } 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; chan[i].freqChanged=true;
} else { } 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].baseFreq=(chan[i].note<<6);
chan[i].freqChanged=true; chan[i].freqChanged=true;
} }
@ -214,7 +214,7 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) {
break; break;
case DIV_CMD_VOLUME: { case DIV_CMD_VOLUME: {
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].outVol=c.value;
} }
chan[c.chan].chVolL=c.value; chan[c.chan].chVolL=c.value;

View file

@ -56,21 +56,21 @@ int DivPlatformSMS::acquireOne() {
void DivPlatformSMS::tick() { void DivPlatformSMS::tick() {
for (int i=0; i<4; i++) { for (int i=0; i<4; i++) {
chan[i].std.next(); chan[i].std.next();
if (chan[i].std.hadVol) { if (chan[i].std.vol.had) {
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 (chan[i].outVol<0) chan[i].outVol=0;
// old formula // 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)))); 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].inPorta) {
if (chan[i].std.arpMode) { if (chan[i].std.arp.mode) {
chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp); chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val);
chan[i].actualNote=chan[i].std.arp; chan[i].actualNote=chan[i].std.arp.val;
} else { } else {
// TODO: check whether this weird octave boundary thing applies to other systems as well // 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; while (areYouSerious>0x60) areYouSerious-=12;
chan[i].baseFreq=NOTE_PERIODIC(areYouSerious); chan[i].baseFreq=NOTE_PERIODIC(areYouSerious);
chan[i].actualNote=areYouSerious; chan[i].actualNote=areYouSerious;
@ -78,15 +78,15 @@ void DivPlatformSMS::tick() {
chan[i].freqChanged=true; chan[i].freqChanged=true;
} }
} else { } 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].baseFreq=NOTE_PERIODIC(chan[i].note);
chan[i].actualNote=chan[i].note; chan[i].actualNote=chan[i].note;
chan[i].freqChanged=true; chan[i].freqChanged=true;
} }
} }
if (i==3) if (chan[i].std.hadDuty) { if (i==3) if (chan[i].std.duty.had) {
snNoiseMode=chan[i].std.duty; snNoiseMode=chan[i].std.duty.val;
if (chan[i].std.duty<2) { if (chan[i].std.duty.val<2) {
chan[3].freqChanged=false; chan[3].freqChanged=false;
} }
updateSNMode=true; updateSNMode=true;
@ -130,11 +130,11 @@ void DivPlatformSMS::tick() {
} }
} else { // 3 fixed values } else { // 3 fixed values
unsigned char value; unsigned char value;
if (chan[3].std.hadArp) { if (chan[3].std.arp.had) {
if (chan[3].std.arpMode) { if (chan[3].std.arp.mode) {
value=chan[3].std.arp%12; value=chan[3].std.arp.val%12;
} else { } else {
value=(chan[3].note+chan[3].std.arp)%12; value=(chan[3].note+chan[3].std.arp.val)%12;
} }
} else { } else {
value=chan[3].note%12; value=chan[3].note%12;
@ -181,14 +181,14 @@ int DivPlatformSMS::dispatch(DivCommand c) {
case DIV_CMD_VOLUME: case DIV_CMD_VOLUME:
if (chan[c.chan].vol!=c.value) { if (chan[c.chan].vol!=c.value) {
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].outVol=c.value;
} }
if (chan[c.chan].active) rWrite(0x90|c.chan<<5|(isMuted[c.chan]?15:(15-(chan[c.chan].vol&15)))); if (chan[c.chan].active) rWrite(0x90|c.chan<<5|(isMuted[c.chan]?15:(15-(chan[c.chan].vol&15))));
} }
break; break;
case DIV_CMD_GET_VOLUME: 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].vol;
} }
return chan[c.chan].outVol; return chan[c.chan].outVol;
@ -225,7 +225,7 @@ int DivPlatformSMS::dispatch(DivCommand c) {
updateSNMode=true; updateSNMode=true;
break; break;
case DIV_CMD_LEGATO: 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].freqChanged=true;
chan[c.chan].note=c.value; chan[c.chan].note=c.value;
chan[c.chan].actualNote=c.value; chan[c.chan].actualNote=c.value;

View file

@ -1120,7 +1120,7 @@ void ay8910_device::sound_stream_update(short** outputs, int outLen)
for (int chan = 0; chan < NUM_CHANNELS; chan++) for (int chan = 0; chan < NUM_CHANNELS; chan++)
{ {
tone = &m_tone[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 */ /* update envelope */

View file

@ -58,16 +58,27 @@
Frequency formula: Frequency formula:
Frequency: Pitch input * ((Input clock * 15 * Number of activated voices) / 65536) 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" #include "n163.hpp"
void n163_core::tick() void n163_core::tick()
{ {
m_out = 0; if (m_multiplex)
m_out = 0;
// 0xe000-0xe7ff Disable sound bits (bit 6, bit 0 to 5 are CPU ROM Bank 0x8000-0x9fff select.) // 0xe000-0xe7ff Disable sound bits (bit 6, bit 0 to 5 are CPU ROM Bank 0x8000-0x9fff select.)
if (m_disable) if (m_disable)
{
if (!m_multiplex)
m_out = 0;
return; return;
}
// tick per each clock // 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 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); m_ram[m_voice_cycle + 5] = bitfield(accum, 16, 8);
// update voice cycle // update voice cycle
bool flush = m_multiplex ? true : false;
m_voice_cycle -= 0x8; m_voice_cycle -= 0x8;
if (m_voice_cycle < (0x78 - (bitfield(m_ram[0x7f], 4, 3) << 3))) if (m_voice_cycle < (0x78 - (bitfield(m_ram[0x7f], 4, 3) << 3)))
{
if (!m_multiplex)
flush = true;
m_voice_cycle = 0x78; m_voice_cycle = 0x78;
}
// output 4 bit waveform and volume, multiplexed // 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() void n163_core::reset()
{ {
// reset this chip // reset this chip
m_disable = false; m_disable = false;
m_multiplex = true;
std::fill(std::begin(m_ram), std::end(m_ram), 0); std::fill(std::begin(m_ram), std::end(m_ram), 0);
m_voice_cycle = 0x78; m_voice_cycle = 0x78;
m_addr_latch.reset(); m_addr_latch.reset();
m_out = 0; m_out = 0;
m_acc = 0;
} }
// accessor // accessor

View file

@ -48,6 +48,7 @@ public:
// register pool // register pool
u8 reg(u8 addr) { return m_ram[addr & 0x7f]; } u8 reg(u8 addr) { return m_ram[addr & 0x7f]; }
void set_multiplex(bool multiplex = true) { m_multiplex = multiplex; }
private: private:
// Address latch // Address latch
@ -73,6 +74,9 @@ private:
u8 m_voice_cycle = 0x78; // Voice cycle for processing u8 m_voice_cycle = 0x78; // Voice cycle for processing
addr_latch_t m_addr_latch; // address latch addr_latch_t m_addr_latch; // address latch
s16 m_out = 0; // output s16 m_out = 0; // output
// demultiplex related
bool m_multiplex = true; // multiplex flag, but less noisy = inaccurate!
s16 m_acc = 0; // accumulated output
}; };
#endif #endif

View file

@ -213,7 +213,8 @@ void apu_turn_on(struct NESAPU* a, BYTE apu_type) {
a->S2.sweep.delay = 1; a->S2.sweep.delay = 1;
a->S2.sweep.divider = 1; a->S2.sweep.divider = 1;
a->TR.frequency = 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.frequency = 1;
a->NS.shift = 1; a->NS.shift = 1;
a->DMC.frequency = 1; a->DMC.frequency = 1;

View file

@ -33,7 +33,7 @@
#pragma once #pragma once
#ifdef _MSC_VER #if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
#define _CRT_SECURE_NO_WARNINGS #define _CRT_SECURE_NO_WARNINGS
#endif #endif

View file

@ -145,31 +145,31 @@ void DivPlatformSwan::tick() {
unsigned char sndCtrl=(pcm?0x20:0)|(sweep?0x40:0)|((noise>0)?0x80:0); unsigned char sndCtrl=(pcm?0x20:0)|(sweep?0x40:0)|((noise>0)?0x80:0);
for (int i=0; i<4; i++) { for (int i=0; i<4; i++) {
chan[i].std.next(); chan[i].std.next();
if (chan[i].std.hadVol) { if (chan[i].std.vol.had) {
int env=chan[i].std.vol; int env=chan[i].std.vol.val;
if(parent->getIns(chan[i].ins)->type==DIV_INS_AMIGA) { if(parent->getIns(chan[i].ins)->type==DIV_INS_AMIGA) {
env=MIN(env/4,15); env=MIN(env/4,15);
} }
calcAndWriteOutVol(i,env); calcAndWriteOutVol(i,env);
} }
if (chan[i].std.hadArp) { if (chan[i].std.arp.had) {
if (!chan[i].inPorta) { if (!chan[i].inPorta) {
if (chan[i].std.arpMode) { if (chan[i].std.arp.mode) {
chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp); chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val);
} else { } 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; chan[i].freqChanged=true;
} else { } 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].baseFreq=NOTE_PERIODIC(chan[i].note);
chan[i].freqChanged=true; chan[i].freqChanged=true;
} }
} }
if (chan[i].std.hadWave && !(i==1 && pcm)) { if (chan[i].std.wave.had && !(i==1 && pcm)) {
if (chan[i].wave!=chan[i].std.wave || chan[i].ws.activeChanged()) { if (chan[i].wave!=chan[i].std.wave.val || chan[i].ws.activeChanged()) {
chan[i].wave=chan[i].std.wave; chan[i].wave=chan[i].std.wave.val;
chan[i].ws.changeWave1(chan[i].wave); chan[i].ws.changeWave1(chan[i].wave);
} }
} }
@ -200,7 +200,7 @@ void DivPlatformSwan::tick() {
rWrite(i*2,rVal&0xff); rWrite(i*2,rVal&0xff);
rWrite(i*2+1,rVal>>8); rWrite(i*2+1,rVal>>8);
if (chan[i].keyOn) { if (chan[i].keyOn) {
if (!chan[i].std.willVol) { if (!chan[i].std.vol.will) {
calcAndWriteOutVol(i,15); calcAndWriteOutVol(i,15);
} }
chan[i].keyOn=false; chan[i].keyOn=false;
@ -211,8 +211,8 @@ void DivPlatformSwan::tick() {
chan[i].freqChanged=false; chan[i].freqChanged=false;
} }
} }
if (chan[3].std.hadDuty) { if (chan[3].std.duty.had) {
noise=chan[3].std.duty; noise=chan[3].std.duty.val;
if (noise>0) { if (noise>0) {
rWrite(0x0e,((noise-1)&0x07)|0x18); rWrite(0x0e,((noise-1)&0x07)|0x18);
sndCtrl|=0x80; sndCtrl|=0x80;
@ -319,7 +319,7 @@ int DivPlatformSwan::dispatch(DivCommand c) {
case DIV_CMD_VOLUME: case DIV_CMD_VOLUME:
if (chan[c.chan].vol!=c.value) { if (chan[c.chan].vol!=c.value) {
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); calcAndWriteOutVol(c.chan,15);
} }
} }
@ -391,11 +391,11 @@ int DivPlatformSwan::dispatch(DivCommand c) {
break; break;
case DIV_CMD_PANNING: { case DIV_CMD_PANNING: {
chan[c.chan].pan=c.value; 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; break;
} }
case DIV_CMD_LEGATO: 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].freqChanged=true;
chan[c.chan].note=c.value; chan[c.chan].note=c.value;
break; break;

View file

@ -87,8 +87,8 @@ unsigned char DivPlatformTIA::dealWithFreq(unsigned char shape, int base, int pi
void DivPlatformTIA::tick() { void DivPlatformTIA::tick() {
for (int i=0; i<2; i++) { for (int i=0; i<2; i++) {
chan[i].std.next(); chan[i].std.next();
if (chan[i].std.hadVol) { if (chan[i].std.vol.had) {
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 (chan[i].outVol<0) chan[i].outVol=0;
if (isMuted[i]) { if (isMuted[i]) {
rWrite(0x19+i,0); rWrite(0x19+i,0);
@ -96,29 +96,29 @@ void DivPlatformTIA::tick() {
rWrite(0x19+i,chan[i].outVol&15); 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].inPorta) {
if (chan[i].std.arpMode) { if (chan[i].std.arp.mode) {
chan[i].baseFreq=0x80000000|chan[i].std.arp; chan[i].baseFreq=0x80000000|chan[i].std.arp.val;
} else { } 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; chan[i].freqChanged=true;
} else { } 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].baseFreq=chan[i].note<<8;
chan[i].freqChanged=true; chan[i].freqChanged=true;
} }
} }
if (chan[i].std.hadWave) { if (chan[i].std.wave.had) {
chan[i].shape=chan[i].std.wave&15; chan[i].shape=chan[i].std.wave.val&15;
rWrite(0x15+i,chan[i].shape); rWrite(0x15+i,chan[i].shape);
chan[i].freqChanged=true; chan[i].freqChanged=true;
} }
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
if (chan[i].insChanged) { if (chan[i].insChanged) {
if (!chan[i].std.willWave) { if (!chan[i].std.wave.will) {
chan[i].shape=4; chan[i].shape=4;
rWrite(0x15+i,chan[i].shape); rWrite(0x15+i,chan[i].shape);
} }
@ -179,7 +179,7 @@ int DivPlatformTIA::dispatch(DivCommand c) {
break; break;
case DIV_CMD_VOLUME: { case DIV_CMD_VOLUME: {
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].outVol=c.value;
} }
if (isMuted[c.chan]) { if (isMuted[c.chan]) {

View file

@ -137,6 +137,9 @@ const char* DivPlatformTX81Z::getEffectName(unsigned char effect) {
case 0x1f: case 0x1f:
return "1Fxx: Set PM depth (0 to 7F)"; return "1Fxx: Set PM depth (0 to 7F)";
break; break;
case 0x30:
return "30xx: Toggle hard envelope reset on new notes";
break;
} }
return NULL; return NULL;
} }
@ -184,8 +187,8 @@ void DivPlatformTX81Z::tick() {
for (int i=0; i<8; i++) { for (int i=0; i<8; i++) {
chan[i].std.next(); chan[i].std.next();
if (chan[i].std.hadVol) { if (chan[i].std.vol.had) {
chan[i].outVol=(chan[i].vol*MIN(127,chan[i].std.vol))/127; chan[i].outVol=(chan[i].vol*MIN(127,chan[i].std.vol.val))/127;
for (int j=0; j<4; j++) { for (int j=0; j<4; j++) {
unsigned short baseAddr=chanOffs[i]|opOffs[j]; unsigned short baseAddr=chanOffs[i]|opOffs[j];
DivInstrumentFM::Operator& op=chan[i].state.op[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].inPorta) {
if (chan[i].std.arpMode) { if (chan[i].std.arp.mode) {
chan[i].baseFreq=NOTE_LINEAR(chan[i].std.arp); chan[i].baseFreq=NOTE_LINEAR(chan[i].std.arp.val);
} else { } 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; chan[i].freqChanged=true;
} else { } 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].baseFreq=NOTE_LINEAR(chan[i].note);
chan[i].freqChanged=true; chan[i].freqChanged=true;
} }
} }
if (chan[i].std.hadDuty) { if (chan[i].std.duty.had) {
if (chan[i].std.duty>0) { if (chan[i].std.duty.val>0) {
rWrite(0x0f,0x80|(0x20-chan[i].std.duty)); rWrite(0x0f,0x80|(0x20-chan[i].std.duty.val));
} else { } else {
rWrite(0x0f,0); rWrite(0x0f,0);
} }
} }
if (chan[i].std.hadWave) { if (chan[i].std.wave.had) {
rWrite(0x1b,chan[i].std.wave&3); rWrite(0x1b,chan[i].std.wave.val&3);
} }
if (chan[i].std.hadEx1) { if (chan[i].std.ex1.had) {
amDepth=chan[i].std.ex1; amDepth=chan[i].std.ex1.val;
immWrite(0x19,amDepth); immWrite(0x19,amDepth);
} }
if (chan[i].std.hadEx2) { if (chan[i].std.ex2.had) {
pmDepth=chan[i].std.ex2; pmDepth=chan[i].std.ex2.val;
immWrite(0x19,0x80|pmDepth); immWrite(0x19,0x80|pmDepth);
} }
if (chan[i].std.hadEx3) { if (chan[i].std.ex3.had) {
immWrite(0x18,chan[i].std.ex3); immWrite(0x18,chan[i].std.ex3.val);
} }
if (chan[i].std.hadAlg) { if (chan[i].std.alg.had) {
chan[i].state.alg=chan[i].std.alg; chan[i].state.alg=chan[i].std.alg.val;
if (isMuted[i]) { if (isMuted[i]) {
immWrite(chanOffs[i]+ADDR_LR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3)|0x40); immWrite(chanOffs[i]+ADDR_LR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3)|0x40);
} else { } else {
@ -260,82 +263,99 @@ void DivPlatformTX81Z::tick() {
} }
} }
} }
if (chan[i].std.hadFb) { if (chan[i].std.fb.had) {
chan[i].state.fb=chan[i].std.fb; chan[i].state.fb=chan[i].std.fb.val;
if (isMuted[i]) { if (isMuted[i]) {
immWrite(chanOffs[i]+ADDR_LR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3)|0x40); immWrite(chanOffs[i]+ADDR_LR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3)|0x40);
} else { } 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)); 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) { if (chan[i].std.fms.had) {
chan[i].state.fms=chan[i].std.fms; 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)); rWrite(chanOffs[i]+ADDR_FMS_AMS,((chan[i].state.fms&7)<<4)|(chan[i].state.ams&3));
} }
if (chan[i].std.hadAms) { if (chan[i].std.ams.had) {
chan[i].state.ams=chan[i].std.ams; 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)); rWrite(chanOffs[i]+ADDR_FMS_AMS,((chan[i].state.fms&7)<<4)|(chan[i].state.ams&3));
} }
for (int j=0; j<4; j++) { for (int j=0; j<4; j++) {
unsigned short baseAddr=chanOffs[i]|opOffs[j]; unsigned short baseAddr=chanOffs[i]|opOffs[j];
DivInstrumentFM::Operator& op=chan[i].state.op[j]; DivInstrumentFM::Operator& op=chan[i].state.op[j];
DivMacroInt::IntOp& m=chan[i].std.op[j]; DivMacroInt::IntOp& m=chan[i].std.op[j];
if (m.hadAm) { if (m.am.had) {
op.am=m.am; op.am=m.am.val;
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7)); rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
} }
if (m.hadAr) { if (m.ar.had) {
op.ar=m.ar; op.ar=m.ar.val;
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.egt<<5)|(op.rs<<6)); rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.egt<<5)|(op.rs<<6));
} }
if (m.hadDr) { if (m.dr.had) {
op.dr=m.dr; op.dr=m.dr.val;
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7)); rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
} }
if (m.hadMult) { if (m.mult.had) {
op.mult=m.mult; op.mult=m.mult.val;
rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4)); rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4));
} }
if (m.hadRr) { if (m.rr.had) {
op.rr=m.rr; op.rr=m.rr.val;
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4)); rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
} }
if (m.hadSl) { if (m.sl.had) {
op.sl=m.sl; op.sl=m.sl.val;
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4)); rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
} }
if (m.hadTl) { if (m.tl.had) {
op.tl=127-m.tl; op.tl=127-m.tl.val;
if (isOutput[chan[i].state.alg][j]) { if (isOutput[chan[i].state.alg][j]) {
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127)); rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127));
} else { } else {
rWrite(baseAddr+ADDR_TL,op.tl); rWrite(baseAddr+ADDR_TL,op.tl);
} }
} }
if (m.hadRs) { if (m.rs.had) {
op.rs=m.rs; op.rs=m.rs.val;
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.egt<<5)|(op.rs<<6)); rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.egt<<5)|(op.rs<<6));
} }
if (m.hadDt) { if (m.dt.had) {
op.dt=m.dt; op.dt=m.dt.val;
rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4)); rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4));
} }
if (m.hadD2r) { if (m.d2r.had) {
op.d2r=m.d2r; op.d2r=m.d2r.val;
rWrite(baseAddr+ADDR_DT2_D2R,(op.d2r&31)|(op.dt2<<6)); rWrite(baseAddr+ADDR_DT2_D2R,(op.d2r&31)|(op.dt2<<6));
} }
if (m.hadDt2) { if (m.dt2.had) {
op.dt2=m.dt2; op.dt2=m.dt2.val;
rWrite(baseAddr+ADDR_DT2_D2R,(op.d2r&31)|(op.dt2<<6)); rWrite(baseAddr+ADDR_DT2_D2R,(op.d2r&31)|(op.dt2<<6));
} }
} }
if (chan[i].keyOn || chan[i].keyOff) { 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]) { if (isMuted[i]) {
immWrite(chanOffs[i]+ADDR_LR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3)|0x00); immWrite(chanOffs[i]+ADDR_LR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3)|0x00);
} else { } else {
//if (chan[i].keyOn) immWrite(0x08,i); //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)); 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; chan[i].keyOff=false;
} }
} }
@ -401,7 +421,7 @@ int DivPlatformTX81Z::dispatch(DivCommand c) {
} }
chan[c.chan].std.init(ins); 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; 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_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,((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; chan[c.chan].insChanged=false;
@ -463,7 +484,7 @@ int DivPlatformTX81Z::dispatch(DivCommand c) {
break; break;
case DIV_CMD_VOLUME: { case DIV_CMD_VOLUME: {
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].outVol=c.value;
} }
for (int i=0; i<4; i++) { for (int i=0; i<4; i++) {
@ -596,6 +617,9 @@ int DivPlatformTX81Z::dispatch(DivCommand c) {
immWrite(0x19,0x80|pmDepth); immWrite(0x19,0x80|pmDepth);
break; break;
} }
case DIV_CMD_FM_HARD_RESET:
chan[c.chan].hardReset=c.value;
break;
case DIV_CMD_STD_NOISE_FREQ: { case DIV_CMD_STD_NOISE_FREQ: {
if (c.chan!=7) break; if (c.chan!=7) break;
if (c.value) { 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_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,((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) { if (chan[i].active) {
chan[i].keyOn=true; chan[i].keyOn=true;
chan[i].freqChanged=true; chan[i].freqChanged=true;

View file

@ -38,10 +38,30 @@ class DivPlatformTX81Z: public DivDispatch {
int freq, baseFreq, pitch, note; int freq, baseFreq, pitch, note;
unsigned char ins; unsigned char ins;
signed char konCycles; 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; int vol, outVol;
unsigned char chVolL, chVolR; 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]; Channel chan[8];
struct QueuedWrite { struct QueuedWrite {

View file

@ -158,30 +158,30 @@ int DivPlatformVERA::calcNoteFreq(int ch, int note) {
void DivPlatformVERA::tick() { void DivPlatformVERA::tick() {
for (int i=0; i<16; i++) { for (int i=0; i<16; i++) {
chan[i].std.next(); chan[i].std.next();
if (chan[i].std.hadVol) { if (chan[i].std.vol.had) {
chan[i].outVol=MAX(chan[i].vol+chan[i].std.vol-63,0); chan[i].outVol=MAX(chan[i].vol+chan[i].std.vol.val-63,0);
rWriteLo(i,2,chan[i].outVol); rWriteLo(i,2,chan[i].outVol);
} }
if (chan[i].std.hadArp) { if (chan[i].std.arp.had) {
if (!chan[i].inPorta) { if (!chan[i].inPorta) {
if (chan[i].std.arpMode) { if (chan[i].std.arp.mode) {
chan[i].baseFreq=calcNoteFreq(0,chan[i].std.arp); chan[i].baseFreq=calcNoteFreq(0,chan[i].std.arp.val);
} else { } 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; chan[i].freqChanged=true;
} else { } 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].baseFreq=calcNoteFreq(0,chan[i].note);
chan[i].freqChanged=true; chan[i].freqChanged=true;
} }
} }
if (chan[i].std.hadDuty) { if (chan[i].std.duty.had) {
rWriteLo(i,3,chan[i].std.duty); rWriteLo(i,3,chan[i].std.duty.val);
} }
if (chan[i].std.hadWave) { if (chan[i].std.wave.had) {
rWriteHi(i,3,chan[i].std.wave); rWriteHi(i,3,chan[i].std.wave.val);
} }
if (chan[i].freqChanged) { if (chan[i].freqChanged) {
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,8); chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,8);
@ -193,21 +193,21 @@ void DivPlatformVERA::tick() {
} }
// PCM // PCM
chan[16].std.next(); chan[16].std.next();
if (chan[16].std.hadVol) { if (chan[16].std.vol.had) {
chan[16].outVol=MAX(chan[16].vol+MIN(chan[16].std.vol/4,15)-15,0); chan[16].outVol=MAX(chan[16].vol+MIN(chan[16].std.vol.val/4,15)-15,0);
rWritePCMVol(chan[16].outVol&15); rWritePCMVol(chan[16].outVol&15);
} }
if (chan[16].std.hadArp) { if (chan[16].std.arp.had) {
if (!chan[16].inPorta) { if (!chan[16].inPorta) {
if (chan[16].std.arpMode) { if (chan[16].std.arp.mode) {
chan[16].baseFreq=calcNoteFreq(16,chan[16].std.arp); chan[16].baseFreq=calcNoteFreq(16,chan[16].std.arp.val);
} else { } 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; chan[16].freqChanged=true;
} else { } 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].baseFreq=calcNoteFreq(16,chan[16].note);
chan[16].freqChanged=true; chan[16].freqChanged=true;
} }
@ -311,7 +311,7 @@ int DivPlatformVERA::dispatch(DivCommand c) {
break; break;
} }
case DIV_CMD_LEGATO: 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].freqChanged=true;
chan[c.chan].note=c.value; chan[c.chan].note=c.value;
break; break;

View file

@ -94,28 +94,28 @@ void DivPlatformVIC20::writeOutVol(int ch) {
void DivPlatformVIC20::tick() { void DivPlatformVIC20::tick() {
for (int i=0; i<4; i++) { for (int i=0; i<4; i++) {
chan[i].std.next(); chan[i].std.next();
if (chan[i].std.hadVol) { if (chan[i].std.vol.had) {
int env=chan[i].std.vol; int env=chan[i].std.vol.val;
calcAndWriteOutVol(i,env); calcAndWriteOutVol(i,env);
} }
if (chan[i].std.hadArp) { if (chan[i].std.arp.had) {
if (!chan[i].inPorta) { if (!chan[i].inPorta) {
if (chan[i].std.arpMode) { if (chan[i].std.arp.mode) {
chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp); chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val);
} else { } 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; chan[i].freqChanged=true;
} else { } 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].baseFreq=NOTE_PERIODIC(chan[i].note);
chan[i].freqChanged=true; chan[i].freqChanged=true;
} }
} }
if (chan[i].std.hadWave) { if (chan[i].std.wave.had) {
if (chan[i].wave!=chan[i].std.wave) { if (chan[i].wave!=chan[i].std.wave.val) {
chan[i].wave=chan[i].std.wave&0x0f; chan[i].wave=chan[i].std.wave.val&0x0f;
chan[i].keyOn=true; chan[i].keyOn=true;
} }
} }
@ -183,7 +183,7 @@ int DivPlatformVIC20::dispatch(DivCommand c) {
case DIV_CMD_VOLUME: case DIV_CMD_VOLUME:
if (chan[c.chan].vol!=c.value) { if (chan[c.chan].vol!=c.value) {
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); calcAndWriteOutVol(c.chan,15);
} }
} }
@ -223,7 +223,7 @@ int DivPlatformVIC20::dispatch(DivCommand c) {
break; break;
} }
case DIV_CMD_LEGATO: 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].freqChanged=true;
chan[c.chan].note=c.value; chan[c.chan].note=c.value;
break; break;

View file

@ -140,16 +140,16 @@ void DivPlatformVRC6::tick() {
// 16 for pulse; 14 for saw // 16 for pulse; 14 for saw
int CHIP_DIVIDER=(i==2)?14:16; int CHIP_DIVIDER=(i==2)?14:16;
chan[i].std.next(); chan[i].std.next();
if (chan[i].std.hadVol) { if (chan[i].std.vol.had) {
if (i==2) { // sawtooth 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<0) chan[i].outVol=0;
if (chan[i].outVol>63) chan[i].outVol=63; if (chan[i].outVol>63) chan[i].outVol=63;
if (!isMuted[i]) { if (!isMuted[i]) {
chWrite(i,0,chan[i].outVol); chWrite(i,0,chan[i].outVol);
} }
} else { // pulse } 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<0) chan[i].outVol=0;
if (chan[i].outVol>15) chan[i].outVol=15; if (chan[i].outVol>15) chan[i].outVol=15;
if ((!isMuted[i]) && (!chan[i].pcm)) { 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].inPorta) {
if (chan[i].std.arpMode) { if (chan[i].std.arp.mode) {
chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp); chan[i].baseFreq=NOTE_PERIODIC(chan[i].std.arp.val);
} else { } 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; chan[i].freqChanged=true;
} else { } 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].baseFreq=NOTE_PERIODIC(chan[i].note);
chan[i].freqChanged=true; chan[i].freqChanged=true;
} }
} }
if (chan[i].std.hadDuty) { if (chan[i].std.duty.had) {
chan[i].duty=chan[i].std.duty; chan[i].duty=chan[i].std.duty.val;
if ((!isMuted[i]) && (i!=2) && (!chan[i].pcm)) { // pulse if ((!isMuted[i]) && (i!=2) && (!chan[i].pcm)) { // pulse
chWrite(i,0,(chan[i].outVol&0xf)|((chan[i].duty&7)<<4)); 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: case DIV_CMD_VOLUME:
if (chan[c.chan].vol!=c.value) { if (chan[c.chan].vol!=c.value) {
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].outVol=c.value;
} }
if (!isMuted[c.chan]) { if (!isMuted[c.chan]) {
@ -371,7 +371,7 @@ int DivPlatformVRC6::dispatch(DivCommand c) {
} }
break; break;
case DIV_CMD_LEGATO: 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].freqChanged=true;
chan[c.chan].note=c.value; chan[c.chan].note=c.value;
break; break;

View file

@ -339,41 +339,41 @@ void DivPlatformX1_010::updateEnvelope(int ch) {
void DivPlatformX1_010::tick() { void DivPlatformX1_010::tick() {
for (int i=0; i<16; i++) { for (int i=0; i<16; i++) {
chan[i].std.next(); chan[i].std.next();
if (chan[i].std.hadVol) { if (chan[i].std.vol.had) {
signed char macroVol=((chan[i].vol&15)*MIN(chan[i].furnacePCM?64:15,chan[i].std.vol))/(chan[i].furnacePCM?64:15); 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)) { if ((!isMuted[i]) && (macroVol!=chan[i].outVol)) {
chan[i].outVol=macroVol; chan[i].outVol=macroVol;
chan[i].envChanged=true; chan[i].envChanged=true;
} }
} }
if ((!chan[i].pcm) || chan[i].furnacePCM) { 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].inPorta) {
if (chan[i].std.arpMode) { if (chan[i].std.arp.mode) {
chan[i].baseFreq=NoteX1_010(i,chan[i].std.arp); chan[i].baseFreq=NoteX1_010(i,chan[i].std.arp.val);
} else { } 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; chan[i].freqChanged=true;
} else { } 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].baseFreq=NoteX1_010(i,chan[i].note);
chan[i].freqChanged=true; chan[i].freqChanged=true;
} }
} }
} }
if (chan[i].std.hadWave && !chan[i].pcm) { if (chan[i].std.wave.had && !chan[i].pcm) {
if (chan[i].wave!=chan[i].std.wave || chan[i].ws.activeChanged()) { if (chan[i].wave!=chan[i].std.wave.val || chan[i].ws.activeChanged()) {
chan[i].wave=chan[i].std.wave; chan[i].wave=chan[i].std.wave.val;
if (!chan[i].pcm) { if (!chan[i].pcm) {
chan[i].ws.changeWave1(chan[i].wave); chan[i].ws.changeWave1(chan[i].wave);
if (!chan[i].keyOff) chan[i].keyOn=true; if (!chan[i].keyOff) chan[i].keyOn=true;
} }
} }
} }
if (chan[i].std.hadEx1) { if (chan[i].std.ex1.had) {
bool nextEnable=(chan[i].std.ex1&1); bool nextEnable=(chan[i].std.ex1.val&1);
if (nextEnable!=(chan[i].env.flag.envEnable)) { if (nextEnable!=(chan[i].env.flag.envEnable)) {
chan[i].env.flag.envEnable=nextEnable; chan[i].env.flag.envEnable=nextEnable;
if (!chan[i].pcm) { if (!chan[i].pcm) {
@ -383,42 +383,42 @@ void DivPlatformX1_010::tick() {
refreshControl(i); refreshControl(i);
} }
} }
bool nextOneshot=(chan[i].std.ex1&2); bool nextOneshot=(chan[i].std.ex1.val&2);
if (nextOneshot!=(chan[i].env.flag.envOneshot)) { if (nextOneshot!=(chan[i].env.flag.envOneshot)) {
chan[i].env.flag.envOneshot=nextOneshot; chan[i].env.flag.envOneshot=nextOneshot;
if (!chan[i].pcm) { if (!chan[i].pcm) {
refreshControl(i); refreshControl(i);
} }
} }
bool nextSplit=(chan[i].std.ex1&4); bool nextSplit=(chan[i].std.ex1.val&4);
if (nextSplit!=(chan[i].env.flag.envSplit)) { if (nextSplit!=(chan[i].env.flag.envSplit)) {
chan[i].env.flag.envSplit=nextSplit; chan[i].env.flag.envSplit=nextSplit;
if (!isMuted[i] && !chan[i].pcm) { if (!isMuted[i] && !chan[i].pcm) {
chan[i].envChanged=true; 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)) { if (nextHinvR!=(chan[i].env.flag.envHinvR)) {
chan[i].env.flag.envHinvR=nextHinvR; chan[i].env.flag.envHinvR=nextHinvR;
if (!isMuted[i] && !chan[i].pcm) { if (!isMuted[i] && !chan[i].pcm) {
chan[i].envChanged=true; 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)) { if (nextVinvR!=(chan[i].env.flag.envVinvR)) {
chan[i].env.flag.envVinvR=nextVinvR; chan[i].env.flag.envVinvR=nextVinvR;
if (!isMuted[i] && !chan[i].pcm) { if (!isMuted[i] && !chan[i].pcm) {
chan[i].envChanged=true; 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)) { if (nextHinvL!=(chan[i].env.flag.envHinvL)) {
chan[i].env.flag.envHinvL=nextHinvL; chan[i].env.flag.envHinvL=nextHinvL;
if (!isMuted[i] && !chan[i].pcm) { if (!isMuted[i] && !chan[i].pcm) {
chan[i].envChanged=true; 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)) { if (nextVinvL!=(chan[i].env.flag.envVinvL)) {
chan[i].env.flag.envVinvL=nextVinvL; chan[i].env.flag.envVinvL=nextVinvL;
if (!isMuted[i] && !chan[i].pcm) { if (!isMuted[i] && !chan[i].pcm) {
@ -426,9 +426,9 @@ void DivPlatformX1_010::tick() {
} }
} }
} }
if (chan[i].std.hadEx2) { if (chan[i].std.ex2.had) {
if (chan[i].env.shape!=chan[i].std.ex2) { if (chan[i].env.shape!=chan[i].std.ex2.val) {
chan[i].env.shape=chan[i].std.ex2; chan[i].env.shape=chan[i].std.ex2.val;
if (!chan[i].pcm) { if (!chan[i].pcm) {
if (chan[i].env.flag.envEnable && (!isMuted[i])) { if (chan[i].env.flag.envEnable && (!isMuted[i])) {
chan[i].envChanged=true; chan[i].envChanged=true;
@ -437,18 +437,18 @@ void DivPlatformX1_010::tick() {
} }
} }
} }
if (chan[i].std.hadEx3) { if (chan[i].std.ex3.had) {
chan[i].autoEnvNum=chan[i].std.ex3; chan[i].autoEnvNum=chan[i].std.ex3.val;
if (!chan[i].pcm) { if (!chan[i].pcm) {
chan[i].freqChanged=true; 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) { if (chan[i].std.alg.had) {
chan[i].autoEnvDen=chan[i].std.alg; chan[i].autoEnvDen=chan[i].std.alg.val;
if (!chan[i].pcm) { if (!chan[i].pcm) {
chan[i].freqChanged=true; 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) { if (chan[i].active) {
@ -601,7 +601,7 @@ int DivPlatformX1_010::dispatch(DivCommand c) {
case DIV_CMD_VOLUME: case DIV_CMD_VOLUME:
if (chan[c.chan].vol!=c.value) { if (chan[c.chan].vol!=c.value) {
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) { if (chan[c.chan].outVol!=c.value) {
chan[c.chan].outVol=c.value; chan[c.chan].outVol=c.value;
if (!isMuted[c.chan]) { if (!isMuted[c.chan]) {
@ -612,7 +612,7 @@ int DivPlatformX1_010::dispatch(DivCommand c) {
} }
break; break;
case DIV_CMD_GET_VOLUME: 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].vol;
} }
return chan[c.chan].outVol; return chan[c.chan].outVol;
@ -685,7 +685,7 @@ int DivPlatformX1_010::dispatch(DivCommand c) {
} }
case DIV_CMD_LEGATO: case DIV_CMD_LEGATO:
chan[c.chan].note=c.value; 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; chan[c.chan].freqChanged=true;
break; break;
case DIV_CMD_PRE_PORTA: case DIV_CMD_PRE_PORTA:

View file

@ -309,6 +309,9 @@ const char* DivPlatformYM2610::getEffectName(unsigned char effect) {
case 0x29: case 0x29:
return "29xy: Set SSG auto-envelope (x: numerator; y: denominator)"; return "29xy: Set SSG auto-envelope (x: numerator; y: denominator)";
break; break;
case 0x30:
return "30xx: Toggle hard envelope reset on new notes";
break;
} }
return NULL; return NULL;
} }
@ -376,8 +379,8 @@ void DivPlatformYM2610::tick() {
if (i==1 && extMode) continue; if (i==1 && extMode) continue;
chan[i].std.next(); chan[i].std.next();
if (chan[i].std.hadVol) { if (chan[i].std.vol.had) {
chan[i].outVol=(chan[i].vol*MIN(127,chan[i].std.vol))/127; chan[i].outVol=(chan[i].vol*MIN(127,chan[i].std.vol.val))/127;
for (int j=0; j<4; j++) { for (int j=0; j<4; j++) {
unsigned short baseAddr=chanOffs[i]|opOffs[j]; unsigned short baseAddr=chanOffs[i]|opOffs[j];
DivInstrumentFM::Operator& op=chan[i].state.op[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].inPorta) {
if (chan[i].std.arpMode) { if (chan[i].std.arp.mode) {
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].std.arp); chan[i].baseFreq=NOTE_FREQUENCY(chan[i].std.arp.val);
} else { } 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; chan[i].freqChanged=true;
} else { } 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].baseFreq=NOTE_FREQUENCY(chan[i].note);
chan[i].freqChanged=true; chan[i].freqChanged=true;
} }
} }
if (chan[i].std.hadAlg) { if (chan[i].std.alg.had) {
chan[i].state.alg=chan[i].std.alg; 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)); 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++) { if (!parent->song.algMacroBehavior) for (int j=0; j<4; j++) {
unsigned short baseAddr=chanOffs[i]|opOffs[j]; unsigned short baseAddr=chanOffs[i]|opOffs[j];
@ -422,74 +425,92 @@ void DivPlatformYM2610::tick() {
} }
} }
} }
if (chan[i].std.hadFb) { if (chan[i].std.fb.had) {
chan[i].state.fb=chan[i].std.fb; 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)); rWrite(chanOffs[i]+ADDR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3));
} }
if (chan[i].std.hadFms) { if (chan[i].std.fms.had) {
chan[i].state.fms=chan[i].std.fms; 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)); 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) { if (chan[i].std.ams.had) {
chan[i].state.ams=chan[i].std.ams; 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)); 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++) { for (int j=0; j<4; j++) {
unsigned short baseAddr=chanOffs[i]|opOffs[j]; unsigned short baseAddr=chanOffs[i]|opOffs[j];
DivInstrumentFM::Operator& op=chan[i].state.op[j]; DivInstrumentFM::Operator& op=chan[i].state.op[j];
DivMacroInt::IntOp& m=chan[i].std.op[j]; DivMacroInt::IntOp& m=chan[i].std.op[j];
if (m.hadAm) { if (m.am.had) {
op.am=m.am; op.am=m.am.val;
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7)); rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
} }
if (m.hadAr) { if (m.ar.had) {
op.ar=m.ar; op.ar=m.ar.val;
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6)); rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6));
} }
if (m.hadDr) { if (m.dr.had) {
op.dr=m.dr; op.dr=m.dr.val;
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7)); rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
} }
if (m.hadMult) { if (m.mult.had) {
op.mult=m.mult; op.mult=m.mult.val;
rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4)); rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4));
} }
if (m.hadRr) { if (m.rr.had) {
op.rr=m.rr; op.rr=m.rr.val;
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4)); rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
} }
if (m.hadSl) { if (m.sl.had) {
op.sl=m.sl; op.sl=m.sl.val;
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4)); rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
} }
if (m.hadTl) { if (m.tl.had) {
op.tl=127-m.tl; op.tl=127-m.tl.val;
if (isOutput[chan[i].state.alg][j]) { if (isOutput[chan[i].state.alg][j]) {
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127)); rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127));
} else { } else {
rWrite(baseAddr+ADDR_TL,op.tl); rWrite(baseAddr+ADDR_TL,op.tl);
} }
} }
if (m.hadRs) { if (m.rs.had) {
op.rs=m.rs; op.rs=m.rs.val;
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6)); rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6));
} }
if (m.hadDt) { if (m.dt.had) {
op.dt=m.dt; op.dt=m.dt.val;
rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4)); rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4));
} }
if (m.hadD2r) { if (m.d2r.had) {
op.d2r=m.d2r; op.d2r=m.d2r.val;
rWrite(baseAddr+ADDR_DT2_D2R,op.d2r&31); rWrite(baseAddr+ADDR_DT2_D2R,op.d2r&31);
} }
if (m.hadSsg) { if (m.ssg.had) {
op.ssgEnv=m.ssg; op.ssgEnv=m.ssg.val;
rWrite(baseAddr+ADDR_SSG,op.ssgEnv&15); rWrite(baseAddr+ADDR_SSG,op.ssgEnv&15);
} }
} }
if (chan[i].keyOn || chan[i].keyOff) { 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]); 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; chan[i].keyOff=false;
} }
} }
@ -498,22 +519,22 @@ void DivPlatformYM2610::tick() {
if (chan[13].furnacePCM) { if (chan[13].furnacePCM) {
chan[13].std.next(); chan[13].std.next();
if (chan[13].std.hadVol) { if (chan[13].std.vol.had) {
chan[13].outVol=(chan[13].vol*MIN(64,chan[13].std.vol))/64; chan[13].outVol=(chan[13].vol*MIN(64,chan[13].std.vol.val))/64;
immWrite(0x1b,chan[13].outVol); immWrite(0x1b,chan[13].outVol);
} }
if (chan[13].std.hadArp) { if (chan[13].std.arp.had) {
if (!chan[13].inPorta) { if (!chan[13].inPorta) {
if (chan[13].std.arpMode) { if (chan[13].std.arp.mode) {
chan[13].baseFreq=NOTE_ADPCMB(chan[13].std.arp); chan[13].baseFreq=NOTE_ADPCMB(chan[13].std.arp.val);
} else { } 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; chan[13].freqChanged=true;
} else { } 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].baseFreq=NOTE_ADPCMB(chan[13].note);
chan[13].freqChanged=true; chan[13].freqChanged=true;
} }
@ -608,7 +629,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
if (skipRegisterWrites) break; if (skipRegisterWrites) break;
if (chan[c.chan].furnacePCM) { if (chan[c.chan].furnacePCM) {
chan[c.chan].std.init(ins); 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; chan[c.chan].outVol=chan[c.chan].vol;
immWrite(0x1b,chan[c.chan].outVol); immWrite(0x1b,chan[c.chan].outVol);
} }
@ -685,7 +706,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
DivInstrument* ins=parent->getIns(chan[c.chan].ins); DivInstrument* ins=parent->getIns(chan[c.chan].ins);
chan[c.chan].std.init(ins); chan[c.chan].std.init(ins);
if (c.chan<4) { 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; chan[c.chan].outVol=chan[c.chan].vol;
} }
} }
@ -764,7 +785,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
break; break;
case DIV_CMD_VOLUME: { case DIV_CMD_VOLUME: {
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].outVol=c.value;
} }
if (c.chan>12) { // ADPCM-B if (c.chan>12) { // ADPCM-B
@ -930,6 +951,9 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
} }
break; break;
} }
case DIV_CMD_FM_HARD_RESET:
chan[c.chan].hardReset=c.value;
break;
case DIV_ALWAYS_SET_VOLUME: case DIV_ALWAYS_SET_VOLUME:
return 0; return 0;
break; break;

View file

@ -46,7 +46,7 @@ class DivPlatformYM2610: public DivDispatch {
int freq, baseFreq, pitch, note; int freq, baseFreq, pitch, note;
unsigned char ins, psgMode, autoEnvNum, autoEnvDen; unsigned char ins, psgMode, autoEnvNum, autoEnvDen;
signed char konCycles; 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 vol, outVol;
int sample; int sample;
unsigned char pan; unsigned char pan;
@ -70,6 +70,7 @@ class DivPlatformYM2610: public DivDispatch {
portaPause(false), portaPause(false),
inPorta(false), inPorta(false),
furnacePCM(false), furnacePCM(false),
hardReset(false),
vol(0), vol(0),
outVol(15), outVol(15),
sample(-1), sample(-1),

View file

@ -373,6 +373,9 @@ const char* DivPlatformYM2610B::getEffectName(unsigned char effect) {
case 0x29: case 0x29:
return "29xy: Set SSG auto-envelope (x: numerator; y: denominator)"; return "29xy: Set SSG auto-envelope (x: numerator; y: denominator)";
break; break;
case 0x30:
return "30xx: Toggle hard envelope reset on new notes";
break;
} }
return NULL; return NULL;
} }
@ -440,8 +443,8 @@ void DivPlatformYM2610B::tick() {
if (i==2 && extMode) continue; if (i==2 && extMode) continue;
chan[i].std.next(); chan[i].std.next();
if (chan[i].std.hadVol) { if (chan[i].std.vol.had) {
chan[i].outVol=(chan[i].vol*MIN(127,chan[i].std.vol))/127; chan[i].outVol=(chan[i].vol*MIN(127,chan[i].std.vol.val))/127;
for (int j=0; j<4; j++) { for (int j=0; j<4; j++) {
unsigned short baseAddr=chanOffs[i]|opOffs[j]; unsigned short baseAddr=chanOffs[i]|opOffs[j];
DivInstrumentFM::Operator& op=chan[i].state.op[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].inPorta) {
if (chan[i].std.arpMode) { if (chan[i].std.arp.mode) {
chan[i].baseFreq=NOTE_FREQUENCY(chan[i].std.arp); chan[i].baseFreq=NOTE_FREQUENCY(chan[i].std.arp.val);
} else { } 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; chan[i].freqChanged=true;
} else { } 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].baseFreq=NOTE_FREQUENCY(chan[i].note);
chan[i].freqChanged=true; chan[i].freqChanged=true;
} }
} }
if (chan[i].std.hadAlg) { if (chan[i].std.alg.had) {
chan[i].state.alg=chan[i].std.alg; 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)); 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++) { if (!parent->song.algMacroBehavior) for (int j=0; j<4; j++) {
unsigned short baseAddr=chanOffs[i]|opOffs[j]; unsigned short baseAddr=chanOffs[i]|opOffs[j];
@ -486,74 +489,92 @@ void DivPlatformYM2610B::tick() {
} }
} }
} }
if (chan[i].std.hadFb) { if (chan[i].std.fb.had) {
chan[i].state.fb=chan[i].std.fb; 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)); rWrite(chanOffs[i]+ADDR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3));
} }
if (chan[i].std.hadFms) { if (chan[i].std.fms.had) {
chan[i].state.fms=chan[i].std.fms; 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)); 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) { if (chan[i].std.ams.had) {
chan[i].state.ams=chan[i].std.ams; 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)); 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++) { for (int j=0; j<4; j++) {
unsigned short baseAddr=chanOffs[i]|opOffs[j]; unsigned short baseAddr=chanOffs[i]|opOffs[j];
DivInstrumentFM::Operator& op=chan[i].state.op[j]; DivInstrumentFM::Operator& op=chan[i].state.op[j];
DivMacroInt::IntOp& m=chan[i].std.op[j]; DivMacroInt::IntOp& m=chan[i].std.op[j];
if (m.hadAm) { if (m.am.had) {
op.am=m.am; op.am=m.am.val;
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7)); rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
} }
if (m.hadAr) { if (m.ar.had) {
op.ar=m.ar; op.ar=m.ar.val;
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6)); rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6));
} }
if (m.hadDr) { if (m.dr.had) {
op.dr=m.dr; op.dr=m.dr.val;
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7)); rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
} }
if (m.hadMult) { if (m.mult.had) {
op.mult=m.mult; op.mult=m.mult.val;
rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4)); rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4));
} }
if (m.hadRr) { if (m.rr.had) {
op.rr=m.rr; op.rr=m.rr.val;
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4)); rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
} }
if (m.hadSl) { if (m.sl.had) {
op.sl=m.sl; op.sl=m.sl.val;
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4)); rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
} }
if (m.hadTl) { if (m.tl.had) {
op.tl=127-m.tl; op.tl=127-m.tl.val;
if (isOutput[chan[i].state.alg][j]) { if (isOutput[chan[i].state.alg][j]) {
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127)); rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127));
} else { } else {
rWrite(baseAddr+ADDR_TL,op.tl); rWrite(baseAddr+ADDR_TL,op.tl);
} }
} }
if (m.hadRs) { if (m.rs.had) {
op.rs=m.rs; op.rs=m.rs.val;
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6)); rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6));
} }
if (m.hadDt) { if (m.dt.had) {
op.dt=m.dt; op.dt=m.dt.val;
rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4)); rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4));
} }
if (m.hadD2r) { if (m.d2r.had) {
op.d2r=m.d2r; op.d2r=m.d2r.val;
rWrite(baseAddr+ADDR_DT2_D2R,op.d2r&31); rWrite(baseAddr+ADDR_DT2_D2R,op.d2r&31);
} }
if (m.hadSsg) { if (m.ssg.had) {
op.ssgEnv=m.ssg; op.ssgEnv=m.ssg.val;
rWrite(baseAddr+ADDR_SSG,op.ssgEnv&15); rWrite(baseAddr+ADDR_SSG,op.ssgEnv&15);
} }
} }
if (chan[i].keyOn || chan[i].keyOff) { 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]); 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; chan[i].keyOff=false;
} }
} }
@ -561,22 +582,22 @@ void DivPlatformYM2610B::tick() {
if (chan[15].furnacePCM) { if (chan[15].furnacePCM) {
chan[15].std.next(); chan[15].std.next();
if (chan[15].std.hadVol) { if (chan[15].std.vol.had) {
chan[15].outVol=(chan[15].vol*MIN(64,chan[15].std.vol))/64; chan[15].outVol=(chan[15].vol*MIN(64,chan[15].std.vol.val))/64;
immWrite(0x1b,chan[15].outVol); immWrite(0x1b,chan[15].outVol);
} }
if (chan[15].std.hadArp) { if (chan[15].std.arp.had) {
if (!chan[15].inPorta) { if (!chan[15].inPorta) {
if (chan[15].std.arpMode) { if (chan[15].std.arp.mode) {
chan[15].baseFreq=NOTE_ADPCMB(chan[15].std.arp); chan[15].baseFreq=NOTE_ADPCMB(chan[15].std.arp.val);
} else { } 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; chan[15].freqChanged=true;
} else { } 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].baseFreq=NOTE_ADPCMB(chan[15].note);
chan[15].freqChanged=true; chan[15].freqChanged=true;
} }
@ -671,7 +692,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) {
if (skipRegisterWrites) break; if (skipRegisterWrites) break;
if (chan[c.chan].furnacePCM) { if (chan[c.chan].furnacePCM) {
chan[c.chan].std.init(ins); 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; chan[c.chan].outVol=chan[c.chan].vol;
immWrite(0x1b,chan[c.chan].outVol); immWrite(0x1b,chan[c.chan].outVol);
} }
@ -748,7 +769,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) {
DivInstrument* ins=parent->getIns(chan[c.chan].ins); DivInstrument* ins=parent->getIns(chan[c.chan].ins);
chan[c.chan].std.init(ins); chan[c.chan].std.init(ins);
if (c.chan<6) { 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; chan[c.chan].outVol=chan[c.chan].vol;
} }
} }
@ -827,7 +848,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) {
break; break;
case DIV_CMD_VOLUME: { case DIV_CMD_VOLUME: {
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].outVol=c.value;
} }
if (c.chan>14) { // ADPCM-B if (c.chan>14) { // ADPCM-B
@ -993,6 +1014,9 @@ int DivPlatformYM2610B::dispatch(DivCommand c) {
} }
break; break;
} }
case DIV_CMD_FM_HARD_RESET:
chan[c.chan].hardReset=c.value;
break;
case DIV_ALWAYS_SET_VOLUME: case DIV_ALWAYS_SET_VOLUME:
return 0; return 0;
break; break;

View file

@ -38,7 +38,7 @@ class DivPlatformYM2610B: public DivDispatch {
int freq, baseFreq, pitch, note; int freq, baseFreq, pitch, note;
unsigned char ins, psgMode, autoEnvNum, autoEnvDen; unsigned char ins, psgMode, autoEnvNum, autoEnvDen;
signed char konCycles; 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 vol, outVol;
int sample; int sample;
unsigned char pan; unsigned char pan;
@ -62,6 +62,7 @@ class DivPlatformYM2610B: public DivDispatch {
portaPause(false), portaPause(false),
inPorta(false), inPorta(false),
furnacePCM(false), furnacePCM(false),
hardReset(false),
vol(0), vol(0),
outVol(15), outVol(15),
sample(-1), sample(-1),

View file

@ -17,9 +17,6 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#include "blip_buf.h"
#include "song.h"
#include "wavetable.h"
#define _USE_MATH_DEFINES #define _USE_MATH_DEFINES
#include "dispatch.h" #include "dispatch.h"
#include "engine.h" #include "engine.h"
@ -64,6 +61,7 @@ const char* cmdName[DIV_CMD_MAX]={
"SAMPLE_BANK", "SAMPLE_BANK",
"SAMPLE_POS", "SAMPLE_POS",
"FM_HARD_RESET",
"FM_LFO", "FM_LFO",
"FM_LFO_WAVE", "FM_LFO_WAVE",
"FM_TL", "FM_TL",
@ -201,16 +199,24 @@ int DivEngine::dispatchCmd(DivCommand c) {
chan[c.chan].curMidiNote=-1; chan[c.chan].curMidiNote=-1;
break; break;
case DIV_CMD_INSTRUMENT: case DIV_CMD_INSTRUMENT:
output->midiOut->send(TAMidiMessage(0xc0|(c.chan&15),c.value,0)); if (chan[c.chan].lastIns!=c.value) {
output->midiOut->send(TAMidiMessage(0xc0|(c.chan&15),c.value,0));
}
break; break;
case DIV_CMD_VOLUME: 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; break;
case DIV_CMD_PITCH: { case DIV_CMD_PITCH: {
int pitchBend=8192+(c.value<<5); int pitchBend=8192+(c.value<<5);
if (pitchBend<0) pitchBend=0; if (pitchBend<0) pitchBend=0;
if (pitchBend>16383) pitchBend=16383; if (pitchBend>16383) pitchBend=16383;
output->midiOut->send(TAMidiMessage(0xe0|(c.chan&15),pitchBend&0x7f,pitchBend>>7)); if (pitchBend!=chan[c.chan].midiPitch) {
chan[c.chan].midiPitch=pitchBend;
output->midiOut->send(TAMidiMessage(0xe0|(c.chan&15),pitchBend&0x7f,pitchBend>>7));
}
break; break;
} }
default: default:
@ -235,6 +241,23 @@ bool DivEngine::perSystemEffect(int ch, unsigned char effect, unsigned char effe
case 0x20: // SN noise mode case 0x20: // SN noise mode
dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_MODE,ch,effectVal)); dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_MODE,ch,effectVal));
break; 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: default:
return false; return false;
} }
@ -335,6 +358,22 @@ bool DivEngine::perSystemEffect(int ch, unsigned char effect, unsigned char effe
case 0x18: // drum mode toggle case 0x18: // drum mode toggle
dispatchCmd(DivCommand(DIV_CMD_FM_EXTCH,ch,effectVal)); dispatchCmd(DivCommand(DIV_CMD_FM_EXTCH,ch,effectVal));
break; 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: default:
return false; return false;
} }
@ -963,6 +1002,9 @@ void DivEngine::processRow(int i, bool afterDelay) {
// volume // volume
if (pat->data[whatRow][3]!=-1) { 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 (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; chan[i].volume=pat->data[whatRow][3]<<8;
dispatchCmd(DivCommand(DIV_CMD_VOLUME,i,chan[i].volume>>8)); dispatchCmd(DivCommand(DIV_CMD_VOLUME,i,chan[i].volume>>8));
} }
@ -1436,6 +1478,11 @@ bool DivEngine::nextTick(bool noAccum) {
cycles++; cycles++;
} }
// MIDI clock
if (output) if (!skipping && output->midiOut!=NULL) {
output->midiOut->send(TAMidiMessage(TA_MIDI_CLOCK,0,0));
}
while (!pendingNotes.empty()) { while (!pendingNotes.empty()) {
DivNoteEvent& note=pendingNotes.front(); DivNoteEvent& note=pendingNotes.front();
if (note.on) { if (note.on) {
@ -1613,7 +1660,7 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi
if (softLocked) { if (softLocked) {
if (!isBusy.try_lock()) { if (!isBusy.try_lock()) {
logV("audio is soft-locked (%d)\n",softLockCount++); logV("audio is soft-locked (%d)",softLockCount++);
return; return;
} }
} else { } 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(); output->midiIn->queue.pop();
} }
@ -1732,8 +1779,11 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi
if (!playing) { if (!playing) {
if (out!=NULL) { if (out!=NULL) {
memcpy(oscBuf[0],out[0],size*sizeof(float)); for (unsigned int i=0; i<size; i++) {
memcpy(oscBuf[1],out[1],size*sizeof(float)); oscBuf[0][oscWritePos]=out[0][i];
oscBuf[1][oscWritePos]=out[1][i];
if (++oscWritePos>=32768) oscWritePos=0;
}
oscSize=size; oscSize=size;
} }
isBusy.unlock(); isBusy.unlock();
@ -1795,7 +1845,7 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi
if (remainingLoops>0) { if (remainingLoops>0) {
remainingLoops--; remainingLoops--;
if (!remainingLoops) { if (!remainingLoops) {
logI("end of song!\n"); logI("end of song!");
remainingLoops=-1; remainingLoops=-1;
playing=false; playing=false;
freelance=false; freelance=false;
@ -1831,9 +1881,9 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi
return; return;
} }
//logD("attempts: %d\n",attempts); //logD("attempts: %d",attempts);
if (attempts>=100) { 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; freelance=false;
playing=false; playing=false;
extValuePresent=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++) { 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 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; 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()) { if (disCont[i].dispatch->isStereo()) {
for (size_t j=0; j<size; j++) { for (size_t j=0; j<size; j++) {
out[0][j]+=((float)disCont[i].bbOut[0][j]/32768.0)*volL; 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--; while (metroPos>=1) metroPos--;
} }
memcpy(oscBuf[0],out[0],size*sizeof(float)); for (unsigned int i=0; i<size; i++) {
memcpy(oscBuf[1],out[1],size*sizeof(float)); oscBuf[0][oscWritePos]=out[0][i];
oscBuf[1][oscWritePos]=out[1][i];
if (++oscWritePos>=32768) oscWritePos=0;
}
oscSize=size; oscSize=size;
if (forceMono) { if (forceMono) {

View file

@ -57,7 +57,7 @@ size_t SafeReader::size() {
int SafeReader::read(void* where, size_t count) { int SafeReader::read(void* where, size_t count) {
#ifdef READ_DEBUG #ifdef READ_DEBUG
logD("SR: reading %d bytes at %x\n",count,curSeek); logD("SR: reading %d bytes at %x",count,curSeek);
#endif #endif
if (count==0) return 0; if (count==0) return 0;
if (curSeek+count>len) throw EndOfFileException(this,len); if (curSeek+count>len) throw EndOfFileException(this,len);
@ -68,23 +68,23 @@ int SafeReader::read(void* where, size_t count) {
signed char SafeReader::readC() { signed char SafeReader::readC() {
#ifdef READ_DEBUG #ifdef READ_DEBUG
logD("SR: reading char %x:\n",curSeek); logD("SR: reading char %x:",curSeek);
#endif #endif
if (curSeek+1>len) throw EndOfFileException(this,len); if (curSeek+1>len) throw EndOfFileException(this,len);
#ifdef READ_DEBUG #ifdef READ_DEBUG
logD("SR: %.2x\n",buf[curSeek]); logD("SR: %.2x",buf[curSeek]);
#endif #endif
return (signed char)buf[curSeek++]; return (signed char)buf[curSeek++];
} }
short SafeReader::readS() { short SafeReader::readS() {
#ifdef READ_DEBUG #ifdef READ_DEBUG
logD("SR: reading short %x:\n",curSeek); logD("SR: reading short %x:",curSeek);
#endif #endif
if (curSeek+2>len) throw EndOfFileException(this,len); if (curSeek+2>len) throw EndOfFileException(this,len);
short ret=*(short*)(&buf[curSeek]); short ret=*(short*)(&buf[curSeek]);
#ifdef READ_DEBUG #ifdef READ_DEBUG
logD("SR: %.4x\n",ret); logD("SR: %.4x",ret);
#endif #endif
curSeek+=2; curSeek+=2;
return ret; return ret;
@ -99,13 +99,13 @@ short SafeReader::readS_BE() {
int SafeReader::readI() { int SafeReader::readI() {
#ifdef READ_DEBUG #ifdef READ_DEBUG
logD("SR: reading int %x:\n",curSeek); logD("SR: reading int %x:",curSeek);
#endif #endif
if (curSeek+4>len) throw EndOfFileException(this,len); if (curSeek+4>len) throw EndOfFileException(this,len);
int ret=*(int*)(&buf[curSeek]); int ret=*(int*)(&buf[curSeek]);
curSeek+=4; curSeek+=4;
#ifdef READ_DEBUG #ifdef READ_DEBUG
logD("SR: %.8x\n",ret); logD("SR: %.8x",ret);
#endif #endif
return ret; return ret;
} }
@ -141,7 +141,7 @@ double SafeReader::readD() {
String SafeReader::readString(size_t stlen) { String SafeReader::readString(size_t stlen) {
String ret; String ret;
#ifdef READ_DEBUG #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 #endif
size_t curPos=0; size_t curPos=0;
while (curPos<stlen) { while (curPos<stlen) {

View file

@ -24,6 +24,11 @@
#include <stdint.h> #include <stdint.h>
#include "../ta-utils.h" #include "../ta-utils.h"
enum Endianness {
LittleEndian=0,
BigEndian
};
class SafeReader; class SafeReader;
struct EndOfFileException { struct EndOfFileException {

View file

@ -50,7 +50,7 @@ bool DivSample::save(const char* path) {
f=sf_open(path,SFM_WRITE,&si); f=sf_open(path,SFM_WRITE,&si);
if (f==NULL) { 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; return false;
} }
@ -822,7 +822,7 @@ DivSampleHistory* DivSample::prepareUndo(bool data, bool doNotPush) {
initInternal(h->depth,h->samples); \ initInternal(h->depth,h->samples); \
samples=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(); \ void* buf=getCurBuf(); \
\ \

View file

@ -143,12 +143,15 @@ struct DivSong {
// - 9: v3.9 // - 9: v3.9
// - introduces Genesis system // - introduces Genesis system
// - introduces system number // - introduces system number
// - patterns now stored in current known format
// - 7: ??? // - 7: ???
// - 5: BETA 3 (?) // - 5: BETA 3
// - adds arpeggio tick // - adds arpeggio tick
// - 3: BETA 2 // - 4: BETA 2
// - 3: BETA 1
// - possibly the first version that could save // - possibly the first version that could save
// - basic format, no system number, 16 instruments, one speed, YMU759-only // - 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 // - 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; unsigned short version;
bool isDMF; bool isDMF;

View file

@ -415,7 +415,7 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
} }
if (write.addr>=0xffff0000) { // Furnace special command if (write.addr>=0xffff0000) { // Furnace special command
unsigned char streamID=streamOff+((write.addr&0xff00)>>8); 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) { switch (write.addr&0xff) {
case 0: // play sample case 0: // play sample
if (write.val<song.sampleLen) { if (write.val<song.sampleLen) {
@ -599,7 +599,7 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
} }
break; break;
default: default:
logW("write not handled!\n"); logW("write not handled!");
break; break;
} }
} }
@ -620,7 +620,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) {
int loopRow=0; int loopRow=0;
int loopEnd=0; int loopEnd=0;
walkSong(loopOrder,loopRow,loopEnd); walkSong(loopOrder,loopRow,loopEnd);
logI("loop point: %d %d\n",loopOrder,loopRow); logI("loop point: %d %d",loopOrder,loopRow);
warnings=""; warnings="";
curOrder=0; curOrder=0;
@ -1162,7 +1162,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) {
unsigned int sampleSeek=0; unsigned int sampleSeek=0;
for (int i=0; i<song.sampleLen; i++) { for (int i=0; i<song.sampleLen; i++) {
DivSample* sample=song.sample[i]; DivSample* sample=song.sample[i];
logI("setting seek to %d\n",sampleSeek); logI("setting seek to %d",sampleSeek);
sample->off8=sampleSeek; sample->off8=sampleSeek;
sampleSeek+=sample->length8; sampleSeek+=sample->length8;
} }
@ -1447,7 +1447,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) {
if (waitTime>0) { if (waitTime>0) {
w->writeC(0x61); w->writeC(0x61);
w->writeS(waitTime); w->writeS(waitTime);
printf("wait is: %f\n",waitTime); logV("wait is: %f",waitTime);
totalWait-=waitTime; totalWait-=waitTime;
tickCount+=waitTime; tickCount+=waitTime;
} }
@ -1561,7 +1561,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) {
freelance=false; freelance=false;
extValuePresent=false; extValuePresent=false;
logI("%d register writes total.\n",writeCount); logI("%d register writes total.",writeCount);
BUSY_END; BUSY_END;
return w; return w;

View file

@ -25,6 +25,54 @@ bool DivWaveSynth::tick() {
} }
updated=true; updated=true;
break; 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; divCounter=state.rateDivider;
} }
@ -96,4 +144,4 @@ void DivWaveSynth::init(DivInstrument* which, int w, int h, bool insChanged) {
changeWave1(state.wave1); changeWave1(state.wave1);
changeWave2(state.wave2); changeWave2(state.wave2);
} }
} }

View file

@ -75,8 +75,8 @@ class DivWaveSynth {
height(31), height(31),
first(false), first(false),
activeChangedB(false) { activeChangedB(false) {
memset(wave1,0,sizeof(int)*256); memset(wave1,0,256);
memset(wave2,0,sizeof(int)*256); memset(wave2,0,256);
memset(output,0,sizeof(int)*256); memset(output,0,sizeof(int)*256);
} }
}; };

View file

@ -73,12 +73,12 @@ bool DivWavetable::save(const char* path) {
FILE* outFile=ps_fopen(path,"wb"); FILE* outFile=ps_fopen(path,"wb");
if (outFile==NULL) { if (outFile==NULL) {
logE("could not save wavetable: %s!\n",strerror(errno)); logE("could not save wavetable: %s!",strerror(errno));
w->finish(); w->finish();
return false; return false;
} }
if (fwrite(w->getFinalBuf(),1,w->size(),outFile)!=w->size()) { 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); fclose(outFile);
w->finish(); w->finish();

View file

@ -33,15 +33,15 @@ String getWinConfigPath() {
configPath=path; configPath=path;
configPath+=L"\\furnace"; configPath+=L"\\furnace";
if (!PathIsDirectoryW(configPath.c_str())) { if (!PathIsDirectoryW(configPath.c_str())) {
logI("creating config dir...\n"); logI("creating config dir...");
int mkdirRet; int mkdirRet;
if ((mkdirRet=SHCreateDirectory(NULL,configPath.c_str()))!=ERROR_SUCCESS) { 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"."; configPath=L".";
} }
} }
} else { } else {
logW("unable to determine config directory! (%.8x)\n",configHR); logW("unable to determine config directory! (%.8x)",configHR);
configPath=L"."; configPath=L".";
} }
return utf16To8(configPath.c_str()); return utf16To8(configPath.c_str());

View file

@ -212,6 +212,9 @@ void FurnaceGUI::doAction(int what) {
case GUI_ACTION_WINDOW_REGISTER_VIEW: case GUI_ACTION_WINDOW_REGISTER_VIEW:
nextWindow=GUI_WINDOW_REGISTER_VIEW; nextWindow=GUI_WINDOW_REGISTER_VIEW;
break; break;
case GUI_ACTION_WINDOW_LOG:
nextWindow=GUI_WINDOW_LOG;
break;
case GUI_ACTION_COLLAPSE_WINDOW: case GUI_ACTION_COLLAPSE_WINDOW:
collapseWindow=true; collapseWindow=true;

View file

@ -546,8 +546,8 @@ void FurnaceGUI::doPaste(PasteMode mode) {
} }
if (invalidData) { if (invalidData) {
logW("invalid clipboard data! failed at line %d char %d\n",i,charPos); logW("invalid clipboard data! failed at line %d char %d",i,charPos);
logW("%s\n",line.c_str()); logW("%s",line.c_str());
break; break;
} }
j++; j++;
@ -562,6 +562,7 @@ void FurnaceGUI::doPaste(PasteMode mode) {
} }
if (settings.cursorPastePos) { if (settings.cursorPastePos) {
cursor.y=j; cursor.y=j;
updateScroll(cursor.y);
} }
makeUndo(GUI_UNDO_PATTERN_PASTE); makeUndo(GUI_UNDO_PATTERN_PASTE);

View file

@ -8,6 +8,7 @@ bool FurnaceGUIFileDialog::openLoad(String header, std::vector<String> filter, c
if (opened) return false; if (opened) return false;
saving=false; saving=false;
curPath=path; curPath=path;
logD("opening load file dialog with curPath %s",curPath.c_str());
if (sysDialog) { if (sysDialog) {
dialogO=new pfd::open_file(header,path,filter); dialogO=new pfd::open_file(header,path,filter);
} else { } else {
@ -22,6 +23,7 @@ bool FurnaceGUIFileDialog::openSave(String header, std::vector<String> filter, c
if (opened) return false; if (opened) return false;
saving=true; saving=true;
curPath=path; curPath=path;
logD("opening save file dialog with curPath %s",curPath.c_str());
if (sysDialog) { if (sysDialog) {
dialogS=new pfd::save_file(header,path,filter); dialogS=new pfd::save_file(header,path,filter);
} else { } else {
@ -65,7 +67,9 @@ bool FurnaceGUIFileDialog::render(const ImVec2& min, const ImVec2& max) {
if (dialogS!=NULL) { if (dialogS!=NULL) {
if (dialogS->ready(0)) { if (dialogS->ready(0)) {
fileName=dialogS->result(); 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; return true;
} }
} }
@ -74,10 +78,12 @@ bool FurnaceGUIFileDialog::render(const ImVec2& min, const ImVec2& max) {
if (dialogO->ready(0)) { if (dialogO->ready(0)) {
if (dialogO->result().empty()) { if (dialogO->result().empty()) {
fileName=""; fileName="";
logD("returning nothing\n"); logD("returning nothing");
} else { } else {
fileName=dialogO->result()[0]; 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; return true;
} }
@ -91,6 +97,12 @@ bool FurnaceGUIFileDialog::render(const ImVec2& min, const ImVec2& max) {
String FurnaceGUIFileDialog::getPath() { String FurnaceGUIFileDialog::getPath() {
if (sysDialog) { 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; return curPath;
} else { } else {
return ImGuiFileDialog::Instance()->GetCurrentPath(); return ImGuiFileDialog::Instance()->GetCurrentPath();

View file

@ -815,10 +815,10 @@ void FurnaceGUI::prepareLayout() {
} }
// copy initial layout // copy initial layout
logI("loading default layout.\n"); logI("loading default layout.");
check=ps_fopen(finalLayoutPath,"w"); check=ps_fopen(finalLayoutPath,"w");
if (check==NULL) { if (check==NULL) {
logW("could not write default layout!\n"); logW("could not write default layout!");
return; return;
} }
@ -1131,7 +1131,7 @@ void FurnaceGUI::keyDown(SDL_Event& ev) {
if (orderCursor>=0 && orderCursor<e->getTotalChannelCount()) { if (orderCursor>=0 && orderCursor<e->getTotalChannelCount()) {
int curOrder=e->getOrder(); int curOrder=e->getOrder();
e->lockSave([this,curOrder,num]() { 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) { if (orderEditMode==2 || orderEditMode==3) {
curNibble=!curNibble; curNibble=!curNibble;
@ -1539,7 +1539,7 @@ int FurnaceGUI::save(String path, int dmfVersion) {
memset(&zl,0,sizeof(z_stream)); memset(&zl,0,sizeof(z_stream));
ret=deflateInit(&zl,Z_DEFAULT_COMPRESSION); ret=deflateInit(&zl,Z_DEFAULT_COMPRESSION);
if (ret!=Z_OK) { if (ret!=Z_OK) {
logE("zlib error!\n"); logE("zlib error!");
lastError="compression error"; lastError="compression error";
fclose(outFile); fclose(outFile);
w->finish(); w->finish();
@ -1551,7 +1551,7 @@ int FurnaceGUI::save(String path, int dmfVersion) {
zl.avail_out=131072; zl.avail_out=131072;
zl.next_out=zbuf; zl.next_out=zbuf;
if ((ret=deflate(&zl,Z_NO_FLUSH))==Z_STREAM_ERROR) { if ((ret=deflate(&zl,Z_NO_FLUSH))==Z_STREAM_ERROR) {
logE("zlib stream error!\n"); logE("zlib stream error!");
lastError="zlib stream error"; lastError="zlib stream error";
deflateEnd(&zl); deflateEnd(&zl);
fclose(outFile); fclose(outFile);
@ -1561,7 +1561,7 @@ int FurnaceGUI::save(String path, int dmfVersion) {
size_t amount=131072-zl.avail_out; size_t amount=131072-zl.avail_out;
if (amount>0) { if (amount>0) {
if (fwrite(zbuf,1,amount,outFile)!=amount) { 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); lastError=strerror(errno);
deflateEnd(&zl); deflateEnd(&zl);
fclose(outFile); fclose(outFile);
@ -1573,7 +1573,7 @@ int FurnaceGUI::save(String path, int dmfVersion) {
zl.avail_out=131072; zl.avail_out=131072;
zl.next_out=zbuf; zl.next_out=zbuf;
if ((ret=deflate(&zl,Z_FINISH))==Z_STREAM_ERROR) { 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"; lastError="zlib finish stream error";
deflateEnd(&zl); deflateEnd(&zl);
fclose(outFile); fclose(outFile);
@ -1582,7 +1582,7 @@ int FurnaceGUI::save(String path, int dmfVersion) {
} }
if (131072-zl.avail_out>0) { if (131072-zl.avail_out>0) {
if (fwrite(zbuf,1,131072-zl.avail_out,outFile)!=(131072-zl.avail_out)) { 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); lastError=strerror(errno);
deflateEnd(&zl); deflateEnd(&zl);
fclose(outFile); fclose(outFile);
@ -1593,7 +1593,7 @@ int FurnaceGUI::save(String path, int dmfVersion) {
deflateEnd(&zl); deflateEnd(&zl);
#else #else
if (fwrite(w->getFinalBuf(),1,w->size(),outFile)!=w->size()) { 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); lastError=strerror(errno);
fclose(outFile); fclose(outFile);
w->finish(); w->finish();
@ -1613,7 +1613,7 @@ int FurnaceGUI::save(String path, int dmfVersion) {
int FurnaceGUI::load(String path) { int FurnaceGUI::load(String path) {
if (!path.empty()) { if (!path.empty()) {
logI("loading module...\n"); logI("loading module...");
FILE* f=ps_fopen(path.c_str(),"rb"); FILE* f=ps_fopen(path.c_str(),"rb");
if (f==NULL) { if (f==NULL) {
perror("error"); perror("error");
@ -1635,7 +1635,7 @@ int FurnaceGUI::load(String path) {
} }
if (len<1) { if (len<1) {
if (len==0) { if (len==0) {
logE("that file is empty!\n"); logE("that file is empty!");
lastError="file is empty"; lastError="file is empty";
} else { } else {
perror("tell error"); perror("tell error");
@ -1662,7 +1662,7 @@ int FurnaceGUI::load(String path) {
fclose(f); fclose(f);
if (!e->load(file,(size_t)len)) { if (!e->load(file,(size_t)len)) {
lastError=e->getLastError(); lastError=e->getLastError();
logE("could not open file!\n"); logE("could not open file!");
return 1; return 1;
} }
} }
@ -2076,7 +2076,7 @@ bool FurnaceGUI::loop() {
macroLoopDragActive=false; macroLoopDragActive=false;
waveDragActive=false; waveDragActive=false;
if (sampleDragActive) { if (sampleDragActive) {
logD("stopping sample drag\n"); logD("stopping sample drag");
if (sampleDragMode) { if (sampleDragMode) {
e->renderSamplesP(); e->renderSamplesP();
} else { } else {
@ -2506,6 +2506,7 @@ bool FurnaceGUI::loop() {
if (ImGui::MenuItem("oscilloscope",BIND_FOR(GUI_ACTION_WINDOW_OSCILLOSCOPE),oscOpen)) oscOpen=!oscOpen; 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("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("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; if (ImGui::MenuItem("statistics",BIND_FOR(GUI_ACTION_WINDOW_STATS),statsOpen)) statsOpen=!statsOpen;
ImGui::EndMenu(); ImGui::EndMenu();
@ -2600,6 +2601,9 @@ bool FurnaceGUI::loop() {
drawInsList(); drawInsList();
drawInsEdit(); drawInsEdit();
drawMixer(); drawMixer();
readOsc();
drawOsc(); drawOsc();
drawVolMeter(); drawVolMeter();
drawSettings(); drawSettings();
@ -2610,6 +2614,7 @@ bool FurnaceGUI::loop() {
drawNotes(); drawNotes();
drawChannels(); drawChannels();
drawRegView(); drawRegView();
drawLog();
if (inspectorOpen) ImGui::ShowMetricsWindow(&inspectorOpen); if (inspectorOpen) ImGui::ShowMetricsWindow(&inspectorOpen);
@ -2710,7 +2715,7 @@ bool FurnaceGUI::loop() {
} }
break; break;
case GUI_FILE_SAVE: { case GUI_FILE_SAVE: {
logD("saving: %s\n",copyOfName.c_str()); logD("saving: %s",copyOfName.c_str());
String lowerCase=fileName; String lowerCase=fileName;
for (char& i: lowerCase) { for (char& i: lowerCase) {
if (i>='A' && i<='Z') i+='a'-'A'; if (i>='A' && i<='Z') i+='a'-'A';
@ -2727,7 +2732,7 @@ bool FurnaceGUI::loop() {
break; break;
} }
case GUI_FILE_SAVE_DMF_LEGACY: case GUI_FILE_SAVE_DMF_LEGACY:
logD("saving: %s\n",copyOfName.c_str()); logD("saving: %s",copyOfName.c_str());
if (save(copyOfName,24)>0) { if (save(copyOfName,24)>0) {
showError(fmt::sprintf("Error while saving file! (%s)",lastError)); showError(fmt::sprintf("Error while saving file! (%s)",lastError));
} }
@ -2862,7 +2867,7 @@ bool FurnaceGUI::loop() {
if (aboutOpen) drawAbout(); if (aboutOpen) drawAbout();
if (ImGui::BeginPopupModal("Rendering...",NULL,ImGuiWindowFlags_AlwaysAutoResize)) { if (ImGui::BeginPopupModal("Rendering...",NULL,ImGuiWindowFlags_AlwaysAutoResize)) {
ImGui::Text("Please wait...\n"); ImGui::Text("Please wait...");
if (ImGui::Button("Abort")) { if (ImGui::Button("Abort")) {
if (e->haltAudioFile()) { if (e->haltAudioFile()) {
ImGui::CloseCurrentPopup(); ImGui::CloseCurrentPopup();
@ -2923,6 +2928,7 @@ bool FurnaceGUI::loop() {
break; break;
case GUI_WARN_RESET_COLORS: case GUI_WARN_RESET_COLORS:
resetColors(); resetColors();
applyUISettings(false);
break; break;
case GUI_WARN_GENERIC: case GUI_WARN_GENERIC:
break; break;
@ -2944,22 +2950,22 @@ bool FurnaceGUI::loop() {
if (backupTimer<=0) { if (backupTimer<=0) {
backupTask=std::async(std::launch::async,[this]() -> bool { backupTask=std::async(std::launch::async,[this]() -> bool {
if (backupPath==curFileName) { if (backupPath==curFileName) {
logD("backup file open. not saving backup.\n"); logD("backup file open. not saving backup.");
return true; return true;
} }
logD("saving backup...\n"); logD("saving backup...");
SafeWriter* w=e->saveFur(true); SafeWriter* w=e->saveFur(true);
if (w!=NULL) { if (w!=NULL) {
FILE* outFile=ps_fopen(backupPath.c_str(),"wb"); FILE* outFile=ps_fopen(backupPath.c_str(),"wb");
if (outFile!=NULL) { if (outFile!=NULL) {
if (fwrite(w->getFinalBuf(),1,w->size(),outFile)!=w->size()) { 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(); w->finish();
} }
fclose(outFile); fclose(outFile);
} else { } else {
logW("could not save backup: %s!\n",strerror(errno)); logW("could not save backup: %s!",strerror(errno));
w->finish(); w->finish();
} }
} }
@ -3034,6 +3040,7 @@ bool FurnaceGUI::init() {
notesOpen=e->getConfBool("notesOpen",false); notesOpen=e->getConfBool("notesOpen",false);
channelsOpen=e->getConfBool("channelsOpen",false); channelsOpen=e->getConfBool("channelsOpen",false);
regViewOpen=e->getConfBool("regViewOpen",false); regViewOpen=e->getConfBool("regViewOpen",false);
logOpen=e->getConfBool("logOpen",false);
tempoView=e->getConfBool("tempoView",true); tempoView=e->getConfBool("tempoView",true);
waveHex=e->getConfBool("waveHex",false); 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); sdlWin=SDL_CreateWindow("Furnace",SDL_WINDOWPOS_CENTERED,SDL_WINDOWPOS_CENTERED,scrW*dpiScale,scrH*dpiScale,SDL_WINDOW_RESIZABLE|SDL_WINDOW_ALLOW_HIGHDPI);
if (sdlWin==NULL) { if (sdlWin==NULL) {
logE("could not open window! %s\n",SDL_GetError()); logE("could not open window! %s",SDL_GetError());
return false; return false;
} }
@ -3088,14 +3095,14 @@ bool FurnaceGUI::init() {
SDL_FreeSurface(icon); SDL_FreeSurface(icon);
free(furIcon); free(furIcon);
} else { } else {
logW("could not create icon!\n"); logW("could not create icon!");
} }
#endif #endif
sdlRend=SDL_CreateRenderer(sdlWin,-1,SDL_RENDERER_ACCELERATED|SDL_RENDERER_PRESENTVSYNC|SDL_RENDERER_TARGETTEXTURE); sdlRend=SDL_CreateRenderer(sdlWin,-1,SDL_RENDERER_ACCELERATED|SDL_RENDERER_PRESENTVSYNC|SDL_RENDERER_TARGETTEXTURE);
if (sdlRend==NULL) { if (sdlRend==NULL) {
logE("could not init renderer! %s\n",SDL_GetError()); logE("could not init renderer! %s",SDL_GetError());
return false; return false;
} }
@ -3112,14 +3119,14 @@ bool FurnaceGUI::init() {
applyUISettings(); applyUISettings();
if (!ImGui::GetIO().Fonts->Build()) { 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."); showError("error while loading fonts! please check your settings.");
ImGui::GetIO().Fonts->Clear(); ImGui::GetIO().Fonts->Clear();
mainFont=ImGui::GetIO().Fonts->AddFontDefault(); mainFont=ImGui::GetIO().Fonts->AddFontDefault();
patFont=mainFont; patFont=mainFont;
ImGui_ImplSDLRenderer_DestroyFontsTexture(); ImGui_ImplSDLRenderer_DestroyFontsTexture();
if (!ImGui::GetIO().Fonts->Build()) { 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("notesOpen",notesOpen);
e->setConf("channelsOpen",channelsOpen); e->setConf("channelsOpen",channelsOpen);
e->setConf("regViewOpen",regViewOpen); e->setConf("regViewOpen",regViewOpen);
e->setConf("logOpen",logOpen);
// commit last window size // commit last window size
e->setConf("lastWindowWidth",scrW); e->setConf("lastWindowWidth",scrW);
@ -3295,6 +3303,7 @@ FurnaceGUI::FurnaceGUI():
notesOpen(false), notesOpen(false),
channelsOpen(false), channelsOpen(false),
regViewOpen(false), regViewOpen(false),
logOpen(false),
/* /*
editControlsDocked(false), editControlsDocked(false),
ordersDocked(false), ordersDocked(false),
@ -3428,7 +3437,11 @@ FurnaceGUI::FurnaceGUI():
openSampleResampleOpt(false), openSampleResampleOpt(false),
openSampleAmplifyOpt(false), openSampleAmplifyOpt(false),
openSampleSilenceOpt(false), openSampleSilenceOpt(false),
openSampleFilterOpt(false) { openSampleFilterOpt(false),
oscTotal(0),
oscZoom(0.5f),
oscZoomSlider(false),
followLog(true) {
// value keys // value keys
valueKeys[SDLK_0]=0; valueKeys[SDLK_0]=0;
valueKeys[SDLK_1]=1; valueKeys[SDLK_1]=1;
@ -3469,4 +3482,5 @@ FurnaceGUI::FurnaceGUI():
memset(patChanX,0,sizeof(float)*(DIV_MAX_CHANS+1)); memset(patChanX,0,sizeof(float)*(DIV_MAX_CHANS+1));
memset(patChanSlideY,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(lastIns,-1,sizeof(int)*DIV_MAX_CHANS);
memset(oscValues,0,sizeof(float)*512);
} }

View file

@ -71,6 +71,16 @@ enum FurnaceGUIColors {
GUI_COLOR_FILE_FONT, GUI_COLOR_FILE_FONT,
GUI_COLOR_FILE_OTHER, 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_LOW,
GUI_COLOR_VOLMETER_HIGH, GUI_COLOR_VOLMETER_HIGH,
GUI_COLOR_VOLMETER_PEAK, GUI_COLOR_VOLMETER_PEAK,
@ -157,6 +167,12 @@ enum FurnaceGUIColors {
GUI_COLOR_PATTERN_EFFECT_SYS_SECONDARY, GUI_COLOR_PATTERN_EFFECT_SYS_SECONDARY,
GUI_COLOR_PATTERN_EFFECT_MISC, 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_EE_VALUE,
GUI_COLOR_PLAYBACK_STAT, GUI_COLOR_PLAYBACK_STAT,
GUI_COLOR_MAX GUI_COLOR_MAX
@ -185,7 +201,8 @@ enum FurnaceGUIWindows {
GUI_WINDOW_PIANO, GUI_WINDOW_PIANO,
GUI_WINDOW_NOTES, GUI_WINDOW_NOTES,
GUI_WINDOW_CHANNELS, GUI_WINDOW_CHANNELS,
GUI_WINDOW_REGISTER_VIEW GUI_WINDOW_REGISTER_VIEW,
GUI_WINDOW_LOG
}; };
enum FurnaceGUIFileDialogs { enum FurnaceGUIFileDialogs {
@ -280,6 +297,7 @@ enum FurnaceGUIActions {
GUI_ACTION_WINDOW_NOTES, GUI_ACTION_WINDOW_NOTES,
GUI_ACTION_WINDOW_CHANNELS, GUI_ACTION_WINDOW_CHANNELS,
GUI_ACTION_WINDOW_REGISTER_VIEW, GUI_ACTION_WINDOW_REGISTER_VIEW,
GUI_ACTION_WINDOW_LOG,
GUI_ACTION_COLLAPSE_WINDOW, GUI_ACTION_COLLAPSE_WINDOW,
GUI_ACTION_CLOSE_WINDOW, GUI_ACTION_CLOSE_WINDOW,
@ -761,6 +779,9 @@ class FurnaceGUI {
int titleBarSys; int titleBarSys;
int frameBorders; int frameBorders;
int effectDeletionAltersValue; int effectDeletionAltersValue;
int oscRoundedCorners;
int oscTakesEntireWindow;
int oscBorder;
unsigned int maxUndoSteps; unsigned int maxUndoSteps;
String mainFontPath; String mainFontPath;
String patFontPath; String patFontPath;
@ -821,6 +842,9 @@ class FurnaceGUI {
titleBarSys(1), titleBarSys(1),
frameBorders(0), frameBorders(0),
effectDeletionAltersValue(1), effectDeletionAltersValue(1),
oscRoundedCorners(1),
oscTakesEntireWindow(0),
oscBorder(1),
maxUndoSteps(100), maxUndoSteps(100),
mainFontPath(""), mainFontPath(""),
patFontPath(""), patFontPath(""),
@ -838,7 +862,7 @@ class FurnaceGUI {
bool editControlsOpen, ordersOpen, insListOpen, songInfoOpen, patternOpen, insEditOpen; bool editControlsOpen, ordersOpen, insListOpen, songInfoOpen, patternOpen, insEditOpen;
bool waveListOpen, waveEditOpen, sampleListOpen, sampleEditOpen, aboutOpen, settingsOpen; bool waveListOpen, waveEditOpen, sampleListOpen, sampleEditOpen, aboutOpen, settingsOpen;
bool mixerOpen, debugOpen, inspectorOpen, oscOpen, volMeterOpen, statsOpen, compatFlagsOpen; 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... /* there ought to be a better way...
bool editControlsDocked, ordersDocked, insListDocked, songInfoDocked, patternDocked, insEditDocked; bool editControlsDocked, ordersDocked, insListDocked, songInfoDocked, patternDocked, insEditDocked;
@ -952,7 +976,7 @@ class FurnaceGUI {
int oldOrdersLen; int oldOrdersLen;
DivOrders oldOrders; DivOrders oldOrders;
DivPattern* oldPat[128]; DivPattern* oldPat[DIV_MAX_CHANS];
std::deque<UndoStep> undoHist; std::deque<UndoStep> undoHist;
std::deque<UndoStep> redoHist; std::deque<UndoStep> redoHist;
@ -976,9 +1000,18 @@ class FurnaceGUI {
size_t sampleClipboardLen; size_t sampleClipboardLen;
bool openSampleResizeOpt, openSampleResampleOpt, openSampleAmplifyOpt, openSampleSilenceOpt, openSampleFilterOpt; bool openSampleResizeOpt, openSampleResampleOpt, openSampleAmplifyOpt, openSampleSilenceOpt, openSampleFilterOpt;
// oscilloscope
int oscTotal;
float oscValues[512];
float oscZoom;
bool oscZoomSlider;
// visualizer // visualizer
float keyHit[DIV_MAX_CHANS]; float keyHit[DIV_MAX_CHANS];
int lastIns[DIV_MAX_CHANS]; int lastIns[DIV_MAX_CHANS];
// log window
bool followLog;
void drawSSGEnv(unsigned char type, const ImVec2& size); void drawSSGEnv(unsigned char type, const ImVec2& size);
void drawWaveform(unsigned char type, bool opz, const ImVec2& size); void drawWaveform(unsigned char type, bool opz, const ImVec2& size);
@ -996,6 +1029,8 @@ class FurnaceGUI {
void updateWindowTitle(); void updateWindowTitle();
void prepareLayout(); void prepareLayout();
void readOsc();
float calcBPM(int s1, int s2, float hz); float calcBPM(int s1, int s2, float hz);
void patternRow(int i, bool isPlaying, float lineHeight, int chans, int ord, const DivPattern** patCache); void patternRow(int i, bool isPlaying, float lineHeight, int chans, int ord, const DivPattern** patCache);
@ -1026,6 +1061,7 @@ class FurnaceGUI {
void drawSettings(); void drawSettings();
void drawDebug(); void drawDebug();
void drawNewSong(); void drawNewSong();
void drawLog();
void parseKeybinds(); void parseKeybinds();
void promptKey(int which); void promptKey(int which);
@ -1096,7 +1132,7 @@ class FurnaceGUI {
int load(String path); int load(String path);
void exportAudio(String path, DivAudioExportModes mode); void exportAudio(String path, DivAudioExportModes mode);
void applyUISettings(); void applyUISettings(bool updateFonts=true);
void initSystemPresets(); void initSystemPresets();
void encodeMMLStr(String& target, int* macro, int macroLen, int macroLoop, int macroRel, bool hex=false); void encodeMMLStr(String& target, int* macro, int macroLen, int macroLoop, int macroRel, bool hex=false);

View file

@ -191,6 +191,7 @@ const FurnaceGUIActionDef guiActions[GUI_ACTION_MAX]={
D("WINDOW_NOTES", "Song Comments", 0), D("WINDOW_NOTES", "Song Comments", 0),
D("WINDOW_CHANNELS", "Channels", 0), D("WINDOW_CHANNELS", "Channels", 0),
D("WINDOW_REGISTER_VIEW", "Register View", 0), D("WINDOW_REGISTER_VIEW", "Register View", 0),
D("WINDOW_LOG", "Log Viewer", 0),
D("COLLAPSE_WINDOW", "Collapse/expand current window", 0), D("COLLAPSE_WINDOW", "Collapse/expand current window", 0),
D("CLOSE_WINDOW", "Close current window", FURKMOD_SHIFT|SDLK_ESCAPE), 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_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_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_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_HIGH,"",ImVec4(1.0f,0.9f,0.2f,1.0f)),
D(GUI_COLOR_VOLMETER_PEAK,"",ImVec4(1.0f,0.1f,0.1f,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_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_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_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)), D(GUI_COLOR_PLAYBACK_STAT,"",ImVec4(0.6f,0.6f,0.6f,1.0f)),
}; };

View file

@ -32,7 +32,7 @@ const char* ssgEnvTypes[8]={
}; };
const char* fmParamNames[3][32]={ 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", "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"} {"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_NAME(x) fmParamNames[settings.fmNames][x]
#define FM_SHORT_NAME(x) fmParamShortNames[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]={ const char* c64ShapeBits[5]={
"triangle", "saw", "pulse", "noise", NULL "triangle", "saw", "pulse", "noise", NULL
}; };
@ -176,6 +180,16 @@ const char* dualWSEffects[7]={
"Phase (dual)", "Phase (dual)",
}; };
const char* macroAbsoluteMode[2]={
"Relative",
"Absolute"
};
const char* macroDummyMode[2]={
"Bug",
"Bug"
};
String macroHoverNote(int id, float val) { String macroHoverNote(int id, float val) {
if (val<-60 || val>=120) return "???"; if (val<-60 || val>=120) return "???";
return fmt::sprintf("%d: %s",id,noteNames[(int)val+60]); 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 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 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 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 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))))); //Heght of the peak of SR, 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; //dl->Flags=ImDrawListFlags_AntiAliasedLines|ImDrawListFlags_AntiAliasedLinesUseTex;
if (ar==0.0) { //if AR = 0, the envelope never starts 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 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::TableNextRow(); \
ImGui::TableNextColumn(); \ ImGui::TableNextColumn(); \
ImGui::Text("%s",displayName); \ ImGui::Text("%s",displayName); \
@ -973,26 +987,41 @@ void FurnaceGUI::drawFMEnv(unsigned char tl, unsigned char ar, unsigned char dr,
} \ } \
if (displayLoop) { \ if (displayLoop) { \
ImGui::SetNextItemWidth(lenAvail); \ ImGui::SetNextItemWidth(lenAvail); \
if (ImGui::InputScalar("##IMacroLen_" macroName,ImGuiDataType_U8,&macroLen,&_ONE,&_THREE)) { MARK_MODIFIED \ if (ImGui::InputScalar("##IMacroLen_" macroName,ImGuiDataType_U8,&macro.len,&_ONE,&_THREE)) { MARK_MODIFIED \
if (macroLen>127) macroLen=127; \ if (macro.len>127) macro.len=127; \
} \ } \
if (macroMode!=NULL) { \ if (macroMode) { \
ImGui::Checkbox("Fixed##IMacroMode_" macroName,macroMode); \ String modeName; \
if (macro.mode>macroModeMax) { \
modeName="none selected"; \
} else { \
modeName=displayModeName[macro.mode]; \
} \
if (ImGui::BeginCombo("TODO: Improve##IMacroMode_" macroName,modeName.c_str())) { \
String id; \
for (unsigned int i=0; i<=macroModeMax; i++) { \
id=fmt::sprintf("%d: %s",i,displayModeName[i]); \
if (ImGui::Selectable(id.c_str(),macro.mode==i)) { PARAMETER \
macro.mode=i; \
} \
} \
ImGui::EndCombo(); \
} \
} \ } \
} \ } \
ImGui::TableNextColumn(); \ ImGui::TableNextColumn(); \
for (int j=0; j<256; j++) { \ for (int j=0; j<256; j++) { \
if (j+macroDragScroll>=macroLen) { \ if (j+macroDragScroll>=macro.len) { \
asFloat[j]=0; \ asFloat[j]=0; \
asInt[j]=0; \ asInt[j]=0; \
} else { \ } else { \
asFloat[j]=macro[j+macroDragScroll]+macroDispMin; \ asFloat[j]=macro.val[j+macroDragScroll]+macroDispMin; \
asInt[j]=macro[j+macroDragScroll]+macroDispMin+bitOff; \ 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; \ loopIndicator[j]=0; \
} else { \ } 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)); \ 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) { \ if (bitfield) { \
PlotBitfield("##IMacro_" macroName,asInt,totalFit,0,bfVal,macroHeight,ImVec2(availableWidth,(displayLoop)?(displayHeight*dpiScale):(32.0f*dpiScale))); \ PlotBitfield("##IMacro_" macroName,asInt,totalFit,0,bfVal,macroHeight,ImVec2(availableWidth,(displayLoop)?(displayHeight*dpiScale):(32.0f*dpiScale))); \
} else { \ } 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)) { \ if (displayLoop && ImGui::IsItemClicked(ImGuiMouseButton_Left)) { \
macroDragStart=ImGui::GetItemRectMin(); \ macroDragStart=ImGui::GetItemRectMin(); \
@ -1013,7 +1042,7 @@ void FurnaceGUI::drawFMEnv(unsigned char tl, unsigned char ar, unsigned char dr,
macroDragInitialValue=false; \ macroDragInitialValue=false; \
macroDragLen=totalFit; \ macroDragLen=totalFit; \
macroDragActive=true; \ macroDragActive=true; \
macroDragTarget=macro; \ macroDragTarget=macro.val; \
macroDragChar=false; \ macroDragChar=false; \
processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y); \ 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(); \ ImGui::SameLine(); \
CWVSliderInt("##IArpMacroPos",ImVec2(20.0f*dpiScale,displayHeight*dpiScale),sliderVal,sliderLow,70); \ 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,&macroHoverLoop); \ PlotCustom("##IMacroLoop_" macroName,loopIndicator,totalFit,macroDragScroll,NULL,0,2,ImVec2(availableWidth,12.0f*dpiScale),sizeof(float),macroColor,macro.len-macroDragScroll,&macroHoverLoop); \
if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) { \ if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) { \
macroLoopDragStart=ImGui::GetItemRectMin(); \ macroLoopDragStart=ImGui::GetItemRectMin(); \
macroLoopDragAreaSize=ImVec2(availableWidth,12.0f*dpiScale); \ macroLoopDragAreaSize=ImVec2(availableWidth,12.0f*dpiScale); \
macroLoopDragLen=totalFit; \ macroLoopDragLen=totalFit; \
if (ImGui::IsKeyDown(ImGuiKey_LeftShift) || ImGui::IsKeyDown(ImGuiKey_RightShift)) { \ if (ImGui::IsKeyDown(ImGuiKey_LeftShift) || ImGui::IsKeyDown(ImGuiKey_RightShift)) { \
macroLoopDragTarget=&macroRel; \ macroLoopDragTarget=&macro.rel; \
} else { \ } else { \
macroLoopDragTarget=&macroLoop; \ macroLoopDragTarget=&macro.loop; \
} \ } \
macroLoopDragActive=true; \ macroLoopDragActive=true; \
processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y); \ processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y); \
} \ } \
if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) { \ if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) { \
if (ImGui::IsKeyDown(ImGuiKey_LeftShift) || ImGui::IsKeyDown(ImGuiKey_RightShift)) { \ if (ImGui::IsKeyDown(ImGuiKey_LeftShift) || ImGui::IsKeyDown(ImGuiKey_RightShift)) { \
macroRel=-1; \ macro.rel=-1; \
} else { \ } else { \
macroLoop=-1; \ macro.loop=-1; \
} \ } \
} \ } \
ImGui::SetNextItemWidth(availableWidth); \ ImGui::SetNextItemWidth(availableWidth); \
if (ImGui::InputText("##IMacroMML_" macroName,&mmlStr)) { \ 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()) { \ if (!ImGui::IsItemActive()) { \
encodeMMLStr(mmlStr,macro,macroLen,macroLoop,macroRel); \ encodeMMLStr(mmlStr,macro.val,macro.len,macro.loop,macro.rel); \
} \ } \
} \ } \
ImGui::PopStyleVar(); 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::TableNextRow(); \
ImGui::TableNextColumn(); \ ImGui::TableNextColumn(); \
ImGui::Text("%s",displayName); \ ImGui::Text("%s",displayName); \
@ -1062,23 +1091,41 @@ void FurnaceGUI::drawFMEnv(unsigned char tl, unsigned char ar, unsigned char dr,
} \ } \
if (displayLoop) { \ if (displayLoop) { \
ImGui::SetNextItemWidth(lenAvail); \ ImGui::SetNextItemWidth(lenAvail); \
if (ImGui::InputScalar("##IOPMacroLen_" #op macroName,ImGuiDataType_U8,&macroLen,&_ONE,&_THREE)) { MARK_MODIFIED \ if (ImGui::InputScalar("##IOPMacroLen_" #op macroName,ImGuiDataType_U8,&macro.len,&_ONE,&_THREE)) { MARK_MODIFIED \
if (macroLen>127) macroLen=127; \ 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(); \ ImGui::TableNextColumn(); \
for (int j=0; j<256; j++) { \ for (int j=0; j<256; j++) { \
if (j+macroDragScroll>=macroLen) { \ if (j+macroDragScroll>=macro.len) { \
asFloat[j]=0; \ asFloat[j]=0; \
asInt[j]=0; \ asInt[j]=0; \
} else { \ } else { \
asFloat[j]=macro[j+macroDragScroll]; \ asFloat[j]=macro.val[j+macroDragScroll]; \
asInt[j]=macro[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; \ loopIndicator[j]=0; \
} else { \ } 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)); \ 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) { \ if (bitfield) { \
PlotBitfield("##IOPMacro_" #op macroName,asInt,totalFit,0,bfVal,macroHeight,ImVec2(availableWidth,displayLoop?(displayHeight*dpiScale):(24*dpiScale))); \ PlotBitfield("##IOPMacro_" #op macroName,asInt,totalFit,0,bfVal,macroHeight,ImVec2(availableWidth,displayLoop?(displayHeight*dpiScale):(24*dpiScale))); \
} else { \ } 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)) { \ if (displayLoop && ImGui::IsItemClicked(ImGuiMouseButton_Left)) { \
macroDragStart=ImGui::GetItemRectMin(); \ macroDragStart=ImGui::GetItemRectMin(); \
@ -1099,37 +1146,37 @@ void FurnaceGUI::drawFMEnv(unsigned char tl, unsigned char ar, unsigned char dr,
macroDragInitialValue=false; \ macroDragInitialValue=false; \
macroDragLen=totalFit; \ macroDragLen=totalFit; \
macroDragActive=true; \ macroDragActive=true; \
macroDragCTarget=macro; \ macroDragTarget=macro.val; \
macroDragChar=true; \ macroDragChar=false; \
processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y); \ processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y); \
} \ } \
if (displayLoop) { \ 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,&macroHoverLoop); \ 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,&macroHoverLoop); \
if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) { \ if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) { \
macroLoopDragStart=ImGui::GetItemRectMin(); \ macroLoopDragStart=ImGui::GetItemRectMin(); \
macroLoopDragAreaSize=ImVec2(availableWidth,8.0f*dpiScale); \ macroLoopDragAreaSize=ImVec2(availableWidth,8.0f*dpiScale); \
macroLoopDragLen=totalFit; \ macroLoopDragLen=totalFit; \
if (ImGui::IsKeyDown(ImGuiKey_LeftShift) || ImGui::IsKeyDown(ImGuiKey_RightShift)) { \ if (ImGui::IsKeyDown(ImGuiKey_LeftShift) || ImGui::IsKeyDown(ImGuiKey_RightShift)) { \
macroLoopDragTarget=&macroRel; \ macroLoopDragTarget=&macro.rel; \
} else { \ } else { \
macroLoopDragTarget=&macroLoop; \ macroLoopDragTarget=&macro.loop; \
} \ } \
macroLoopDragActive=true; \ macroLoopDragActive=true; \
processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y); \ processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y); \
} \ } \
if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) { \ if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) { \
if (ImGui::IsKeyDown(ImGuiKey_LeftShift) || ImGui::IsKeyDown(ImGuiKey_RightShift)) { \ if (ImGui::IsKeyDown(ImGuiKey_LeftShift) || ImGui::IsKeyDown(ImGuiKey_RightShift)) { \
macroRel=-1; \ macro.rel=-1; \
} else { \ } else { \
macroLoop=-1; \ macro.loop=-1; \
} \ } \
} \ } \
ImGui::SetNextItemWidth(availableWidth); \ ImGui::SetNextItemWidth(availableWidth); \
if (ImGui::InputText("##IOPMacroMML_" macroName,&mmlStr)) { \ 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()) { \ if (!ImGui::IsItemActive()) { \
encodeMMLStr(mmlStr,macro,macroLen,macroLoop,macroRel); \ encodeMMLStr(mmlStr,macro.val,macro.len,macro.loop,macro.rel); \
} \ } \
} \ } \
ImGui::PopStyleVar(); ImGui::PopStyleVar();
@ -1262,7 +1309,7 @@ void FurnaceGUI::drawInsEdit() {
ImGui::Text("Type"); ImGui::Text("Type");
ImGui::TableNextColumn(); 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; int insType=ins->type;
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
if (ImGui::Combo("##Type",&insType,insTypes,DIV_INS_MAX,DIV_INS_MAX)) { if (ImGui::Combo("##Type",&insType,insTypes,DIV_INS_MAX,DIV_INS_MAX)) {
@ -1804,8 +1851,6 @@ void FurnaceGUI::drawInsEdit() {
op.am=amOn; op.am=amOn;
} }
ImGui::SameLine();
int maxTl=127; int maxTl=127;
if (ins->type==DIV_INS_OPLL) { if (ins->type==DIV_INS_OPLL) {
if (i==1) { if (i==1) {
@ -1825,6 +1870,7 @@ void FurnaceGUI::drawInsEdit() {
bool susOn=op.sus; // don't you make fun of this one bool susOn=op.sus; // don't you make fun of this one
unsigned char ssgEnv=op.ssgEnv&7; unsigned char ssgEnv=op.ssgEnv&7;
if (ins->type!=DIV_INS_OPL && ins->type!=DIV_INS_OPZ) { 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 if (ImGui::Checkbox((ins->type==DIV_INS_OPLL)?FM_NAME(FM_EGS):"SSG On",&ssgOn)) { PARAMETER
op.ssgEnv=(op.ssgEnv&7)|(ssgOn<<3); op.ssgEnv=(op.ssgEnv&7)|(ssgOn<<3);
} }
@ -1836,6 +1882,7 @@ void FurnaceGUI::drawInsEdit() {
} }
if (ins->type==DIV_INS_OPL) { if (ins->type==DIV_INS_OPL) {
ImGui::SameLine();
if (ImGui::Checkbox(FM_NAME(FM_SUS),&susOn)) { PARAMETER if (ImGui::Checkbox(FM_NAME(FM_SUS),&susOn)) { PARAMETER
op.sus=susOn; op.sus=susOn;
} }
@ -1953,14 +2000,16 @@ void FurnaceGUI::drawInsEdit() {
ImGui::TableNextColumn(); ImGui::TableNextColumn();
ImGui::Text("%s",FM_NAME(FM_DT2)); ImGui::Text("%s",FM_NAME(FM_DT2));
ImGui::TableNextRow(); if (ins->type==DIV_INS_FM) { // OPN only
ImGui::TableNextColumn(); ImGui::TableNextRow();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); ImGui::TableNextColumn();
if (CWSliderScalar("##SSG",ImGuiDataType_U8,&ssgEnv,&_ZERO,&_SEVEN,ssgEnvTypes[ssgEnv])) { PARAMETER ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
op.ssgEnv=(op.ssgEnv&8)|(ssgEnv&7); if (CWSliderScalar("##SSG",ImGuiDataType_U8,&ssgEnv,&_ZERO,&_SEVEN,ssgEnvTypes[ssgEnv])) { PARAMETER
} rightClickable op.ssgEnv=(op.ssgEnv&8)|(ssgEnv&7);
ImGui::TableNextColumn(); } rightClickable
ImGui::Text("%s",FM_NAME(FM_SSG)); ImGui::TableNextColumn();
ImGui::Text("%s",FM_NAME(FM_SSG));
}
} }
if (ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPZ) { if (ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPZ) {
@ -1999,24 +2048,31 @@ void FurnaceGUI::drawInsEdit() {
if (ImGui::BeginTabItem("FM Macros")) { if (ImGui::BeginTabItem("FM Macros")) {
MACRO_BEGIN(0); MACRO_BEGIN(0);
if (ins->type==DIV_INS_OPLL) { 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.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,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.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,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.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,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.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 { } 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.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,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.fbMacro,0,7,"fb",FM_NAME(FM_FB),96,ins->std.fbMacro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[1],0,7,NULL,false);
if (ins->type!=DIV_INS_OPL) { if (ins->type!=DIV_INS_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); if (ins->type==DIV_INS_OPZ) {
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); // 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) { 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.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,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.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,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.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,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,&macroLFOWaves,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,&macroLFOWaves,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; MACRO_END;
ImGui::EndTabItem(); ImGui::EndTabItem();
@ -2041,45 +2097,45 @@ void FurnaceGUI::drawInsEdit() {
int maxArDr=(ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ)?31:15; int maxArDr=(ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ)?31:15;
if (ins->type==DIV_INS_OPL) { 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].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,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].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,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].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,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].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,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].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,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].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,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].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,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].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].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,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].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,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].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,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].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) { } 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].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,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].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,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].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,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].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,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].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,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].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,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].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].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,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].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,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].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,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].egtMacro,1,ordi,"egt",FM_NAME(FM_EGS),32,ins->std.opMacros[ordi].egtMacro.open,true,NULL,false,0,macroDummyMode,mmlString[11]);
} else { } 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].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,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].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,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].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,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].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,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].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,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].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,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].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,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].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,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].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,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].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,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].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,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].ssgMacro,4,ordi,"ssg",FM_NAME(FM_SSG),64,ins->std.opMacros[ordi].ssgMacro.open,true,ssgEnvBits,false,0,macroDummyMode,mmlString[11]);
} }
MACRO_END; MACRO_END;
ImGui::PopID(); ImGui::PopID();
@ -2464,7 +2520,7 @@ void FurnaceGUI::drawInsEdit() {
volMax=32; volMax=32;
} }
bool arpMode=ins->std.arpMacroMode; bool arpMode=ins->std.arpMacro.mode;
const char* dutyLabel="Duty/Noise"; const char* dutyLabel="Duty/Noise";
int dutyMax=3; int dutyMax=3;
@ -2571,66 +2627,67 @@ void FurnaceGUI::drawInsEdit() {
if (settings.macroView==0) { // modern view if (settings.macroView==0) { // modern view
MACRO_BEGIN(28*dpiScale); MACRO_BEGIN(28*dpiScale);
if (volMax>0) { 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?(&macroHoverNote):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?(&macroHoverNote):NULL),true);
if (dutyMax>0) { if (dutyMax>0) {
if (ins->type==DIV_INS_MIKEY) { if (ins->type==DIV_INS_MIKEY) {
NORMAL_MACRO(ins->std.dutyMacro,ins->std.dutyMacroLen,ins->std.dutyMacroLoop,ins->std.dutyMacroRel,0,dutyMax,"duty",dutyLabel,160,ins->std.dutyMacroOpen,true,mikeyFeedbackBits,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[2],0,dutyMax,NULL,false); NORMAL_MACRO(ins->std.dutyMacro,0,dutyMax,"duty",dutyLabel,160,ins->std.dutyMacro.open,true,mikeyFeedbackBits,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[2],0,dutyMax,NULL,false);
} else if (ins->type==DIV_INS_C64) {
NORMAL_MACRO(ins->std.dutyMacro,0,dutyMax,"duty",dutyLabel,160,ins->std.dutyMacro.open,false,NULL,false,NULL,0,0,0,true,1,macroAbsoluteMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[2],0,dutyMax,NULL,false);
} else {
NORMAL_MACRO(ins->std.dutyMacro,0,dutyMax,"duty",dutyLabel,160,ins->std.dutyMacro.open,false,NULL,false,NULL,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[2],0,dutyMax,NULL,false);
} }
else {
NORMAL_MACRO(ins->std.dutyMacro,ins->std.dutyMacroLen,ins->std.dutyMacroLoop,ins->std.dutyMacroRel,0,dutyMax,"duty",dutyLabel,160,ins->std.dutyMacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[2],0,dutyMax,NULL,false);
}
} }
if (waveMax>0) { 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 (ex1Max>0) {
if (ins->type==DIV_INS_C64) { 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) { } 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) { } 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) { } 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) { } 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 { } 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 (ex2Max>0) {
if (ins->type==DIV_INS_C64) { 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) { } 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) { } 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 { } 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) { 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) { 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.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,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.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) { if (ins->type==DIV_INS_AY8930) {
// oh my i am running out of macros // 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.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,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.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) { 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.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,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.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,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.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,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.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) { 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; MACRO_END;
@ -2646,87 +2703,87 @@ void FurnaceGUI::drawInsEdit() {
} else { } else {
ImGui::Text("Volume Macro"); 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) { 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 { } 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; macroDragScroll=0;
if (volMax>0) { if (volMax>0) {
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding,ImVec2(0.0f,0.0f)); 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)) { if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) {
macroDragStart=ImGui::GetItemRectMin(); macroDragStart=ImGui::GetItemRectMin();
macroDragAreaSize=ImVec2(400.0f*dpiScale,200.0f*dpiScale); macroDragAreaSize=ImVec2(400.0f*dpiScale,200.0f*dpiScale);
macroDragMin=volMin; macroDragMin=volMin;
macroDragMax=volMax; macroDragMax=volMax;
macroDragLen=ins->std.volMacroLen; macroDragLen=ins->std.volMacro.len;
macroDragActive=true; macroDragActive=true;
macroDragTarget=ins->std.volMacro; macroDragTarget=ins->std.volMacro.val;
macroDragChar=false; macroDragChar=false;
processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y); 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)) { if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) {
macroLoopDragStart=ImGui::GetItemRectMin(); macroLoopDragStart=ImGui::GetItemRectMin();
macroLoopDragAreaSize=ImVec2(400.0f*dpiScale,16.0f*dpiScale); macroLoopDragAreaSize=ImVec2(400.0f*dpiScale,16.0f*dpiScale);
macroLoopDragLen=ins->std.volMacroLen; macroLoopDragLen=ins->std.volMacro.len;
macroLoopDragTarget=&ins->std.volMacroLoop; macroLoopDragTarget=&ins->std.volMacro.loop;
macroLoopDragActive=true; macroLoopDragActive=true;
processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y); processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y);
} }
if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) { if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) {
ins->std.volMacroLoop=-1; ins->std.volMacro.loop=-1;
} }
ImGui::PopStyleVar(); ImGui::PopStyleVar();
if (ImGui::InputScalar("Length##IVolMacroL",ImGuiDataType_U8,&ins->std.volMacroLen,&_ONE,&_THREE)) { if (ImGui::InputScalar("Length##IVolMacroL",ImGuiDataType_U8,&ins->std.volMacro.len,&_ONE,&_THREE)) {
if (ins->std.volMacroLen>127) ins->std.volMacroLen=127; if (ins->std.volMacro.len>127) ins->std.volMacro.len=127;
} }
} }
// arp macro // arp macro
ImGui::Separator(); ImGui::Separator();
ImGui::Text("Arpeggio Macro"); ImGui::Text("Arpeggio Macro");
for (int i=0; i<ins->std.arpMacroLen; i++) { for (int i=0; i<ins->std.arpMacro.len; i++) {
asFloat[i]=ins->std.arpMacro[i]; asFloat[i]=ins->std.arpMacro.val[i];
loopIndicator[i]=(ins->std.arpMacroLoop!=-1 && i>=ins->std.arpMacroLoop); loopIndicator[i]=(ins->std.arpMacro.loop!=-1 && i>=ins->std.arpMacro.loop);
} }
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding,ImVec2(0.0f,0.0f)); 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)) { if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) {
macroDragStart=ImGui::GetItemRectMin(); macroDragStart=ImGui::GetItemRectMin();
macroDragAreaSize=ImVec2(400.0f*dpiScale,200.0f*dpiScale); macroDragAreaSize=ImVec2(400.0f*dpiScale,200.0f*dpiScale);
macroDragMin=arpMacroScroll; macroDragMin=arpMacroScroll;
macroDragMax=arpMacroScroll+24; macroDragMax=arpMacroScroll+24;
macroDragLen=ins->std.arpMacroLen; macroDragLen=ins->std.arpMacro.len;
macroDragActive=true; macroDragActive=true;
macroDragTarget=ins->std.arpMacro; macroDragTarget=ins->std.arpMacro.val;
macroDragChar=false; macroDragChar=false;
processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y); processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y);
} }
ImGui::SameLine(); ImGui::SameLine();
CWVSliderInt("##IArpMacroPos",ImVec2(20.0f*dpiScale,200.0f*dpiScale),&arpMacroScroll,arpMode?0:-80,70); 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)) { if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) {
macroLoopDragStart=ImGui::GetItemRectMin(); macroLoopDragStart=ImGui::GetItemRectMin();
macroLoopDragAreaSize=ImVec2(400.0f*dpiScale,16.0f*dpiScale); macroLoopDragAreaSize=ImVec2(400.0f*dpiScale,16.0f*dpiScale);
macroLoopDragLen=ins->std.arpMacroLen; macroLoopDragLen=ins->std.arpMacro.len;
macroLoopDragTarget=&ins->std.arpMacroLoop; macroLoopDragTarget=&ins->std.arpMacro.loop;
macroLoopDragActive=true; macroLoopDragActive=true;
processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y); processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y);
} }
if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) { if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) {
ins->std.arpMacroLoop=-1; ins->std.arpMacro.loop=-1;
} }
ImGui::PopStyleVar(); ImGui::PopStyleVar();
if (ImGui::InputScalar("Length##IArpMacroL",ImGuiDataType_U8,&ins->std.arpMacroLen,&_ONE,&_THREE)) { if (ImGui::InputScalar("Length##IArpMacroL",ImGuiDataType_U8,&ins->std.arpMacro.len,&_ONE,&_THREE)) {
if (ins->std.arpMacroLen>127) ins->std.arpMacroLen=127; if (ins->std.arpMacro.len>127) ins->std.arpMacro.len=127;
} }
if (ImGui::Checkbox("Fixed",&arpMode)) { if (ImGui::Checkbox("Fixed",&arpMode)) {
ins->std.arpMacroMode=arpMode; ins->std.arpMacro.mode=arpMode;
if (arpMode) { if (arpMode) {
if (arpMacroScroll<0) arpMacroScroll=0; if (arpMacroScroll<0) arpMacroScroll=0;
} }
@ -2748,39 +2805,39 @@ void FurnaceGUI::drawInsEdit() {
ImGui::Text("Duty/Noise Mode Macro"); ImGui::Text("Duty/Noise Mode Macro");
} }
} }
for (int i=0; i<ins->std.dutyMacroLen; i++) { for (int i=0; i<ins->std.dutyMacro.len; i++) {
asFloat[i]=ins->std.dutyMacro[i]-(dutyIsRel?12:0); asFloat[i]=ins->std.dutyMacro.val[i]-(dutyIsRel?12:0);
loopIndicator[i]=(ins->std.dutyMacroLoop!=-1 && i>=ins->std.dutyMacroLoop); loopIndicator[i]=(ins->std.dutyMacro.loop!=-1 && i>=ins->std.dutyMacro.loop);
} }
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding,ImVec2(0.0f,0.0f)); 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)) { if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) {
macroDragStart=ImGui::GetItemRectMin(); macroDragStart=ImGui::GetItemRectMin();
macroDragAreaSize=ImVec2(400.0f*dpiScale,200.0f*dpiScale); macroDragAreaSize=ImVec2(400.0f*dpiScale,200.0f*dpiScale);
macroDragMin=0; macroDragMin=0;
macroDragMax=dutyMax; macroDragMax=dutyMax;
macroDragLen=ins->std.dutyMacroLen; macroDragLen=ins->std.dutyMacro.len;
macroDragActive=true; macroDragActive=true;
macroDragTarget=ins->std.dutyMacro; macroDragTarget=ins->std.dutyMacro.val;
macroDragChar=false; macroDragChar=false;
processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y); 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)) { if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) {
macroLoopDragStart=ImGui::GetItemRectMin(); macroLoopDragStart=ImGui::GetItemRectMin();
macroLoopDragAreaSize=ImVec2(400.0f*dpiScale,16.0f*dpiScale); macroLoopDragAreaSize=ImVec2(400.0f*dpiScale,16.0f*dpiScale);
macroLoopDragLen=ins->std.dutyMacroLen; macroLoopDragLen=ins->std.dutyMacro.len;
macroLoopDragTarget=&ins->std.dutyMacroLoop; macroLoopDragTarget=&ins->std.dutyMacro.loop;
macroLoopDragActive=true; macroLoopDragActive=true;
processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y); processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y);
} }
if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) { if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) {
ins->std.dutyMacroLoop=-1; ins->std.dutyMacro.loop=-1;
} }
ImGui::PopStyleVar(); ImGui::PopStyleVar();
if (ImGui::InputScalar("Length##IDutyMacroL",ImGuiDataType_U8,&ins->std.dutyMacroLen,&_ONE,&_THREE)) { if (ImGui::InputScalar("Length##IDutyMacroL",ImGuiDataType_U8,&ins->std.dutyMacro.len,&_ONE,&_THREE)) {
if (ins->std.dutyMacroLen>127) ins->std.dutyMacroLen=127; if (ins->std.dutyMacro.len>127) ins->std.dutyMacro.len=127;
} }
} }
@ -2788,24 +2845,24 @@ void FurnaceGUI::drawInsEdit() {
if (waveMax>0) { if (waveMax>0) {
ImGui::Separator(); ImGui::Separator();
ImGui::Text("Waveform Macro"); ImGui::Text("Waveform Macro");
for (int i=0; i<ins->std.waveMacroLen; i++) { for (int i=0; i<ins->std.waveMacro.len; i++) {
asFloat[i]=ins->std.waveMacro[i]; asFloat[i]=ins->std.waveMacro.val[i];
if (ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930) { 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 { } 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)); ImGui::PushStyleVar(ImGuiStyleVar_FramePadding,ImVec2(0.0f,0.0f));
ImVec2 areaSize=ImVec2(400.0f*dpiScale,200.0f*dpiScale); 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) { 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); 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; bitMode=true;
} else { } 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)) { if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) {
macroDragStart=ImGui::GetItemRectMin(); macroDragStart=ImGui::GetItemRectMin();
@ -2816,27 +2873,27 @@ void FurnaceGUI::drawInsEdit() {
macroDragBitMode=bitMode; macroDragBitMode=bitMode;
macroDragInitialValueSet=false; macroDragInitialValueSet=false;
macroDragInitialValue=false; macroDragInitialValue=false;
macroDragLen=ins->std.waveMacroLen; macroDragLen=ins->std.waveMacro.len;
macroDragActive=true; macroDragActive=true;
macroDragTarget=ins->std.waveMacro; macroDragTarget=ins->std.waveMacro.val;
macroDragChar=false; macroDragChar=false;
processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y); 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)) { if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) {
macroLoopDragStart=ImGui::GetItemRectMin(); macroLoopDragStart=ImGui::GetItemRectMin();
macroLoopDragAreaSize=ImVec2(400.0f*dpiScale,16.0f*dpiScale); macroLoopDragAreaSize=ImVec2(400.0f*dpiScale,16.0f*dpiScale);
macroLoopDragLen=ins->std.waveMacroLen; macroLoopDragLen=ins->std.waveMacro.len;
macroLoopDragTarget=&ins->std.waveMacroLoop; macroLoopDragTarget=&ins->std.waveMacro.loop;
macroLoopDragActive=true; macroLoopDragActive=true;
processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y); processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y);
} }
if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) { if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) {
ins->std.waveMacroLoop=-1; ins->std.waveMacro.loop=-1;
} }
ImGui::PopStyleVar(); ImGui::PopStyleVar();
if (ImGui::InputScalar("Length##IWaveMacroL",ImGuiDataType_U8,&ins->std.waveMacroLen,&_ONE,&_THREE)) { if (ImGui::InputScalar("Length##IWaveMacroL",ImGuiDataType_U8,&ins->std.waveMacro.len,&_ONE,&_THREE)) {
if (ins->std.waveMacroLen>127) ins->std.waveMacroLen=127; if (ins->std.waveMacro.len>127) ins->std.waveMacro.len=127;
} }
} }
@ -2848,39 +2905,39 @@ void FurnaceGUI::drawInsEdit() {
} else { } else {
ImGui::Text("Extra 1 Macro"); ImGui::Text("Extra 1 Macro");
} }
for (int i=0; i<ins->std.ex1MacroLen; i++) { for (int i=0; i<ins->std.ex1Macro.len; i++) {
asFloat[i]=ins->std.ex1Macro[i]; asFloat[i]=ins->std.ex1Macro.val[i];
loopIndicator[i]=(ins->std.ex1MacroLoop!=-1 && i>=ins->std.ex1MacroLoop); loopIndicator[i]=(ins->std.ex1Macro.loop!=-1 && i>=ins->std.ex1Macro.loop);
} }
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding,ImVec2(0.0f,0.0f)); 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)) { if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) {
macroDragStart=ImGui::GetItemRectMin(); macroDragStart=ImGui::GetItemRectMin();
macroDragAreaSize=ImVec2(400.0f*dpiScale,200.0f*dpiScale); macroDragAreaSize=ImVec2(400.0f*dpiScale,200.0f*dpiScale);
macroDragMin=0; macroDragMin=0;
macroDragMax=ex1Max; macroDragMax=ex1Max;
macroDragLen=ins->std.ex1MacroLen; macroDragLen=ins->std.ex1Macro.len;
macroDragActive=true; macroDragActive=true;
macroDragTarget=ins->std.ex1Macro; macroDragTarget=ins->std.ex1Macro.val;
macroDragChar=false; macroDragChar=false;
processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y); 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)) { if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) {
macroLoopDragStart=ImGui::GetItemRectMin(); macroLoopDragStart=ImGui::GetItemRectMin();
macroLoopDragAreaSize=ImVec2(400.0f*dpiScale,16.0f*dpiScale); macroLoopDragAreaSize=ImVec2(400.0f*dpiScale,16.0f*dpiScale);
macroLoopDragLen=ins->std.ex1MacroLen; macroLoopDragLen=ins->std.ex1Macro.len;
macroLoopDragTarget=&ins->std.ex1MacroLoop; macroLoopDragTarget=&ins->std.ex1Macro.loop;
macroLoopDragActive=true; macroLoopDragActive=true;
processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y); processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y);
} }
if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) { if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) {
ins->std.ex1MacroLoop=-1; ins->std.ex1Macro.loop=-1;
} }
ImGui::PopStyleVar(); ImGui::PopStyleVar();
if (ImGui::InputScalar("Length##IEx1MacroL",ImGuiDataType_U8,&ins->std.ex1MacroLen,&_ONE,&_THREE)) { if (ImGui::InputScalar("Length##IEx1MacroL",ImGuiDataType_U8,&ins->std.ex1Macro.len,&_ONE,&_THREE)) {
if (ins->std.ex1MacroLen>127) ins->std.ex1MacroLen=127; if (ins->std.ex1Macro.len>127) ins->std.ex1Macro.len=127;
} }
} }
} }

77
src/gui/log.cpp Normal file
View 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();
}

View file

@ -64,7 +64,7 @@ int MIDIMap::at(const TAMidiMessage& where) {
#define UNDERSTAND_ARRAY_OPTION(x,yMax) if (optionNameS==#x) { \ #define UNDERSTAND_ARRAY_OPTION(x,yMax) if (optionNameS==#x) { \
if (optionIndex<0 || optionIndex>=yMax) { \ 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; \ break; \
} \ } \
x[optionIndex]=std::stoi(optionValueS); \ x[optionIndex]=std::stoi(optionValueS); \
@ -76,7 +76,7 @@ bool MIDIMap::read(String path) {
FILE* f=fopen(path.c_str(),"rb"); FILE* f=fopen(path.c_str(),"rb");
if (f==NULL) { if (f==NULL) {
if (errno!=ENOENT) { if (errno!=ENOENT) {
logE("error while loading MIDI mapping! %s\n",strerror(errno)); logE("error while loading MIDI mapping! %s",strerror(errno));
} }
return false; return false;
} }
@ -93,7 +93,7 @@ bool MIDIMap::read(String path) {
int result=sscanf(line,"aOption %255s %d %255s",optionName,&optionIndex,optionValue); int result=sscanf(line,"aOption %255s %d %255s",optionName,&optionIndex,optionValue);
if (result!=3) { 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; break;
} }
@ -105,12 +105,12 @@ bool MIDIMap::read(String path) {
UNDERSTAND_ARRAY_OPTION(valueInputSpecificMSB,18) else UNDERSTAND_ARRAY_OPTION(valueInputSpecificMSB,18) else
UNDERSTAND_ARRAY_OPTION(valueInputSpecificLSB,18) else UNDERSTAND_ARRAY_OPTION(valueInputSpecificLSB,18) else
UNDERSTAND_ARRAY_OPTION(valueInputSpecificSingle,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) { } 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) { } 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++; curLine++;
@ -122,7 +122,7 @@ bool MIDIMap::read(String path) {
String optionNameS, optionValueS; String optionNameS, optionValueS;
int result=sscanf(line,"option %255s %255s",optionName,optionValue); int result=sscanf(line,"option %255s %255s",optionName,optionValue);
if (result!=2) { 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; break;
} }
@ -143,12 +143,12 @@ bool MIDIMap::read(String path) {
UNDERSTAND_OPTION(valueInputControlLSB) else UNDERSTAND_OPTION(valueInputControlLSB) else
UNDERSTAND_OPTION(valueInputControlSingle) else UNDERSTAND_OPTION(valueInputControlSingle) else
UNDERSTAND_FLOAT_OPTION(volExp) 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) { } 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) { } 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++; curLine++;
@ -159,7 +159,7 @@ bool MIDIMap::read(String path) {
MIDIBind bind; MIDIBind bind;
int result=sscanf(line,"%d %d %d %d %255s",&bind.type,&bind.channel,&bind.data1,&bind.data2,bindAction); int result=sscanf(line,"%d %d %d %d %255s",&bind.type,&bind.channel,&bind.data1,&bind.data2,bindAction);
if (result!=5 || result==EOF) { 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; break;
} }
@ -172,7 +172,7 @@ bool MIDIMap::read(String path) {
} }
} }
if (!foundAction) { 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; break;
} }
@ -191,7 +191,7 @@ bool MIDIMap::read(String path) {
bool MIDIMap::write(String path) { bool MIDIMap::write(String path) {
FILE* f=fopen(path.c_str(),"wb"); FILE* f=fopen(path.c_str(),"wb");
if (f==NULL) { if (f==NULL) {
logE("error while saving MIDI mapping! %s\n",strerror(errno)); logE("error while saving MIDI mapping! %s",strerror(errno));
return false; return false;
} }
@ -218,7 +218,7 @@ bool MIDIMap::write(String path) {
for (MIDIBind& i: binds) { 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) { 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; break;
} }
} }
@ -274,6 +274,6 @@ void MIDIMap::compile() {
} }
map[i.type-8][i.channel][i.data1][i.data2]=i.action; 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);
} }
} }

View file

@ -102,10 +102,10 @@ void FurnaceGUI::drawOrders() {
e->lockSave([this,i,j]() { e->lockSave([this,i,j]() {
if (changeAllOrders) { if (changeAllOrders) {
for (int k=0; k<e->getTotalChannelCount(); k++) { 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 { } 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); e->walkSong(loopOrder,loopRow,loopEnd);

View file

@ -18,6 +18,52 @@
*/ */
#include "gui.h" #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() { void FurnaceGUI::drawOsc() {
if (nextWindow==GUI_WINDOW_OSCILLOSCOPE) { if (nextWindow==GUI_WINDOW_OSCILLOSCOPE) {
@ -27,21 +73,112 @@ void FurnaceGUI::drawOsc() {
} }
if (!oscOpen) return; if (!oscOpen) return;
ImGui::SetNextWindowSizeConstraints(ImVec2(64.0f*dpiScale,32.0f*dpiScale),ImVec2(scrW*dpiScale,scrH*dpiScale)); ImGui::SetNextWindowSizeConstraints(ImVec2(64.0f*dpiScale,32.0f*dpiScale),ImVec2(scrW*dpiScale,scrH*dpiScale));
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding,ImVec2(0,0)); if (settings.oscTakesEntireWindow) {
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing,ImVec2(0,0)); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding,ImVec2(0,0));
ImGui::PushStyleVar(ImGuiStyleVar_ItemInnerSpacing,ImVec2(0,0)); ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing,ImVec2(0,0));
if (ImGui::Begin("Oscilloscope",&oscOpen)) { ImGui::PushStyleVar(ImGuiStyleVar_ItemInnerSpacing,ImVec2(0,0));
float values[512]; }
for (int i=0; i<512; i++) { if (ImGui::Begin("Oscilloscope",&oscOpen)) {
int pos=i*e->oscSize/512; if (oscZoomSlider) {
values[i]=(e->oscBuf[0][pos]+e->oscBuf[1][pos])*0.5f; if (ImGui::VSliderFloat("##OscZoom",ImVec2(20.0f*dpiScale,ImGui::GetContentRegionAvail().y),&oscZoom,0.5,2.0)) {
} if (oscZoom<0.5) oscZoom=0.5;
//ImGui::SetCursorPos(ImVec2(0,0)); if (oscZoom>2.0) oscZoom=2.0;
ImGui::BeginDisabled(); }
ImGui::PlotLines("##SingleOsc",values,512,0,NULL,-1.0f,1.0f,ImGui::GetContentRegionAvail()); ImGui::SameLine();
ImGui::EndDisabled(); }
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);
} }
ImGui::PopStyleVar(3);
if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_OSCILLOSCOPE; if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_OSCILLOSCOPE;
ImGui::End(); ImGui::End();
} }

View file

@ -17,8 +17,6 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#include <SDL_timer.h>
#include <imgui.h>
#define _USE_MATH_DEFINES #define _USE_MATH_DEFINES
#include "gui.h" #include "gui.h"
#include "../ta-log.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); sprintf(id,"..##PE%d_%d_%d",k,i,j);
ImGui::PushStyleColor(ImGuiCol_Text,inactiveColor); ImGui::PushStyleColor(ImGuiCol_Text,inactiveColor);
} else { } else {
sprintf(id,"%.2X##PE%d_%d_%d",pat->data[i][index],k,i,j); if (pat->data[i][index]>0xff) {
if (pat->data[i][index]<0x10) { sprintf(id,"??##PE%d_%d_%d",k,i,j);
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) {
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_INVALID]); ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_INVALID]);
} else { } 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); ImGui::SameLine(0.0f,0.0f);
@ -870,6 +874,6 @@ void FurnaceGUI::drawPattern() {
if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_PATTERN; if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_PATTERN;
ImGui::End(); ImGui::End();
//int delta1=SDL_GetPerformanceCounter(); //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));
} }

View file

@ -589,12 +589,12 @@ void FurnaceGUI::drawSampleEdit() {
sampleTex=NULL; sampleTex=NULL;
} }
if (avail.x>=1 && avail.y>=1) { 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); sampleTex=SDL_CreateTexture(sdlRend,SDL_PIXELFORMAT_ABGR8888,SDL_TEXTUREACCESS_STREAMING,avail.x,avail.y);
sampleTexW=avail.x; sampleTexW=avail.x;
sampleTexH=avail.y; sampleTexH=avail.y;
if (sampleTex==NULL) { if (sampleTex==NULL) {
logE("error while creating sample texture! %s\n",SDL_GetError()); logE("error while creating sample texture! %s",SDL_GetError());
} else { } else {
updateSampleTex=true; updateSampleTex=true;
} }
@ -605,9 +605,9 @@ void FurnaceGUI::drawSampleEdit() {
if (updateSampleTex) { if (updateSampleTex) {
unsigned int* data=NULL; unsigned int* data=NULL;
int pitch=0; int pitch=0;
logD("updating sample texture.\n"); logD("updating sample texture.");
if (SDL_LockTexture(sampleTex,NULL,(void**)&data,&pitch)!=0) { 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 { } else {
ImU32 bgColor=ImGui::GetColorU32(ImGuiCol_FrameBg); ImU32 bgColor=ImGui::GetColorU32(ImGuiCol_FrameBg);
ImU32 bgColorLoop=ImAlphaBlendColors(bgColor,ImGui::GetColorU32(ImGuiCol_FrameBgHovered,0.5)); 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)); ImU32 centerLineColor=ImAlphaBlendColors(bgColor,ImGui::GetColorU32(ImGuiCol_PlotLines,0.25));
for (int i=0; i<availY; i++) { for (int i=0; i<availY; i++) {
for (int j=0; j<availX; j++) { 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; data[i*availX+j]=bgColorLoop;
} else { } else {
data[i*availX+j]=bgColor; data[i*availX+j]=bgColor;
@ -880,4 +880,4 @@ void FurnaceGUI::doRedoSample() {
updateSampleTex=true; updateSampleTex=true;
} }
}); });
} }

View file

@ -148,7 +148,9 @@ const char* specificControls[18]={
} }
#define UI_COLOR_CONFIG(what,label) \ #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) \ #define KEYBIND_CONFIG_BEGIN(id) \
if (ImGui::BeginTable(id,2)) { if (ImGui::BeginTable(id,2)) {
@ -384,8 +386,8 @@ void FurnaceGUI::drawSettings() {
TAAudioDesc& audioWant=e->getAudioDescWant(); TAAudioDesc& audioWant=e->getAudioDescWant();
TAAudioDesc& audioGot=e->getAudioDescGot(); TAAudioDesc& audioGot=e->getAudioDescGot();
ImGui::Text("want: %d samples @ %.0fHz\n",audioWant.bufsize,audioWant.rate); ImGui::Text("want: %d samples @ %.0fHz",audioWant.bufsize,audioWant.rate);
ImGui::Text("got: %d samples @ %.0fHz\n",audioGot.bufsize,audioGot.rate); ImGui::Text("got: %d samples @ %.0fHz",audioGot.bufsize,audioGot.rate);
ImGui::Separator(); ImGui::Separator();
@ -894,6 +896,25 @@ void FurnaceGUI::drawSettings() {
ImGui::Separator(); 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::TreeNode("Color scheme")) {
if (ImGui::Button("Import")) { if (ImGui::Button("Import")) {
openFileDialog(GUI_FILE_IMPORT_COLORS); openFileDialog(GUI_FILE_IMPORT_COLORS);
@ -942,6 +963,18 @@ void FurnaceGUI::drawSettings() {
UI_COLOR_CONFIG(GUI_COLOR_FILE_OTHER,"Other"); UI_COLOR_CONFIG(GUI_COLOR_FILE_OTHER,"Other");
ImGui::TreePop(); 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")) { if (ImGui::TreeNode("Volume Meter")) {
UI_COLOR_CONFIG(GUI_COLOR_VOLMETER_LOW,"Low"); UI_COLOR_CONFIG(GUI_COLOR_VOLMETER_LOW,"Low");
UI_COLOR_CONFIG(GUI_COLOR_VOLMETER_HIGH,"High"); 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"); UI_COLOR_CONFIG(GUI_COLOR_EE_VALUE,"External command output");
ImGui::TreePop(); 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(); ImGui::TreePop();
} }
@ -1114,6 +1155,7 @@ void FurnaceGUI::drawSettings() {
UI_KEYBIND_CONFIG(GUI_ACTION_WINDOW_NOTES); UI_KEYBIND_CONFIG(GUI_ACTION_WINDOW_NOTES);
UI_KEYBIND_CONFIG(GUI_ACTION_WINDOW_CHANNELS); UI_KEYBIND_CONFIG(GUI_ACTION_WINDOW_CHANNELS);
UI_KEYBIND_CONFIG(GUI_ACTION_WINDOW_REGISTER_VIEW); 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_COLLAPSE_WINDOW);
UI_KEYBIND_CONFIG(GUI_ACTION_CLOSE_WINDOW); UI_KEYBIND_CONFIG(GUI_ACTION_CLOSE_WINDOW);
@ -1463,6 +1505,9 @@ void FurnaceGUI::syncSettings() {
settings.titleBarSys=e->getConfInt("titleBarSys",1); settings.titleBarSys=e->getConfInt("titleBarSys",1);
settings.frameBorders=e->getConfInt("frameBorders",0); settings.frameBorders=e->getConfInt("frameBorders",0);
settings.effectDeletionAltersValue=e->getConfInt("effectDeletionAltersValue",1); 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.mainFontSize,2,96);
clampSetting(settings.patFontSize,2,96); clampSetting(settings.patFontSize,2,96);
@ -1590,6 +1635,9 @@ void FurnaceGUI::commitSettings() {
e->setConf("titleBarSys",settings.titleBarSys); e->setConf("titleBarSys",settings.titleBarSys);
e->setConf("frameBorders",settings.frameBorders); e->setConf("frameBorders",settings.frameBorders);
e->setConf("effectDeletionAltersValue",settings.effectDeletionAltersValue); e->setConf("effectDeletionAltersValue",settings.effectDeletionAltersValue);
e->setConf("oscRoundedCorners",settings.oscRoundedCorners);
e->setConf("oscTakesEntireWindow",settings.oscTakesEntireWindow);
e->setConf("oscBorder",settings.oscBorder);
// colors // colors
for (int i=0; i<GUI_COLOR_MAX; i++) { for (int i=0; i<GUI_COLOR_MAX; i++) {
@ -1621,14 +1669,14 @@ void FurnaceGUI::commitSettings() {
ImGui_ImplSDLRenderer_DestroyFontsTexture(); ImGui_ImplSDLRenderer_DestroyFontsTexture();
if (!ImGui::GetIO().Fonts->Build()) { 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."); showError("error while loading fonts! please check your settings.");
ImGui::GetIO().Fonts->Clear(); ImGui::GetIO().Fonts->Clear();
mainFont=ImGui::GetIO().Fonts->AddFontDefault(); mainFont=ImGui::GetIO().Fonts->AddFontDefault();
patFont=mainFont; patFont=mainFont;
ImGui_ImplSDLRenderer_DestroyFontsTexture(); ImGui_ImplSDLRenderer_DestroyFontsTexture();
if (!ImGui::GetIO().Fonts->Build()) { 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) { bool FurnaceGUI::importColors(String path) {
FILE* f=ps_fopen(path.c_str(),"rb"); FILE* f=ps_fopen(path.c_str(),"rb");
if (f==NULL) { 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; return false;
} }
resetColors(); resetColors();
@ -1677,22 +1725,23 @@ bool FurnaceGUI::importColors(String path) {
break; break;
} }
} }
if (!found) logW("line invalid: %s\n",line); if (!found) logW("line invalid: %s",line);
} }
} }
fclose(f); fclose(f);
applyUISettings(false);
return true; return true;
} }
bool FurnaceGUI::exportColors(String path) { bool FurnaceGUI::exportColors(String path) {
FILE* f=ps_fopen(path.c_str(),"wb"); FILE* f=ps_fopen(path.c_str(),"wb");
if (f==NULL) { 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; return false;
} }
for (int i=0; i<GUI_COLOR_MAX; i++) { for (int i=0; i<GUI_COLOR_MAX; i++) {
if (fprintf(f,"%s=%d\n",guiColors[i].name,ImGui::ColorConvertFloat4ToU32(uiColors[i]))<0) { 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; break;
} }
} }
@ -1703,7 +1752,7 @@ bool FurnaceGUI::exportColors(String path) {
bool FurnaceGUI::importKeybinds(String path) { bool FurnaceGUI::importKeybinds(String path) {
FILE* f=ps_fopen(path.c_str(),"rb"); FILE* f=ps_fopen(path.c_str(),"rb");
if (f==NULL) { 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; return false;
} }
resetKeybinds(); resetKeybinds();
@ -1744,7 +1793,7 @@ bool FurnaceGUI::importKeybinds(String path) {
break; break;
} }
} }
if (!found) logW("line invalid: %s\n",line); if (!found) logW("line invalid: %s",line);
} }
} }
fclose(f); fclose(f);
@ -1754,13 +1803,13 @@ bool FurnaceGUI::importKeybinds(String path) {
bool FurnaceGUI::exportKeybinds(String path) { bool FurnaceGUI::exportKeybinds(String path) {
FILE* f=ps_fopen(path.c_str(),"wb"); FILE* f=ps_fopen(path.c_str(),"wb");
if (f==NULL) { 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; return false;
} }
for (int i=0; i<GUI_ACTION_MAX; i++) { for (int i=0; i<GUI_ACTION_MAX; i++) {
if (guiActions[i].defaultBind==-1) continue; if (guiActions[i].defaultBind==-1) continue;
if (fprintf(f,"%s=%d\n",guiActions[i].name,actionKeys[i])<0) { 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; break;
} }
} }
@ -1771,7 +1820,7 @@ bool FurnaceGUI::exportKeybinds(String path) {
bool FurnaceGUI::importLayout(String path) { bool FurnaceGUI::importLayout(String path) {
FILE* f=ps_fopen(path.c_str(),"rb"); FILE* f=ps_fopen(path.c_str(),"rb");
if (f==NULL) { 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; return false;
} }
if (fseek(f,0,SEEK_END)<0) { if (fseek(f,0,SEEK_END)<0) {
@ -1785,7 +1834,7 @@ bool FurnaceGUI::importLayout(String path) {
} }
if (len<1) { if (len<1) {
if (len==0) { if (len==0) {
logE("that file is empty!\n"); logE("that file is empty!");
lastError="file is empty"; lastError="file is empty";
} else { } else {
perror("tell error"); perror("tell error");
@ -1818,13 +1867,13 @@ bool FurnaceGUI::importLayout(String path) {
bool FurnaceGUI::exportLayout(String path) { bool FurnaceGUI::exportLayout(String path) {
FILE* f=ps_fopen(path.c_str(),"wb"); FILE* f=ps_fopen(path.c_str(),"wb");
if (f==NULL) { 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; return false;
} }
size_t dataSize=0; size_t dataSize=0;
const char* data=ImGui::SaveIniSettingsToMemory(&dataSize); const char* data=ImGui::SaveIniSettingsToMemory(&dataSize);
if (fwrite(data,1,dataSize,f)!=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); fclose(f);
return true; return true;
@ -1924,7 +1973,7 @@ void FurnaceGUI::parseKeybinds() {
#define SYSTEM_PAT_FONT_PATH_3 "/usr/share/fonts/ubuntu/UbuntuMono-R.ttf" #define SYSTEM_PAT_FONT_PATH_3 "/usr/share/fonts/ubuntu/UbuntuMono-R.ttf"
#endif #endif
void FurnaceGUI::applyUISettings() { void FurnaceGUI::applyUISettings(bool updateFonts) {
ImGuiStyle sty; ImGuiStyle sty;
if (settings.guiColorsBase) { if (settings.guiColorsBase) {
ImGui::StyleColorsLight(&sty); ImGui::StyleColorsLight(&sty);
@ -1935,8 +1984,10 @@ void FurnaceGUI::applyUISettings() {
if (settings.dpiScale>=0.5f) dpiScale=settings.dpiScale; if (settings.dpiScale>=0.5f) dpiScale=settings.dpiScale;
// colors // colors
for (int i=0; i<GUI_COLOR_MAX; i++) { if (updateFonts) {
uiColors[i]=ImGui::ColorConvertU32ToFloat4(e->getConfInt(guiColors[i].name,guiColors[i].defaultColor)); 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++) { for (int i=0; i<64; i++) {
@ -2064,120 +2115,122 @@ void FurnaceGUI::applyUISettings() {
sysCmd2Grad[i]=ImGui::GetColorU32(ImVec4(base.x,base.y,base.z,((float)i/255.0f)*base.w)); sysCmd2Grad[i]=ImGui::GetColorU32(ImVec4(base.x,base.y,base.z,((float)i/255.0f)*base.w));
} }
// set to 800 for now due to problems with unifont if (updateFonts) {
static const ImWchar upTo800[]={0x20,0x7e,0xa0,0x800,0}; // set to 800 for now due to problems with unifont
ImFontGlyphRangesBuilder range; static const ImWchar upTo800[]={0x20,0x7e,0xa0,0x800,0};
ImVector<ImWchar> outRange; ImFontGlyphRangesBuilder range;
ImVector<ImWchar> outRange;
range.AddRanges(upTo800); range.AddRanges(upTo800);
if (settings.loadJapanese) { if (settings.loadJapanese) {
range.AddRanges(ImGui::GetIO().Fonts->GetGlyphRangesJapanese()); range.AddRanges(ImGui::GetIO().Fonts->GetGlyphRangesJapanese());
} }
// I'm terribly sorry // I'm terribly sorry
range.UsedChars[0x80>>5]=0; range.UsedChars[0x80>>5]=0;
range.BuildRanges(&outRange); range.BuildRanges(&outRange);
if (fontRange!=NULL) delete[] fontRange; if (fontRange!=NULL) delete[] fontRange;
fontRange=new ImWchar[outRange.size()]; fontRange=new ImWchar[outRange.size()];
int index=0; int index=0;
for (ImWchar& i: outRange) { for (ImWchar& i: outRange) {
fontRange[index++]=i; fontRange[index++]=i;
} }
if (settings.mainFont<0 || settings.mainFont>6) settings.mainFont=0; if (settings.mainFont<0 || settings.mainFont>6) settings.mainFont=0;
if (settings.patFont<0 || settings.patFont>6) settings.patFont=0; if (settings.patFont<0 || settings.patFont>6) settings.patFont=0;
if (settings.mainFont==6 && settings.mainFontPath.empty()) { 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");
settings.patFont=0;
}
ImFontConfig fc1;
fc1.MergeMode=true;
if (settings.mainFont==6) { // custom font
if ((mainFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(settings.mainFontPath.c_str(),e->getConfInt("mainFontSize",18)*dpiScale,NULL,fontRange))==NULL) {
logW("could not load UI font! reverting to default font\n");
settings.mainFont=0; settings.mainFont=0;
if ((mainFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFont[settings.mainFont],builtinFontLen[settings.mainFont],e->getConfInt("mainFontSize",18)*dpiScale,NULL,fontRange))==NULL) {
logE("could not load UI font! falling back to Proggy Clean.\n");
mainFont=ImGui::GetIO().Fonts->AddFontDefault();
}
} }
} else if (settings.mainFont==5) { // system font if (settings.patFont==6 && settings.patFontPath.empty()) {
if ((mainFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_FONT_PATH_1,e->getConfInt("mainFontSize",18)*dpiScale,NULL,fontRange))==NULL) { logW("pattern font path is empty! reverting to default font");
if ((mainFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_FONT_PATH_2,e->getConfInt("mainFontSize",18)*dpiScale,NULL,fontRange))==NULL) { settings.patFont=0;
if ((mainFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_FONT_PATH_3,e->getConfInt("mainFontSize",18)*dpiScale,NULL,fontRange))==NULL) { }
logW("could not load UI font! reverting to default font\n");
settings.mainFont=0; ImFontConfig fc1;
if ((mainFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFont[settings.mainFont],builtinFontLen[settings.mainFont],e->getConfInt("mainFontSize",18)*dpiScale,NULL,fontRange))==NULL) { fc1.MergeMode=true;
logE("could not load UI font! falling back to Proggy Clean.\n");
mainFont=ImGui::GetIO().Fonts->AddFontDefault(); if (settings.mainFont==6) { // custom font
} if ((mainFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(settings.mainFontPath.c_str(),e->getConfInt("mainFontSize",18)*dpiScale,NULL,fontRange))==NULL) {
logW("could not load UI font! reverting to default font");
settings.mainFont=0;
if ((mainFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFont[settings.mainFont],builtinFontLen[settings.mainFont],e->getConfInt("mainFontSize",18)*dpiScale,NULL,fontRange))==NULL) {
logE("could not load UI font! falling back to Proggy Clean.");
mainFont=ImGui::GetIO().Fonts->AddFontDefault();
} }
} }
} } else if (settings.mainFont==5) { // system font
} else { if ((mainFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_FONT_PATH_1,e->getConfInt("mainFontSize",18)*dpiScale,NULL,fontRange))==NULL) {
if ((mainFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFont[settings.mainFont],builtinFontLen[settings.mainFont],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) {
logE("could not load UI font! falling back to Proggy Clean.\n"); if ((mainFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_FONT_PATH_3,e->getConfInt("mainFontSize",18)*dpiScale,NULL,fontRange))==NULL) {
mainFont=ImGui::GetIO().Fonts->AddFontDefault(); 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.");
// two fallback fonts mainFont=ImGui::GetIO().Fonts->AddFontDefault();
mainFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(font_liberationSans_compressed_data,font_liberationSans_compressed_size,e->getConfInt("mainFontSize",18)*dpiScale,&fc1,fontRange);
mainFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(font_unifont_compressed_data,font_unifont_compressed_size,e->getConfInt("mainFontSize",18)*dpiScale,&fc1,fontRange);
ImFontConfig fc;
fc.MergeMode=true;
fc.GlyphMinAdvanceX=e->getConfInt("iconSize",16)*dpiScale;
static const ImWchar fontRangeIcon[]={ICON_MIN_FA,ICON_MAX_FA,0};
if ((iconFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(iconFont_compressed_data,iconFont_compressed_size,e->getConfInt("iconSize",16)*dpiScale,&fc,fontRangeIcon))==NULL) {
logE("could not load icon font!\n");
}
if (settings.mainFontSize==settings.patFontSize && settings.patFont<5 && builtinFontM[settings.patFont]==builtinFont[settings.mainFont]) {
logD("using main font for pat font.\n");
patFont=mainFont;
} else {
if (settings.patFont==6) { // custom font
if ((patFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(settings.patFontPath.c_str(),e->getConfInt("patFontSize",18)*dpiScale,NULL,upTo800))==NULL) {
logW("could not load pattern font! reverting to default font\n");
settings.patFont=0;
if ((patFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFontM[settings.patFont],builtinFontMLen[settings.patFont],e->getConfInt("patFontSize",18)*dpiScale,NULL,upTo800))==NULL) {
logE("could not load pattern font! falling back to Proggy Clean.\n");
patFont=ImGui::GetIO().Fonts->AddFontDefault();
}
}
} else if (settings.patFont==5) { // system font
if ((patFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_PAT_FONT_PATH_1,e->getConfInt("patFontSize",18)*dpiScale,NULL,upTo800))==NULL) {
if ((patFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_PAT_FONT_PATH_2,e->getConfInt("patFontSize",18)*dpiScale,NULL,upTo800))==NULL) {
if ((patFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_PAT_FONT_PATH_3,e->getConfInt("patFontSize",18)*dpiScale,NULL,upTo800))==NULL) {
logW("could not load pattern font! reverting to default font\n");
settings.patFont=0;
if ((patFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFontM[settings.patFont],builtinFontMLen[settings.patFont],e->getConfInt("patFontSize",18)*dpiScale,NULL,upTo800))==NULL) {
logE("could not load pattern font! falling back to Proggy Clean.\n");
patFont=ImGui::GetIO().Fonts->AddFontDefault();
} }
} }
} }
} }
} else { } else {
if ((patFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFontM[settings.patFont],builtinFontMLen[settings.patFont],e->getConfInt("patFontSize",18)*dpiScale,NULL,upTo800))==NULL) { if ((mainFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFont[settings.mainFont],builtinFontLen[settings.mainFont],e->getConfInt("mainFontSize",18)*dpiScale,NULL,fontRange))==NULL) {
logE("could not load pattern font!\n"); logE("could not load UI font! falling back to Proggy Clean.");
patFont=ImGui::GetIO().Fonts->AddFontDefault(); mainFont=ImGui::GetIO().Fonts->AddFontDefault();
} }
} }
}
if ((bigFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(font_plexSans_compressed_data,font_plexSans_compressed_size,40*dpiScale))==NULL) {
logE("could not load big UI font!\n");
}
mainFont->FallbackChar='?'; // two fallback fonts
mainFont->DotChar='.'; mainFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(font_liberationSans_compressed_data,font_liberationSans_compressed_size,e->getConfInt("mainFontSize",18)*dpiScale,&fc1,fontRange);
mainFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(font_unifont_compressed_data,font_unifont_compressed_size,e->getConfInt("mainFontSize",18)*dpiScale,&fc1,fontRange);
ImFontConfig fc;
fc.MergeMode=true;
fc.GlyphMinAdvanceX=e->getConfInt("iconSize",16)*dpiScale;
static const ImWchar fontRangeIcon[]={ICON_MIN_FA,ICON_MAX_FA,0};
if ((iconFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(iconFont_compressed_data,iconFont_compressed_size,e->getConfInt("iconSize",16)*dpiScale,&fc,fontRangeIcon))==NULL) {
logE("could not load icon font!");
}
if (settings.mainFontSize==settings.patFontSize && settings.patFont<5 && builtinFontM[settings.patFont]==builtinFont[settings.mainFont]) {
logD("using main font for pat font.");
patFont=mainFont;
} else {
if (settings.patFont==6) { // custom font
if ((patFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(settings.patFontPath.c_str(),e->getConfInt("patFontSize",18)*dpiScale,NULL,upTo800))==NULL) {
logW("could not load pattern font! reverting to default font");
settings.patFont=0;
if ((patFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFontM[settings.patFont],builtinFontMLen[settings.patFont],e->getConfInt("patFontSize",18)*dpiScale,NULL,upTo800))==NULL) {
logE("could not load pattern font! falling back to Proggy Clean.");
patFont=ImGui::GetIO().Fonts->AddFontDefault();
}
}
} else if (settings.patFont==5) { // system font
if ((patFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_PAT_FONT_PATH_1,e->getConfInt("patFontSize",18)*dpiScale,NULL,upTo800))==NULL) {
if ((patFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_PAT_FONT_PATH_2,e->getConfInt("patFontSize",18)*dpiScale,NULL,upTo800))==NULL) {
if ((patFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_PAT_FONT_PATH_3,e->getConfInt("patFontSize",18)*dpiScale,NULL,upTo800))==NULL) {
logW("could not load pattern font! reverting to default font");
settings.patFont=0;
if ((patFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFontM[settings.patFont],builtinFontMLen[settings.patFont],e->getConfInt("patFontSize",18)*dpiScale,NULL,upTo800))==NULL) {
logE("could not load pattern font! falling back to Proggy Clean.");
patFont=ImGui::GetIO().Fonts->AddFontDefault();
}
}
}
}
} else {
if ((patFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFontM[settings.patFont],builtinFontMLen[settings.patFont],e->getConfInt("patFontSize",18)*dpiScale,NULL,upTo800))==NULL) {
logE("could not load pattern font!");
patFont=ImGui::GetIO().Fonts->AddFontDefault();
}
}
}
if ((bigFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(font_plexSans_compressed_data,font_plexSans_compressed_size,40*dpiScale))==NULL) {
logE("could not load big UI font!");
}
mainFont->FallbackChar='?';
mainFont->DotChar='.';
}
// TODO: allow changing these colors. // TODO: allow changing these colors.
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByTypeDir,"",uiColors[GUI_COLOR_FILE_DIR],ICON_FA_FOLDER_O); 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,".fti",uiColors[GUI_COLOR_FILE_INSTR],ICON_FA_FILE);
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".bti",uiColors[GUI_COLOR_FILE_INSTR],ICON_FA_FILE); ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".bti",uiColors[GUI_COLOR_FILE_INSTR],ICON_FA_FILE);
if (fileDialog!=NULL) delete fileDialog; if (updateFonts) {
fileDialog=new FurnaceGUIFileDialog(settings.sysFileDialog); if (fileDialog!=NULL) delete fileDialog;
fileDialog=new FurnaceGUIFileDialog(settings.sysFileDialog);
}
} }

View file

@ -122,7 +122,7 @@ void FurnaceGUI::drawSongInfo() {
int ordLen=e->song.ordersLen; int ordLen=e->song.ordersLen;
if (ImGui::InputInt("##OrdLength",&ordLen,1,3)) { MARK_MODIFIED if (ImGui::InputInt("##OrdLength",&ordLen,1,3)) { MARK_MODIFIED
if (ordLen<1) ordLen=1; if (ordLen<1) ordLen=1;
if (ordLen>127) ordLen=127; if (ordLen>256) ordLen=256;
e->song.ordersLen=ordLen; e->song.ordersLen=ordLen;
if (e->getOrder()>=ordLen) { if (e->getOrder()>=ordLen) {
e->setOrder(ordLen-1); e->setOrder(ordLen-1);

Some files were not shown because too many files have changed in this diff Show more