Merge branch 'master' into opn_volbalance

This commit is contained in:
tildearrow 2023-02-05 04:58:03 -05:00
commit b4df0b923b
281 changed files with 3140 additions and 1639 deletions

View file

@ -11,7 +11,7 @@ defaults:
shell: bash shell: bash
env: env:
BUILD_TYPE: Debug BUILD_TYPE: RelWithDebInfo
jobs: jobs:
build: build:
@ -20,11 +20,11 @@ jobs:
config: config:
- { name: 'Windows MSVC x86', os: windows-latest, compiler: msvc, arch: x86 } - { name: 'Windows MSVC x86', os: windows-latest, compiler: msvc, arch: x86 }
- { name: 'Windows MSVC x86_64', os: windows-latest, compiler: msvc, arch: x86_64 } - { name: 'Windows MSVC x86_64', os: windows-latest, compiler: msvc, arch: x86_64 }
##- { name: 'Windows MinGW x86', os: ubuntu-20.04, compiler: mingw, arch: x86 } #- { name: 'Windows MinGW x86', os: ubuntu-20.04, compiler: mingw, arch: x86 }
##- { name: 'Windows MinGW x86_64', os: ubuntu-20.04, compiler: mingw, arch: x86_64 } #- { name: 'Windows MinGW x86_64', os: ubuntu-20.04, compiler: mingw, arch: x86_64 }
- { name: 'macOS x86_64', os: macos-latest, arch: x86_64 } - { name: 'macOS x86_64', os: macos-latest, arch: x86_64 }
- { name: 'macOS ARM', os: macos-latest, arch: arm64 } - { name: 'macOS ARM', os: macos-latest, arch: arm64 }
##- { name: 'Linux x86_64', os: ubuntu-18.04, arch: x86_64 } - { name: 'Linux x86_64', os: ubuntu-18.04, arch: x86_64 }
#- { name: 'Linux ARM', os: ubuntu-18.04, arch: armhf } #- { name: 'Linux ARM', os: ubuntu-18.04, arch: armhf }
fail-fast: false fail-fast: false
@ -278,6 +278,9 @@ jobs:
cp -v ../LICENSE LICENSE.txt cp -v ../LICENSE LICENSE.txt
cp -v ../README.md README.txt cp -v ../README.md README.txt
cp -vr ../{papers,demos,instruments} ../${binPath}/furnace.exe ./ cp -vr ../{papers,demos,instruments} ../${binPath}/furnace.exe ./
if [ '${{ matrix.config.compiler }}' == 'msvc' ]; then
cp -v ../${binPath}/furnace.pdb ./
fi
sha256sum ../${binPath}/furnace.exe > checksum.txt sha256sum ../${binPath}/furnace.exe > checksum.txt
popd popd

View file

@ -265,6 +265,9 @@ if (USE_SDL2)
if (MSVC) if (MSVC)
list(APPEND DEPENDENCIES_COMPILE_OPTIONS "/DHAVE_LIBC") list(APPEND DEPENDENCIES_COMPILE_OPTIONS "/DHAVE_LIBC")
endif() endif()
if (WIN32)
list(APPEND DEPENDENCIES_LIBRARIES SDL2main)
endif()
message(STATUS "Using vendored SDL2") message(STATUS "Using vendored SDL2")
endif() endif()
else() else()
@ -593,6 +596,7 @@ src/gui/editControls.cpp
src/gui/effectList.cpp src/gui/effectList.cpp
src/gui/findReplace.cpp src/gui/findReplace.cpp
src/gui/gradient.cpp src/gui/gradient.cpp
src/gui/grooves.cpp
src/gui/insEdit.cpp src/gui/insEdit.cpp
src/gui/log.cpp src/gui/log.cpp
src/gui/mixer.cpp src/gui/mixer.cpp
@ -610,6 +614,7 @@ src/gui/scaling.cpp
src/gui/settings.cpp src/gui/settings.cpp
src/gui/songInfo.cpp src/gui/songInfo.cpp
src/gui/songNotes.cpp src/gui/songNotes.cpp
src/gui/speed.cpp
src/gui/spoiler.cpp src/gui/spoiler.cpp
src/gui/stats.cpp src/gui/stats.cpp
src/gui/subSongs.cpp src/gui/subSongs.cpp

View file

@ -282,17 +282,13 @@ two possibilities:
- the recommended way is by creating the "Sample" type instrument and assigning a sample to it. - the recommended way is by creating the "Sample" type instrument and assigning a sample to it.
- otherwise you may employ the DefleMask-compatible method, using `17xx` effect. - otherwise you may employ the DefleMask-compatible method, using `17xx` effect.
> my .dmf song sounds very odd at a certain point > my .dmf song sounds odd at a certain point
file a bug report. use the Issues page. it's probably another playback inaccuracy. Furnace's .dmf compatibility isn't perfect and it's mostly because DefleMask does things different.
> my .dmf song sounds correct, but it doesn't in DefleMask
file a bug report **here**. it still is a playback inaccuracy.
> my song sounds terrible after saving as .dmf! > my song sounds terrible after saving as .dmf!
the DefleMask format has several limitations. save in Furnace song format instead (.fur). you should only save as .dmf if you're really sure, because the DefleMask format has several limitations. save in Furnace song format instead (.fur).
> how do I solo channels? > how do I solo channels?
@ -301,7 +297,7 @@ right click on the channel name.
--- ---
# footnotes # footnotes
copyright (C) 2021-2022 tildearrow and contributors. copyright (C) 2021-2023 tildearrow and contributors.
This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
@ -310,4 +306,4 @@ This program is distributed in the hope that it will be useful, but WITHOUT ANY
You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
despite the fact this program works with the .dmf file format, it is NOT affiliated with Delek or DefleMask in any way, nor it is a replacement for the original program. despite the fact this program works with the .dmf, .dmp and .dmw file formats (besides its native .fur format), it is NOT affiliated with Delek or DefleMask in any way, nor it is a replacement for the original program.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
demos/nes/the_best-1990.fur Normal file

Binary file not shown.

BIN
demos/nes/turtle_byte.fur Normal file

Binary file not shown.

BIN
demos/opl/e3m2_opl3.fur Normal file

Binary file not shown.

BIN
demos/pc98/Blue_Nebula.fur Normal file

Binary file not shown.

Binary file not shown.

BIN
demos/snes/amalgam.fur Normal file

Binary file not shown.

BIN
demos/specs2/Tim_Follin.fur Normal file

Binary file not shown.

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2019 Nuke.YKT * Copyright (C) 2019-2023 Nuke.YKT
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -17,7 +17,7 @@
* siliconpr0n.org(digshadow, John McMaster): * siliconpr0n.org(digshadow, John McMaster):
* VRC VII decap and die shot. * VRC VII decap and die shot.
* *
* version: 1.0.1 * version: 1.0.2
*/ */
#include <string.h> #include <string.h>
@ -132,7 +132,7 @@ static const opll_patch_t patch_ds1001[opll_patch_max] = {
{ 0x00, 0x00, 0x00, 0x00,{ 0x00, 0x00 },{ 0x00, 0x00 },{ 0x00, 0x00 },{ 0x00, 0x00 },{ 0x01, 0x00 },{ 0x00, 0x00 },{ 0x0c, 0x00 },{ 0x08, 0x00 },{ 0x0a, 0x00 },{ 0x07, 0x00 } }, { 0x00, 0x00, 0x00, 0x00,{ 0x00, 0x00 },{ 0x00, 0x00 },{ 0x00, 0x00 },{ 0x00, 0x00 },{ 0x01, 0x00 },{ 0x00, 0x00 },{ 0x0c, 0x00 },{ 0x08, 0x00 },{ 0x0a, 0x00 },{ 0x07, 0x00 } },
{ 0x00, 0x00, 0x00, 0x00,{ 0x00, 0x00 },{ 0x00, 0x00 },{ 0x00, 0x00 },{ 0x00, 0x00 },{ 0x05, 0x00 },{ 0x00, 0x00 },{ 0x0f, 0x00 },{ 0x08, 0x00 },{ 0x05, 0x00 },{ 0x09, 0x00 } }, { 0x00, 0x00, 0x00, 0x00,{ 0x00, 0x00 },{ 0x00, 0x00 },{ 0x00, 0x00 },{ 0x00, 0x00 },{ 0x05, 0x00 },{ 0x00, 0x00 },{ 0x0f, 0x00 },{ 0x08, 0x00 },{ 0x05, 0x00 },{ 0x09, 0x00 } },
{ 0x00, 0x00, 0x00, 0x00,{ 0x00, 0x00 },{ 0x00, 0x00 },{ 0x00, 0x00 },{ 0x00, 0x00 },{ 0x00, 0x01 },{ 0x00, 0x00 },{ 0x00, 0x0f },{ 0x00, 0x08 },{ 0x00, 0x06 },{ 0x00, 0x0d } }, { 0x00, 0x00, 0x00, 0x00,{ 0x00, 0x00 },{ 0x00, 0x00 },{ 0x00, 0x00 },{ 0x00, 0x00 },{ 0x00, 0x01 },{ 0x00, 0x00 },{ 0x00, 0x0f },{ 0x00, 0x08 },{ 0x00, 0x06 },{ 0x00, 0x0d } },
{ 0x00, 0x00, 0x00, 0x00,{ 0x00, 0x00 },{ 0x00, 0x00 },{ 0x00, 0x00 },{ 0x00, 0x00 },{ 0x00, 0x01 },{ 0x00, 0x00 },{ 0x00, 0x0d },{ 0x00, 0x08 },{ 0x00, 0x06 },{ 0x00, 0x08 } }, { 0x00, 0x00, 0x00, 0x00,{ 0x00, 0x00 },{ 0x00, 0x00 },{ 0x00, 0x00 },{ 0x00, 0x00 },{ 0x00, 0x01 },{ 0x00, 0x00 },{ 0x00, 0x0d },{ 0x00, 0x08 },{ 0x00, 0x04 },{ 0x00, 0x08 } },
{ 0x00, 0x00, 0x00, 0x00,{ 0x00, 0x00 },{ 0x00, 0x00 },{ 0x00, 0x00 },{ 0x00, 0x00 },{ 0x00, 0x01 },{ 0x00, 0x00 },{ 0x00, 0x0a },{ 0x00, 0x0a },{ 0x00, 0x05 },{ 0x00, 0x05 } } { 0x00, 0x00, 0x00, 0x00,{ 0x00, 0x00 },{ 0x00, 0x00 },{ 0x00, 0x00 },{ 0x00, 0x00 },{ 0x00, 0x01 },{ 0x00, 0x00 },{ 0x00, 0x0a },{ 0x00, 0x0a },{ 0x00, 0x05 },{ 0x00, 0x05 } }
}; };
@ -1018,6 +1018,9 @@ static void OPLL_Operator(opll_t *chip) {
} }
} }
if (!(chip->rm_enable & 0x80))
routput = 0;
chip->ch_out = ismod1 ? routput : (output>>3); chip->ch_out = ismod1 ? routput : (output>>3);
if (!ismod1) { if (!ismod1) {

View file

@ -30,6 +30,9 @@
// hack I know // hack I know
#include "../../../src/utfutils.h" #include "../../../src/utfutils.h"
// hack 2...
#include "../../../src/ta-log.h"
class NFDWinEvents: public IFileDialogEvents { class NFDWinEvents: public IFileDialogEvents {
nfdselcallback_t selCallback; nfdselcallback_t selCallback;
size_t refCount; size_t refCount;
@ -38,21 +41,21 @@ class NFDWinEvents: public IFileDialogEvents {
} }
public: public:
IFACEMETHODIMP QueryInterface(REFIID riid, void** ppv) { IFACEMETHODIMP QueryInterface(REFIID riid, void** ppv) {
printf("QueryInterface called DAMN IT\n"); logV("%p: QueryInterface called DAMN IT",(const void*)this);
*ppv=NULL; *ppv=NULL;
return E_NOTIMPL; return E_NOTIMPL;
} }
IFACEMETHODIMP_(ULONG) AddRef() { IFACEMETHODIMP_(ULONG) AddRef() {
printf("AddRef() called\n"); logV("%p: AddRef() called",(const void*)this);
return InterlockedIncrement(&refCount); return InterlockedIncrement(&refCount);
} }
IFACEMETHODIMP_(ULONG) Release() { IFACEMETHODIMP_(ULONG) Release() {
printf("Release() called\n"); logV("%p: Release() called",(const void*)this);
LONG ret=InterlockedDecrement(&refCount); LONG ret=InterlockedDecrement(&refCount);
if (ret==0) { if (ret==0) {
printf("Destroying the final object.\n"); logV("%p: Destroying the final object.",(const void*)this);
delete this; delete this;
} }
return ret; return ret;
@ -67,30 +70,40 @@ class NFDWinEvents: public IFileDialogEvents {
IFACEMETHODIMP OnSelectionChange(IFileDialog* dialog) { IFACEMETHODIMP OnSelectionChange(IFileDialog* dialog) {
// Get the file name // Get the file name
logV("%p: OnSelectionChange() called",(const void*)this);
::IShellItem *shellItem(NULL); ::IShellItem *shellItem(NULL);
logV("%p: GetCurrentSelection",(const void*)this);
HRESULT result = dialog->GetCurrentSelection(&shellItem); HRESULT result = dialog->GetCurrentSelection(&shellItem);
if ( !SUCCEEDED(result) ) if ( !SUCCEEDED(result) )
{ {
printf("failure!\n"); logV("%p: failure!",(const void*)this);
return S_OK; return S_OK;
} }
wchar_t *filePath(NULL); wchar_t *filePath(NULL);
result = shellItem->GetDisplayName(::SIGDN_FILESYSPATH, &filePath); result = shellItem->GetDisplayName(::SIGDN_FILESYSPATH, &filePath);
if ( !SUCCEEDED(result) ) if ( !SUCCEEDED(result) )
{ {
printf("GDN failure!\n"); logV("%p: GDN failure!",(const void*)this);
shellItem->Release(); shellItem->Release();
return S_OK; return S_OK;
} }
std::string utf8FilePath=utf16To8(filePath); std::string utf8FilePath=utf16To8(filePath);
if (selCallback!=NULL) selCallback(utf8FilePath.c_str()); if (selCallback!=NULL) {
printf("I got you for a value of %s\n",utf8FilePath.c_str()); logV("%p: calling back.",(const void*)this);
selCallback(utf8FilePath.c_str());
logV("%p: end of callback",(const void*)this);
} else {
logV("%p: no callback.",(const void*)this);
}
logV("%p: I got you for a value of %s",(const void*)this,utf8FilePath.c_str());
shellItem->Release(); shellItem->Release();
logV("%p: shellItem->Release()",(const void*)this);
return S_OK; return S_OK;
} }
NFDWinEvents(nfdselcallback_t callback): NFDWinEvents(nfdselcallback_t callback):
selCallback(callback), selCallback(callback),
refCount(1) { refCount(1) {
logV("%p: CONSTRUCT!",(const void*)this);
} }
}; };

View file

@ -8,11 +8,11 @@
#include "k005289.hpp" #include "k005289.hpp"
void k005289_core::tick() void k005289_core::tick(const unsigned int cycles)
{ {
for (timer_t &elem : m_timer) for (timer_t &elem : m_timer)
{ {
elem.tick(); elem.tick(cycles);
} }
} }
@ -24,12 +24,12 @@ void k005289_core::reset()
} }
} }
void k005289_core::timer_t::tick() void k005289_core::timer_t::tick(const unsigned int cycles) {
{ m_counter-=cycles;
if (bitfield(++m_counter, 0, 12) == 0) while (m_counter < 0)
{ {
m_addr = bitfield(m_addr + 1, 0, 5); m_addr = bitfield(m_addr + 1, 0, 5);
m_counter = m_freq; m_counter += 0x1000-(m_freq&0xfff);
} }
} }

View file

@ -32,7 +32,7 @@ class k005289_core : public vgsound_emu_core
// internal state // internal state
void reset(); void reset();
void tick(); void tick(const unsigned int cycles=1);
// accessors // accessors
// Replace current frequency to lastest loaded pitch // Replace current frequency to lastest loaded pitch
@ -63,7 +63,7 @@ class k005289_core : public vgsound_emu_core
// internal state // internal state
void reset(); void reset();
void tick(); void tick(const unsigned int cycles);
// accessors // accessors
// TG1/2 pin // TG1/2 pin

View file

@ -1,5 +1,9 @@
# Konami SCC # Konami SCC
## modified
the emulation core has been modified for optimization.
## Summary ## Summary
- 5 voice wavetable - 5 voice wavetable

View file

@ -10,17 +10,17 @@
#include "scc.hpp" #include "scc.hpp"
// shared SCC features // shared SCC features
void scc_core::tick() void scc_core::tick(const int cycles)
{ {
m_out = 0; m_out = 0;
for (auto &elem : m_voice) for (auto &elem : m_voice)
{ {
elem.tick(); elem.tick(cycles);
m_out += elem.out(); m_out += elem.out();
} }
} }
void scc_core::voice_t::tick() void scc_core::voice_t::tick(const int cycles)
{ {
if (m_pitch >= 9) // or voice is halted if (m_pitch >= 9) // or voice is halted
{ {
@ -28,23 +28,27 @@ void scc_core::voice_t::tick()
const u16 temp = m_counter; const u16 temp = m_counter;
if (m_host.m_test.freq_4bit()) // 4 bit frequency mode if (m_host.m_test.freq_4bit()) // 4 bit frequency mode
{ {
m_counter = (m_counter & ~0x0ff) | (bitfield(bitfield(m_counter, 0, 8) - 1, 0, 8) << 0); m_counter = (m_counter & ~0x0ff) | (bitfield(bitfield(m_counter, 0, 8) - cycles, 0, 8) << 0);
m_counter = (m_counter & ~0xf00) | (bitfield(bitfield(m_counter, 8, 4) - 1, 0, 4) << 8); m_counter = (m_counter & ~0xf00) | (bitfield(bitfield(m_counter, 8, 4) - cycles, 0, 4) << 8);
} }
else else
{ {
m_counter = bitfield(m_counter - 1, 0, 12); m_counter = bitfield(m_counter - cycles, 0, 12);
} }
// handle counter carry // handle counter carry
const bool carry = m_host.m_test.freq_8bit() const bool carry = (temp<cycles) || (m_host.m_test.freq_8bit()
? (bitfield(temp, 0, 8) == 0) ? (bitfield(temp, 0, 8) == 0)
: (m_host.m_test.freq_4bit() ? (bitfield(temp, 8, 4) == 0) : (m_host.m_test.freq_4bit() ? (bitfield(temp, 8, 4) == 0)
: (bitfield(temp, 0, 12) == 0)); : (bitfield(temp, 0, 12) == 0)));
if (carry) if (carry)
{ {
m_addr = bitfield(m_addr + 1, 0, 5); m_addr = bitfield(m_addr + 1, 0, 5);
m_counter = m_pitch; m_counter = m_pitch - ((temp<cycles)?(cycles-temp-1):0);
while (m_counter>m_pitch) {
m_addr = bitfield(m_addr + 1, 0, 5);
m_counter+=m_pitch-1;
}
} }
} }
// get output // get output

View file

@ -41,7 +41,7 @@ class scc_core : public vgsound_emu_core
// internal state // internal state
void reset(); void reset();
void tick(); void tick(const int cycles=1);
// accessors // accessors
inline void reset_addr() { m_addr = 0; } inline void reset_addr() { m_addr = 0; }
@ -151,7 +151,7 @@ class scc_core : public vgsound_emu_core
// internal state // internal state
virtual void reset(); virtual void reset();
void tick(); void tick(const int cycles=1);
// getters // getters
inline s32 out() { return m_out; } // output to DA0...DA10 pin inline s32 out() { return m_out; } // output to DA0...DA10 pin

Binary file not shown.

View file

@ -57,9 +57,6 @@ however, effects are continuous, which means you only need to type it once and t
- `EDxx`: delay note by `xx` ticks. - `EDxx`: delay note by `xx` ticks.
- `EExx`: send external command. - `EExx`: send external command.
- this effect is currently incomplete. - this effect is currently incomplete.
- `EFxx`: add or subtract global pitch.
- this effect is rather weird. use with caution.
- `80` is center.
- `F0xx`: change song Hz by BPM value. - `F0xx`: change song Hz by BPM value.
- `F1xx`: single tick slide up. - `F1xx`: single tick slide up.
- `F2xx`: single tick slide down. - `F2xx`: single tick slide down.
@ -135,7 +132,7 @@ ex | FM | OPM | OPZ | OPLL | AY-3-8910 | AY8930 | Lynx
W | | LFO Shape | LFO Shape | Patch | Waveform | Waveform | | Waveform | Waveform | Waveform | Waveform | Waveform | Waveform | | | | Waveform | | W | | LFO Shape | LFO Shape | Patch | Waveform | Waveform | | Waveform | Waveform | Waveform | Waveform | Waveform | Waveform | | | | Waveform | |
1 | | AMD | AMD | | | Duty | | FilterMode | Envelope | EnvMode | WaveLen | Mod Depth | Cutoff | Filter K1 | ClockDiv | EchoFeedback | Special | GroupAtk | 1 | | AMD | AMD | | | Duty | | FilterMode | Envelope | EnvMode | WaveLen | Mod Depth | Cutoff | Filter K1 | ClockDiv | EchoFeedback | Special | GroupAtk |
2 | | PMD | PMD | | Envelope | Envelope | | Resonance | | Envelope | WaveUpdate | Mod Speed | Resonance | Filter K2 | | Echo Length | Gain | GroupDec | 2 | | PMD | PMD | | Envelope | Envelope | | Resonance | | Envelope | WaveUpdate | Mod Speed | Resonance | Filter K2 | | Echo Length | Gain | GroupDec |
3 | | LFO Speed | LFO Speed | | AutoEnvNum | AutoEnvNum | | Special | | AutoEnvNum | WaveLoad W | | Control | Env Count | | | | Noise | 3 | LFOSpd | LFO Speed | LFO Speed | | AutoEnvNum | AutoEnvNum | | Special | | AutoEnvNum | WaveLoad W | | Control | Env Count | | | | Noise |
A | ALG | ALG | ALG | | AutoEnvDen | AutoEnvDen | | | | AutoEnvDen | WaveLoad P | | | Control | | | | | A | ALG | ALG | ALG | | AutoEnvDen | AutoEnvDen | | | | AutoEnvDen | WaveLoad P | | | Control | | | | |
B | FB | FB | FB | | | Noise AND | | | | | WaveLoad L | | | | | | | | B | FB | FB | FB | | | Noise AND | | | | | WaveLoad L | | | | | | | |
C | FMS | FMS | FMS | | | Noise OR | | | | | WaveLoad T | | | | | | | | C | FMS | FMS | FMS | | | Noise OR | | | | | WaveLoad T | | | | | | | |

View file

@ -45,6 +45,16 @@ no plans have been made for TX81Z MIDI passthrough, because:
- `1Bxx`: set attack of operator 2. - `1Bxx`: set attack of operator 2.
- `1Cxx`: set attack of operator 3. - `1Cxx`: set attack of operator 3.
- `1Dxx`: set attack of operator 4. - `1Dxx`: set attack of operator 4.
- `1Exx`: set LFO AM depth.
- `1Fxx`: set LFO PM depth.
- `24xx`: set LFO 2 speed.
- `25xx`: set LFO 2 waveform. `xx` may be one of the following:
- `00`: saw
- `01`: square
- `02`: triangle
- `03`: noise
- `26xx`: set LFO 2 AM depth.
- `27xx`: set LFO 2 PM depth.
- `28xy`: set reverb of operator. - `28xy`: set reverb of operator.
- `x` is the operator (1-4). a value of 0 means "all operators". - `x` is the operator (1-4). a value of 0 means "all operators".
- `y` is the value. - `y` is the value.

View file

@ -32,6 +32,9 @@ these fields are 0 in format versions prior to 100 (0.6pre1).
the format versions are: the format versions are:
- 139: Furnace dev139
- 138: Furnace dev138
- 137: Furnace dev137
- 136: Furnace dev136 - 136: Furnace dev136
- 135: Furnace dev135 - 135: Furnace dev135
- 134: Furnace dev134 - 134: Furnace dev134
@ -398,6 +401,17 @@ size | description
4?? | patchbay 4?? | patchbay
| - see next section for more details. | - see next section for more details.
1 | automatic patchbay (>=136) 1 | automatic patchbay (>=136)
--- | **a couple more compat flags** (>=138)
1 | broken portamento during legato
7 | reserved
--- | **speed pattern of first song** (>=139)
1 | length of speed pattern (fail if this is lower than 0 or higher than 16)
16 | speed pattern (this overrides speed 1 and speed 2 settings)
--- | **groove list** (>=139)
1 | number of entries
??? | groove entries. the format is:
| - 1 byte: length of groove
| - 16 bytes: groove pattern
``` ```
# patchbay # patchbay
@ -467,6 +481,9 @@ size | description
| - a list of channelCount C strings | - a list of channelCount C strings
S?? | channel short names S?? | channel short names
| - same as above | - same as above
--- | **speed pattern** (>=139)
1 | length of speed pattern (fail if this is lower than 0 or higher than 16)
16 | speed pattern (this overrides speed 1 and speed 2 settings)
``` ```
# chip flags # chip flags

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -58,7 +58,7 @@ bool TAMidiInRtMidi::gather() {
if (m.type!=TA_MIDI_SYSEX && msg.size()>1) { if (m.type!=TA_MIDI_SYSEX && msg.size()>1) {
memcpy(m.data,msg.data()+1,MIN(msg.size()-1,7)); memcpy(m.data,msg.data()+1,MIN(msg.size()-1,7));
} else if (m.type==TA_MIDI_SYSEX) { } else if (m.type==TA_MIDI_SYSEX) {
m.sysExData.reset(new unsigned char[msg.size()]); m.sysExData=std::shared_ptr<unsigned char>(new unsigned char[msg.size()],std::default_delete<unsigned char[]>());
m.sysExLen=msg.size(); m.sysExLen=msg.size();
logD("got a SysEx of length %ld!",msg.size()); logD("got a SysEx of length %ld!",msg.size());
memcpy(m.sysExData.get(),msg.data(),msg.size()); memcpy(m.sysExData.get(),msg.data(),msg.size());

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -24,6 +24,7 @@
#define DIV_MAX_CHIPS 32 #define DIV_MAX_CHIPS 32
#define DIV_MAX_CHANS 128 #define DIV_MAX_CHANS 128
#define DIV_MAX_PATTERNS 256 #define DIV_MAX_PATTERNS 256
#define DIV_MAX_CHIP_DEFS 256
// in-pattern // in-pattern
#define DIV_MAX_ROWS 256 #define DIV_MAX_ROWS 256

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -103,9 +103,8 @@ enum DivDispatchCmds {
DIV_CMD_FM_AM_DEPTH, // (depth) DIV_CMD_FM_AM_DEPTH, // (depth)
DIV_CMD_FM_PM_DEPTH, // (depth) DIV_CMD_FM_PM_DEPTH, // (depth)
DIV_CMD_GENESIS_LFO, // unused? DIV_CMD_FM_LFO2, // (speed)
DIV_CMD_FM_LFO2_WAVE, // (waveform)
DIV_CMD_ARCADE_LFO, // unused?
DIV_CMD_STD_NOISE_FREQ, // (freq) DIV_CMD_STD_NOISE_FREQ, // (freq)
DIV_CMD_STD_NOISE_MODE, // (mode) DIV_CMD_STD_NOISE_MODE, // (mode)
@ -215,6 +214,9 @@ enum DivDispatchCmds {
DIV_CMD_SURROUND_PANNING, // (out, val) DIV_CMD_SURROUND_PANNING, // (out, val)
DIV_CMD_FM_AM2_DEPTH, // (depth)
DIV_CMD_FM_PM2_DEPTH, // (depth)
DIV_ALWAYS_SET_VOLUME, // () -> alwaysSetVol DIV_ALWAYS_SET_VOLUME, // () -> alwaysSetVol
DIV_CMD_MAX DIV_CMD_MAX

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -60,7 +60,7 @@ const char* DivEngine::getEffectDesc(unsigned char effect, int chan, bool notNul
case 0x08: case 0x08:
return "08xy: Set panning (x: left; y: right)"; return "08xy: Set panning (x: left; y: right)";
case 0x09: case 0x09:
return "09xx: Set speed 1"; return "09xx: Set groove pattern (speed 1 if no grooves exist)";
case 0x0a: case 0x0a:
return "0Axy: Volume slide (0y: down; x0: up)"; return "0Axy: Volume slide (0y: down; x0: up)";
case 0x0b: case 0x0b:
@ -70,7 +70,7 @@ const char* DivEngine::getEffectDesc(unsigned char effect, int chan, bool notNul
case 0x0d: case 0x0d:
return "0Dxx: Jump to next pattern"; return "0Dxx: Jump to next pattern";
case 0x0f: case 0x0f:
return "0Fxx: Set speed 2"; return "0Fxx: Set speed (speed 2 if no grooves exist)";
case 0x80: case 0x80:
return "80xx: Set panning (00: left; 80: center; FF: right)"; return "80xx: Set panning (00: left; 80: center; FF: right)";
case 0x81: case 0x81:
@ -110,8 +110,6 @@ const char* DivEngine::getEffectDesc(unsigned char effect, int chan, bool notNul
return "EDxx: Note delay"; return "EDxx: Note delay";
case 0xee: case 0xee:
return "EExx: Send external command"; return "EExx: Send external command";
case 0xef:
return "EFxx: Set global tuning (quirky!)";
case 0xf0: case 0xf0:
return "F0xx: Set tick rate (bpm)"; return "F0xx: Set tick rate (bpm)";
case 0xf1: case 0xf1:
@ -1961,14 +1959,12 @@ String DivEngine::getPlaybackDebugInfo() {
"cmdsPerSecond: %d\n" "cmdsPerSecond: %d\n"
"globalPitch: %d\n" "globalPitch: %d\n"
"extValue: %d\n" "extValue: %d\n"
"speed1: %d\n"
"speed2: %d\n"
"tempoAccum: %d\n" "tempoAccum: %d\n"
"totalProcessed: %d\n" "totalProcessed: %d\n"
"bufferPos: %d\n", "bufferPos: %d\n",
curOrder,prevOrder,curRow,prevRow,ticks,subticks,totalLoops,lastLoopPos,nextSpeed,divider,cycles,clockDrift, curOrder,prevOrder,curRow,prevRow,ticks,subticks,totalLoops,lastLoopPos,nextSpeed,divider,cycles,clockDrift,
changeOrd,changePos,totalSeconds,totalTicks,totalTicksR,totalCmds,lastCmds,cmdsPerSecond,globalPitch, changeOrd,changePos,totalSeconds,totalTicks,totalTicksR,totalCmds,lastCmds,cmdsPerSecond,globalPitch,
(int)extValue,(int)speed1,(int)speed2,(int)tempoAccum,(int)totalProcessed,(int)bufferPos (int)extValue,(int)tempoAccum,(int)totalProcessed,(int)bufferPos
); );
} }
@ -2093,7 +2089,8 @@ void DivEngine::playSub(bool preserveDrift, int goalRow) {
lastLoopPos=-1; lastLoopPos=-1;
} }
endOfSong=false; endOfSong=false;
speedAB=false; // whaaaaa?
curSpeed=0;
playing=true; playing=true;
skipping=true; skipping=true;
memset(walked,0,8192); memset(walked,0,8192);
@ -2441,15 +2438,14 @@ void DivEngine::reset() {
} }
extValue=0; extValue=0;
extValuePresent=0; extValuePresent=0;
speed1=curSubSong->speed1; speeds=curSubSong->speeds;
speed2=curSubSong->speed2;
firstTick=false; firstTick=false;
shallStop=false; shallStop=false;
shallStopSched=false; shallStopSched=false;
pendingMetroTick=0; pendingMetroTick=0;
elapsedBars=0; elapsedBars=0;
elapsedBeats=0; elapsedBeats=0;
nextSpeed=speed1; nextSpeed=speeds.val[0];
divider=60; divider=60;
if (curSubSong->customTempo) { if (curSubSong->customTempo) {
divider=curSubSong->hz; divider=curSubSong->hz;
@ -2649,12 +2645,8 @@ size_t DivEngine::getCurrentSubSong() {
return curSubSongIndex; return curSubSongIndex;
} }
unsigned char DivEngine::getSpeed1() { const DivGroovePattern& DivEngine::getSpeeds() {
return speed1; return speeds;
}
unsigned char DivEngine::getSpeed2() {
return speed2;
} }
float DivEngine::getHz() { float DivEngine::getHz() {
@ -4236,7 +4228,7 @@ void DivEngine::quitDispatch() {
clockDrift=0; clockDrift=0;
chans=0; chans=0;
playing=false; playing=false;
speedAB=false; curSpeed=0;
endOfSong=false; endOfSong=false;
ticks=0; ticks=0;
tempoAccum=0; tempoAccum=0;
@ -4472,6 +4464,9 @@ bool DivEngine::init() {
for (int i=0; i<64; i++) { for (int i=0; i<64; i++) {
vibTable[i]=127*sin(((double)i/64.0)*(2*M_PI)); vibTable[i]=127*sin(((double)i/64.0)*(2*M_PI));
} }
for (int i=0; i<128; i++) {
tremTable[i]=255*0.5*(1.0-cos(((double)i/128.0)*(2*M_PI)));
}
for (int i=0; i<4096; i++) { for (int i=0; i<4096; i++) {
reversePitchTable[i]=round(1024.0*pow(2.0,(2048.0-(double)i)/(12.0*128.0))); reversePitchTable[i]=round(1024.0*pow(2.0,(2048.0-(double)i)/(12.0*128.0)));
pitchTable[i]=round(1024.0*pow(2.0,((double)i-2048.0)/(12.0*128.0))); pitchTable[i]=round(1024.0*pow(2.0,((double)i-2048.0)/(12.0*128.0)));

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -47,8 +47,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 "dev136" #define DIV_VERSION "dev139"
#define DIV_ENGINE_VERSION 136 #define DIV_ENGINE_VERSION 139
// for imports // for imports
#define DIV_VERSION_MOD 0xff01 #define DIV_VERSION_MOD 0xff01
#define DIV_VERSION_FC 0xff02 #define DIV_VERSION_FC 0xff02
@ -337,7 +337,6 @@ class DivEngine {
bool playing; bool playing;
bool freelance; bool freelance;
bool shallStop, shallStopSched; bool shallStop, shallStopSched;
bool speedAB;
bool endOfSong; bool endOfSong;
bool consoleMode; bool consoleMode;
bool extValuePresent; bool extValuePresent;
@ -359,7 +358,7 @@ class DivEngine {
bool midiOutClock; bool midiOutClock;
int midiOutMode; int midiOutMode;
int softLockCount; int softLockCount;
int subticks, ticks, curRow, curOrder, prevRow, prevOrder, remainingLoops, totalLoops, lastLoopPos, exportLoopCount, nextSpeed, elapsedBars, elapsedBeats; int subticks, ticks, curRow, curOrder, prevRow, prevOrder, remainingLoops, totalLoops, lastLoopPos, exportLoopCount, nextSpeed, elapsedBars, elapsedBeats, curSpeed;
size_t curSubSongIndex; size_t curSubSongIndex;
size_t bufferPos; size_t bufferPos;
double divider; double divider;
@ -368,7 +367,7 @@ class DivEngine {
int stepPlay; int stepPlay;
int changeOrd, changePos, totalSeconds, totalTicks, totalTicksR, totalCmds, lastCmds, cmdsPerSecond, globalPitch; int changeOrd, changePos, totalSeconds, totalTicks, totalTicksR, totalCmds, lastCmds, cmdsPerSecond, globalPitch;
unsigned char extValue, pendingMetroTick; unsigned char extValue, pendingMetroTick;
unsigned char speed1, speed2; DivGroovePattern speeds;
short tempoAccum; short tempoAccum;
DivStatusView view; DivStatusView view;
DivHaltPositions haltOn; DivHaltPositions haltOn;
@ -391,9 +390,9 @@ class DivEngine {
std::vector<String> midiOuts; std::vector<String> midiOuts;
std::vector<DivCommand> cmdStream; std::vector<DivCommand> cmdStream;
std::vector<DivInstrumentType> possibleInsTypes; std::vector<DivInstrumentType> possibleInsTypes;
static DivSysDef* sysDefs[256]; static DivSysDef* sysDefs[DIV_MAX_CHIP_DEFS];
static DivSystem sysFileMapFur[256]; static DivSystem sysFileMapFur[DIV_MAX_CHIP_DEFS];
static DivSystem sysFileMapDMF[256]; static DivSystem sysFileMapDMF[DIV_MAX_CHIP_DEFS];
struct SamplePreview { struct SamplePreview {
double rate; double rate;
@ -413,6 +412,7 @@ class DivEngine {
} sPreview; } sPreview;
short vibTable[64]; short vibTable[64];
short tremTable[128];
int reversePitchTable[4096]; int reversePitchTable[4096];
int pitchTable[4096]; int pitchTable[4096];
char c163NameCS[1024]; char c163NameCS[1024];
@ -442,7 +442,7 @@ class DivEngine {
void processRow(int i, bool afterDelay); void processRow(int i, bool afterDelay);
void nextOrder(); void nextOrder();
void nextRow(); void nextRow();
void performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write, int streamOff, double* loopTimer, double* loopFreq, int* loopSample, bool* sampleDir, bool isSecond, bool directStream); void performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write, int streamOff, double* loopTimer, double* loopFreq, int* loopSample, bool* sampleDir, bool isSecond, int* pendingFreq, int* playingSample, bool directStream);
// returns true if end of song. // returns true if end of song.
bool nextTick(bool noAccum=false, bool inhibitLowLat=false); bool nextTick(bool noAccum=false, bool inhibitLowLat=false);
bool perSystemEffect(int ch, unsigned char effect, unsigned char effectVal); bool perSystemEffect(int ch, unsigned char effect, unsigned char effectVal);
@ -729,11 +729,8 @@ class DivEngine {
// get current subsong // get current subsong
size_t getCurrentSubSong(); size_t getCurrentSubSong();
// get speed 1 // get speeds
unsigned char getSpeed1(); const DivGroovePattern& getSpeeds();
// get speed 2
unsigned char getSpeed2();
// get Hz // get Hz
float getHz(); float getHz();
@ -1064,7 +1061,6 @@ class DivEngine {
freelance(false), freelance(false),
shallStop(false), shallStop(false),
shallStopSched(false), shallStopSched(false),
speedAB(false),
endOfSong(false), endOfSong(false),
consoleMode(false), consoleMode(false),
extValuePresent(false), extValuePresent(false),
@ -1098,6 +1094,7 @@ class DivEngine {
nextSpeed(3), nextSpeed(3),
elapsedBars(0), elapsedBars(0),
elapsedBeats(0), elapsedBeats(0),
curSpeed(0),
curSubSongIndex(0), curSubSongIndex(0),
bufferPos(0), bufferPos(0),
divider(60), divider(60),
@ -1115,8 +1112,6 @@ class DivEngine {
globalPitch(0), globalPitch(0),
extValue(0), extValue(0),
pendingMetroTick(0), pendingMetroTick(0),
speed1(3),
speed2(3),
tempoAccum(0), tempoAccum(0),
view(DIV_STATUS_NOTHING), view(DIV_STATUS_NOTHING),
haltOn(DIV_HALT_NONE), haltOn(DIV_HALT_NONE),
@ -1158,13 +1153,14 @@ class DivEngine {
memset(dispatchOfChan,0,DIV_MAX_CHANS*sizeof(int)); memset(dispatchOfChan,0,DIV_MAX_CHANS*sizeof(int));
memset(sysOfChan,0,DIV_MAX_CHANS*sizeof(int)); memset(sysOfChan,0,DIV_MAX_CHANS*sizeof(int));
memset(vibTable,0,64*sizeof(short)); memset(vibTable,0,64*sizeof(short));
memset(tremTable,0,128*sizeof(short));
memset(reversePitchTable,0,4096*sizeof(int)); memset(reversePitchTable,0,4096*sizeof(int));
memset(pitchTable,0,4096*sizeof(int)); memset(pitchTable,0,4096*sizeof(int));
memset(sysDefs,0,256*sizeof(void*)); memset(sysDefs,0,DIV_MAX_CHIP_DEFS*sizeof(void*));
memset(walked,0,8192); memset(walked,0,8192);
memset(oscBuf,0,DIV_MAX_OUTPUTS*(sizeof(float*))); memset(oscBuf,0,DIV_MAX_OUTPUTS*(sizeof(float*)));
for (int i=0; i<256; i++) { for (int i=0; i<DIV_MAX_CHIP_DEFS; i++) {
sysFileMapFur[i]=DIV_SYSTEM_NULL; sysFileMapFur[i]=DIV_SYSTEM_NULL;
sysFileMapDMF[i]=DIV_SYSTEM_NULL; sysFileMapDMF[i]=DIV_SYSTEM_NULL;
} }

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -83,7 +83,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
} }
ds.version=(unsigned char)reader.readC(); ds.version=(unsigned char)reader.readC();
logI("module version %d (0x%.2x)",ds.version,ds.version); logI("module version %d (0x%.2x)",ds.version,ds.version);
if (ds.version>0x1a) { if (ds.version>0x1b) {
logE("this version is not supported by Furnace yet!"); logE("this version is not supported by Furnace yet!");
lastError="this version is not supported by Furnace yet"; lastError="this version is not supported by Furnace yet";
delete[] file; delete[] file;
@ -219,14 +219,15 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
} }
ds.subsong[0]->timeBase=reader.readC(); ds.subsong[0]->timeBase=reader.readC();
ds.subsong[0]->speed1=reader.readC(); ds.subsong[0]->speeds.len=2;
ds.subsong[0]->speeds.val[0]=reader.readC();
if (ds.version>0x07) { if (ds.version>0x07) {
ds.subsong[0]->speed2=reader.readC(); ds.subsong[0]->speeds.val[1]=reader.readC();
ds.subsong[0]->pal=reader.readC(); ds.subsong[0]->pal=reader.readC();
ds.subsong[0]->hz=(ds.subsong[0]->pal)?60:50; ds.subsong[0]->hz=(ds.subsong[0]->pal)?60:50;
ds.subsong[0]->customTempo=reader.readC(); ds.subsong[0]->customTempo=reader.readC();
} else { } else {
ds.subsong[0]->speed2=ds.subsong[0]->speed1; ds.subsong[0]->speeds.len=1;
} }
if (ds.version>0x0a) { if (ds.version>0x0a) {
String hz=reader.readString(3); String hz=reader.readString(3);
@ -827,6 +828,8 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
for (int i=0; i<ds.sampleLen; i++) { for (int i=0; i<ds.sampleLen; i++) {
DivSample* sample=new DivSample; DivSample* sample=new DivSample;
int length=reader.readI(); int length=reader.readI();
int cutStart=0;
int cutEnd=length;
int pitch=5; int pitch=5;
int vol=50; int vol=50;
short* data; short* data;
@ -866,6 +869,29 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
sample->depth=DIV_SAMPLE_DEPTH_YMZ_ADPCM; sample->depth=DIV_SAMPLE_DEPTH_YMZ_ADPCM;
} }
} }
if (ds.version>=0x1a) {
// what the hell man...
cutStart=reader.readI();
cutEnd=reader.readI();
if (cutStart<0 || cutStart>length) {
logE("cutStart is out of range! (%d)",cutStart);
lastError="file is corrupt or unreadable at samples";
delete[] file;
return false;
}
if (cutEnd<0 || cutEnd>length) {
logE("cutEnd is out of range! (%d)",cutEnd);
lastError="file is corrupt or unreadable at samples";
delete[] file;
return false;
}
if (cutEnd<cutStart) {
logE("cutEnd %d is before cutStart %d. what's going on?",cutEnd,cutStart);
lastError="file is corrupt or unreadable at samples";
delete[] file;
return false;
}
}
if (length>0) { if (length>0) {
if (ds.version>0x08) { if (ds.version>0x08) {
if (ds.version<0x0b) { if (ds.version<0x0b) {
@ -877,6 +903,19 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
reader.read(data,length*2); reader.read(data,length*2);
} }
if (ds.version>0x1a) {
if (cutStart!=0 || cutEnd!=length) {
// cut data
short* newData=new short[cutEnd-cutStart];
memcpy(newData,&data[cutStart],(cutEnd-cutStart)*sizeof(short));
delete[] data;
data=newData;
length=cutEnd-cutStart;
cutStart=0;
cutEnd=length;
}
}
#ifdef TA_BIG_ENDIAN #ifdef TA_BIG_ENDIAN
// convert to big-endian // convert to big-endian
for (int pos=0; pos<length; pos++) { for (int pos=0; pos<length; pos++) {
@ -1716,6 +1755,9 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
if (ds.version<130) { if (ds.version<130) {
ds.oldArpStrategy=true; ds.oldArpStrategy=true;
} }
if (ds.version<138) {
ds.brokenPortaLegato=true;
}
ds.isDMF=false; ds.isDMF=false;
reader.readS(); // reserved reader.readS(); // reserved
@ -1739,8 +1781,9 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
reader.readI(); reader.readI();
subSong->timeBase=reader.readC(); subSong->timeBase=reader.readC();
subSong->speed1=reader.readC(); subSong->speeds.len=2;
subSong->speed2=reader.readC(); subSong->speeds.val[0]=reader.readC();
subSong->speeds.val[1]=reader.readC();
subSong->arpLen=reader.readC(); subSong->arpLen=reader.readC();
subSong->hz=reader.readF(); subSong->hz=reader.readF();
subSong->pal=(subSong->hz>=53); subSong->pal=(subSong->hz>=53);
@ -2221,6 +2264,32 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
if (ds.version>=136) song.patchbayAuto=reader.readC(); if (ds.version>=136) song.patchbayAuto=reader.readC();
if (ds.version>=138) {
ds.brokenPortaLegato=reader.readC();
for (int i=0; i<7; i++) {
reader.readC();
}
}
if (ds.version>=139) {
subSong->speeds.len=reader.readC();
for (int i=0; i<16; i++) {
subSong->speeds.val[i]=reader.readC();
}
// grooves
unsigned char grooveCount=reader.readC();
for (int i=0; i<grooveCount; i++) {
DivGroovePattern gp;
gp.len=reader.readC();
for (int j=0; j<16; j++) {
gp.val[j]=reader.readC();
}
ds.grooves.push_back(gp);
}
}
// read system flags // read system flags
if (ds.version>=119) { if (ds.version>=119) {
logD("reading chip flags..."); logD("reading chip flags...");
@ -2279,8 +2348,9 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
subSong=ds.subsong[i+1]; subSong=ds.subsong[i+1];
subSong->timeBase=reader.readC(); subSong->timeBase=reader.readC();
subSong->speed1=reader.readC(); subSong->speeds.len=2;
subSong->speed2=reader.readC(); subSong->speeds.val[0]=reader.readC();
subSong->speeds.val[1]=reader.readC();
subSong->arpLen=reader.readC(); subSong->arpLen=reader.readC();
subSong->hz=reader.readF(); subSong->hz=reader.readF();
subSong->pal=(subSong->hz>=53); subSong->pal=(subSong->hz>=53);
@ -2328,6 +2398,13 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
for (int i=0; i<tchans; i++) { for (int i=0; i<tchans; i++) {
subSong->chanShortName[i]=reader.readString(); subSong->chanShortName[i]=reader.readString();
} }
if (ds.version>=139) {
subSong->speeds.len=reader.readC();
for (int i=0; i<16; i++) {
subSong->speeds.val[i]=reader.readC();
}
}
} }
} }
@ -2574,6 +2651,32 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
} }
} }
// new YM2612/SN/X1-010 volumes
if (ds.version<137) {
for (int i=0; i<ds.systemLen; i++) {
switch (ds.system[i]) {
case DIV_SYSTEM_YM2612:
case DIV_SYSTEM_YM2612_EXT:
case DIV_SYSTEM_YM2612_DUALPCM:
case DIV_SYSTEM_YM2612_DUALPCM_EXT:
case DIV_SYSTEM_YM2612_CSM:
ds.systemVol[i]/=2.0;
break;
case DIV_SYSTEM_SMS:
case DIV_SYSTEM_T6W28:
case DIV_SYSTEM_OPLL:
case DIV_SYSTEM_OPLL_DRUMS:
ds.systemVol[i]/=1.5;
break;
case DIV_SYSTEM_X1_010:
ds.systemVol[i]/=4.0;
break;
default:
break;
}
}
}
if (active) quitDispatch(); if (active) quitDispatch();
BUSY_BEGIN_SOFT; BUSY_BEGIN_SOFT;
saveLock.lock(); saveLock.lock();
@ -2920,7 +3023,6 @@ bool DivEngine::loadMod(unsigned char* file, size_t len) {
if (fxVal>0x20 && ds.name!="klisje paa klisje") { if (fxVal>0x20 && ds.name!="klisje paa klisje") {
writeFxCol(0xf0,fxVal); writeFxCol(0xf0,fxVal);
} else { } else {
writeFxCol(0x09,fxVal);
writeFxCol(0x0f,fxVal); writeFxCol(0x0f,fxVal);
} }
break; break;
@ -3399,8 +3501,8 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) {
ds.subsong[0]->pal=true; ds.subsong[0]->pal=true;
ds.subsong[0]->customTempo=true; ds.subsong[0]->customTempo=true;
ds.subsong[0]->pat[3].effectCols=3; ds.subsong[0]->pat[3].effectCols=3;
ds.subsong[0]->speed1=3; ds.subsong[0]->speeds.val[0]=3;
ds.subsong[0]->speed2=3; ds.subsong[0]->speeds.len=1;
int lastIns[4]; int lastIns[4];
int lastNote[4]; int lastNote[4];
@ -3417,10 +3519,8 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) {
ds.subsong[0]->orders.ord[j][i]=i; ds.subsong[0]->orders.ord[j][i]=i;
DivPattern* p=ds.subsong[0]->pat[j].getPattern(i,true); DivPattern* p=ds.subsong[0]->pat[j].getPattern(i,true);
if (j==3 && seq[i].speed) { if (j==3 && seq[i].speed) {
p->data[0][6]=0x09; p->data[0][6]=0x0f;
p->data[0][7]=seq[i].speed; p->data[0][7]=seq[i].speed;
p->data[0][8]=0x0f;
p->data[0][9]=seq[i].speed;
} }
bool ignoreNext=false; bool ignoreNext=false;
@ -4307,8 +4407,9 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) {
w->writeI(0); w->writeI(0);
w->writeC(subSong->timeBase); w->writeC(subSong->timeBase);
w->writeC(subSong->speed1); // these are for compatibility
w->writeC(subSong->speed2); w->writeC(subSong->speeds.val[0]);
w->writeC((subSong->speeds.len>=2)?subSong->speeds.val[1]:subSong->speeds.val[0]);
w->writeC(subSong->arpLen); w->writeC(subSong->arpLen);
w->writeF(subSong->hz); w->writeF(subSong->hz);
w->writeS(subSong->patLen); w->writeS(subSong->patLen);
@ -4489,6 +4590,27 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) {
} }
w->writeC(song.patchbayAuto); w->writeC(song.patchbayAuto);
// even more compat flags
w->writeC(song.brokenPortaLegato);
for (int i=0; i<7; i++) {
w->writeC(0);
}
// speeds of first song
w->writeC(subSong->speeds.len);
for (int i=0; i<16; i++) {
w->writeC(subSong->speeds.val[i]);
}
// groove list
w->writeC((unsigned char)song.grooves.size());
for (const DivGroovePattern& i: song.grooves) {
w->writeC(i.len);
for (int j=0; j<16; j++) {
w->writeC(i.val[j]);
}
}
blockEndSeek=w->tell(); blockEndSeek=w->tell();
w->seek(blockStartSeek,SEEK_SET); w->seek(blockStartSeek,SEEK_SET);
w->writeI(blockEndSeek-blockStartSeek-4); w->writeI(blockEndSeek-blockStartSeek-4);
@ -4503,8 +4625,8 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) {
w->writeI(0); w->writeI(0);
w->writeC(subSong->timeBase); w->writeC(subSong->timeBase);
w->writeC(subSong->speed1); w->writeC(subSong->speeds.val[0]);
w->writeC(subSong->speed2); w->writeC((subSong->speeds.len>=2)?subSong->speeds.val[1]:subSong->speeds.val[0]);
w->writeC(subSong->arpLen); w->writeC(subSong->arpLen);
w->writeF(subSong->hz); w->writeF(subSong->hz);
w->writeS(subSong->patLen); w->writeS(subSong->patLen);
@ -4543,6 +4665,12 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) {
w->writeString(subSong->chanShortName[i],false); w->writeString(subSong->chanShortName[i],false);
} }
// speeds
w->writeC(subSong->speeds.len);
for (int i=0; i<16; i++) {
w->writeC(subSong->speeds.val[i]);
}
blockEndSeek=w->tell(); blockEndSeek=w->tell();
w->seek(blockStartSeek,SEEK_SET); w->seek(blockStartSeek,SEEK_SET);
w->writeI(blockEndSeek-blockStartSeek-4); w->writeI(blockEndSeek-blockStartSeek-4);
@ -4798,8 +4926,8 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) {
w->writeC(curSubSong->hilightB); w->writeC(curSubSong->hilightB);
w->writeC(curSubSong->timeBase); w->writeC(curSubSong->timeBase);
w->writeC(curSubSong->speed1); w->writeC(curSubSong->speeds.val[0]);
w->writeC(curSubSong->speed2); w->writeC((curSubSong->speeds.len>=2)?curSubSong->speeds.val[1]:curSubSong->speeds.val[0]);
w->writeC(curSubSong->pal); w->writeC(curSubSong->pal);
w->writeC(curSubSong->customTempo); w->writeC(curSubSong->customTempo);
char customHz[4]; char customHz[4];
@ -4823,6 +4951,14 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) {
addWarning("only the currently selected subsong will be saved"); addWarning("only the currently selected subsong will be saved");
} }
if (!song.grooves.empty()) {
addWarning("grooves will not be saved");
}
if (curSubSong->speeds.len>2) {
addWarning("only the first two speeds will be effective");
}
if (curSubSong->virtualTempoD!=curSubSong->virtualTempoN) { if (curSubSong->virtualTempoD!=curSubSong->virtualTempoN) {
addWarning(".dmf format does not support virtual tempo"); addWarning(".dmf format does not support virtual tempo");
} }

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -56,7 +56,7 @@ void DivMacroStruct::doMacro(DivInstrumentMacro& source, bool released, bool tic
} }
if (delay>0) { if (delay>0) {
delay--; delay--;
had=false; if (!linger) had=false;
return; return;
} }
if (began && source.delay>0) { if (began && source.delay>0) {

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -18,6 +18,7 @@
*/ */
#include "../dispatch.h" #include "../dispatch.h"
#include "../../ta-log.h"
void DivDispatch::acquire(short** buf, size_t len) { void DivDispatch::acquire(short** buf, size_t len) {
} }
@ -121,7 +122,8 @@ void DivDispatch::notifyWaveChange(int ins) {
} }
void DivDispatch::notifyInsDeletion(void* ins) { void DivDispatch::notifyInsDeletion(void* ins) {
logE("notifyInsDeletion NOT implemented!");
abort();
} }
void DivDispatch::notifyPlaybackStop() { void DivDispatch::notifyPlaybackStop() {

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -319,27 +319,6 @@ void DivPlatformArcade::tick(bool sysTick) {
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].hardReset && chan[i].keyOn) {
for (int j=0; j<4; j++) {
unsigned short baseAddr=chanOffs[i]|opOffs[j];
immWrite(baseAddr+ADDR_SL_RR,0x0f);
immWrite(baseAddr+ADDR_TL,0x7f);
oldWrites[baseAddr+ADDR_SL_RR]=-1;
oldWrites[baseAddr+ADDR_TL]=-1;
}
}
immWrite(0x08,i);
if (chan[i].hardReset && chan[i].keyOn) {
for (int j=0; j<4; j++) {
unsigned short baseAddr=chanOffs[i]|opOffs[j];
for (int k=0; k<9; k++) {
immWrite(baseAddr+ADDR_SL_RR,0x0f);
}
}
}
chan[i].keyOff=false;
}
} }
for (int i=0; i<256; i++) { for (int i=0; i<256; i++) {
@ -349,6 +328,24 @@ void DivPlatformArcade::tick(bool sysTick) {
} }
} }
int hardResetElapsed=0;
bool mustHardReset=false;
for (int i=0; i<8; i++) {
if (chan[i].keyOn || chan[i].keyOff) {
immWrite(0x08,i);
if (chan[i].hardReset && chan[i].keyOn) {
mustHardReset=true;
for (int j=0; j<4; j++) {
unsigned short baseAddr=chanOffs[i]|opOffs[j];
immWrite(baseAddr+ADDR_SL_RR,0x0f);
hardResetElapsed++;
}
}
chan[i].keyOff=false;
}
}
for (int i=0; i<8; i++) { for (int i=0; i<8; i++) {
if (chan[i].freqChanged) { if (chan[i].freqChanged) {
chan[i].freq=chan[i].baseFreq+(chan[i].pitch>>1)-64+chan[i].pitch2; chan[i].freq=chan[i].baseFreq+(chan[i].pitch>>1)-64+chan[i].pitch2;
@ -363,15 +360,38 @@ void DivPlatformArcade::tick(bool sysTick) {
if (chan[i].freq>=(95<<6)) chan[i].freq=(95<<6)-1; if (chan[i].freq>=(95<<6)) chan[i].freq=(95<<6)-1;
immWrite(i+0x28,hScale(chan[i].freq>>6)); immWrite(i+0x28,hScale(chan[i].freq>>6));
immWrite(i+0x30,chan[i].freq<<2); immWrite(i+0x30,chan[i].freq<<2);
hardResetElapsed+=2;
chan[i].freqChanged=false; chan[i].freqChanged=false;
} }
if (chan[i].keyOn || chan[i].opMaskChanged) { if ((chan[i].keyOn || chan[i].opMaskChanged) && !chan[i].hardReset) {
immWrite(0x08,(chan[i].opMask<<3)|i);
hardResetElapsed++;
chan[i].opMaskChanged=false;
chan[i].keyOn=false;
}
}
// hard reset handling
if (mustHardReset) {
for (unsigned int i=hardResetElapsed; i<hardResetCycles; i++) {
immWrite(0x1f,i&0xff);
}
for (int i=0; i<8; i++) {
if ((chan[i].keyOn || chan[i].opMaskChanged) && chan[i].hardReset) {
// restore SL/RR
for (int j=0; j<4; j++) {
unsigned short baseAddr=chanOffs[i]|opOffs[j];
DivInstrumentFM::Operator& op=chan[i].state.op[j];
immWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
}
immWrite(0x08,(chan[i].opMask<<3)|i); immWrite(0x08,(chan[i].opMask<<3)|i);
chan[i].opMaskChanged=false; chan[i].opMaskChanged=false;
chan[i].keyOn=false; chan[i].keyOn=false;
} }
} }
} }
}
void DivPlatformArcade::muteChannel(int ch, bool mute) { void DivPlatformArcade::muteChannel(int ch, bool mute) {
isMuted[ch]=mute; isMuted[ch]=mute;
@ -382,38 +402,29 @@ void DivPlatformArcade::muteChannel(int ch, bool mute) {
} }
} }
int DivPlatformArcade::dispatch(DivCommand c) { void DivPlatformArcade::commitState(int ch, DivInstrument* ins) {
switch (c.cmd) { if (chan[ch].insChanged) {
case DIV_CMD_NOTE_ON: { chan[ch].state=ins->fm;
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM); chan[ch].opMask=
(chan[ch].state.op[0].enable?1:0)|
if (chan[c.chan].insChanged) { (chan[ch].state.op[2].enable?2:0)|
chan[c.chan].state=ins->fm; (chan[ch].state.op[1].enable?4:0)|
chan[c.chan].opMask= (chan[ch].state.op[3].enable?8:0);
(chan[c.chan].state.op[0].enable?1:0)|
(chan[c.chan].state.op[2].enable?2:0)|
(chan[c.chan].state.op[1].enable?4:0)|
(chan[c.chan].state.op[3].enable?8:0);
}
chan[c.chan].macroInit(ins);
if (!chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
} }
for (int i=0; i<4; i++) { for (int i=0; i<4; i++) {
unsigned short baseAddr=chanOffs[c.chan]|opOffs[i]; unsigned short baseAddr=chanOffs[ch]|opOffs[i];
DivInstrumentFM::Operator op=chan[c.chan].state.op[i]; DivInstrumentFM::Operator op=chan[ch].state.op[i];
if (KVS(c.chan,i)) { if (KVS(ch,i)) {
if (!chan[c.chan].active || chan[c.chan].insChanged) { if (!chan[ch].active || chan[ch].insChanged) {
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG_BROKEN(127-op.tl,chan[c.chan].outVol&0x7f,127)); rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG_BROKEN(127-op.tl,chan[ch].outVol&0x7f,127));
} }
} else { } else {
if (chan[c.chan].insChanged) { if (chan[ch].insChanged) {
rWrite(baseAddr+ADDR_TL,op.tl); rWrite(baseAddr+ADDR_TL,op.tl);
} }
} }
if (chan[c.chan].insChanged) { if (chan[ch].insChanged) {
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));
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6)); rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6));
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7)); rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
@ -421,14 +432,27 @@ int DivPlatformArcade::dispatch(DivCommand c) {
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4)); rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
} }
} }
if (chan[c.chan].insChanged) { if (chan[ch].insChanged) {
if (isMuted[c.chan]) { if (isMuted[ch]) {
rWrite(chanOffs[c.chan]+ADDR_LR_FB_ALG,(chan[c.chan].state.alg&7)|(chan[c.chan].state.fb<<3)); rWrite(chanOffs[ch]+ADDR_LR_FB_ALG,(chan[ch].state.alg&7)|(chan[ch].state.fb<<3));
} else { } else {
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[ch]+ADDR_LR_FB_ALG,(chan[ch].state.alg&7)|(chan[ch].state.fb<<3)|((chan[ch].chVolL&1)<<6)|((chan[ch].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[ch]+ADDR_FMS_AMS,((chan[ch].state.fms&7)<<4)|(chan[ch].state.ams&3));
} }
}
int DivPlatformArcade::dispatch(DivCommand c) {
switch (c.cmd) {
case DIV_CMD_NOTE_ON: {
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM);
chan[c.chan].macroInit(ins);
if (!chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
commitState(c.chan,ins);
chan[c.chan].insChanged=false; chan[c.chan].insChanged=false;
if (c.value!=DIV_NOTE_NULL) { if (c.value!=DIV_NOTE_NULL) {
@ -521,6 +545,11 @@ int DivPlatformArcade::dispatch(DivCommand c) {
break; break;
} }
case DIV_CMD_LEGATO: { case DIV_CMD_LEGATO: {
if (chan[c.chan].insChanged) {
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_OPM);
commitState(c.chan,ins);
chan[c.chan].insChanged=false;
}
chan[c.chan].baseFreq=NOTE_LINEAR(c.value); chan[c.chan].baseFreq=NOTE_LINEAR(c.value);
chan[c.chan].freqChanged=true; chan[c.chan].freqChanged=true;
break; break;
@ -800,6 +829,12 @@ void DivPlatformArcade::notifyInsChange(int ins) {
} }
} }
void DivPlatformArcade::notifyInsDeletion(void* ins) {
for (int i=0; i<8; i++) {
chan[i].std.notifyInsDeletion((DivInstrument*)ins);
}
}
void* DivPlatformArcade::getChanState(int ch) { void* DivPlatformArcade::getChanState(int ch) {
return &chan[ch]; return &chan[ch];
} }

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -57,6 +57,7 @@ class DivPlatformArcade: public DivPlatformOPM {
int octave(int freq); int octave(int freq);
int toFreq(int freq); int toFreq(int freq);
void commitState(int ch, DivInstrument* ins);
void acquire_nuked(short** buf, size_t len); void acquire_nuked(short** buf, size_t len);
void acquire_ymfm(short** buf, size_t len); void acquire_ymfm(short** buf, size_t len);
@ -76,6 +77,7 @@ class DivPlatformArcade: public DivPlatformOPM {
void muteChannel(int ch, bool mute); void muteChannel(int ch, bool mute);
DivMacroInt* getChanMacroInt(int ch); DivMacroInt* getChanMacroInt(int ch);
void notifyInsChange(int ins); void notifyInsChange(int ins);
void notifyInsDeletion(void* ins);
void setFlags(const DivConfig& flags); void setFlags(const DivConfig& flags);
int getOutputCount(); int getOutputCount();
void setYMFM(bool use); void setYMFM(bool use);

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -44,7 +44,7 @@ void DivPlatformBubSysWSG::acquire(short** buf, size_t len) {
for (size_t h=0; h<len; h++) { for (size_t h=0; h<len; h++) {
signed int out=0; signed int out=0;
// K005289 part // K005289 part
k005289.tick(); k005289.tick(8);
// Wavetable part // Wavetable part
for (int i=0; i<2; i++) { for (int i=0; i<2; i++) {
@ -60,7 +60,7 @@ void DivPlatformBubSysWSG::acquire(short** buf, size_t len) {
} }
} }
if (++writeOscBuf>=64) writeOscBuf=0; if (++writeOscBuf>=8) writeOscBuf=0;
out<<=6; // scale output to 16 bit out<<=6; // scale output to 16 bit
@ -332,9 +332,9 @@ void DivPlatformBubSysWSG::notifyInsDeletion(void* ins) {
void DivPlatformBubSysWSG::setFlags(const DivConfig& flags) { void DivPlatformBubSysWSG::setFlags(const DivConfig& flags) {
chipClock=COLOR_NTSC; chipClock=COLOR_NTSC;
CHECK_CUSTOM_CLOCK; CHECK_CUSTOM_CLOCK;
rate=chipClock; rate=chipClock/8;
for (int i=0; i<2; i++) { for (int i=0; i<2; i++) {
oscBuf[i]->rate=rate/64; oscBuf[i]->rate=rate/8;
} }
} }

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -131,6 +131,10 @@ int DivPlatformDummy::dispatch(DivCommand c) {
return 1; return 1;
} }
void DivPlatformDummy::notifyInsDeletion(void* ins) {
// nothing
}
void DivPlatformDummy::reset() { void DivPlatformDummy::reset() {
for (int i=0; i<chans; i++) { for (int i=0; i<chans; i++) {
chan[i]=DivPlatformDummy::Channel(); chan[i]=DivPlatformDummy::Channel();

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -40,6 +40,7 @@ class DivPlatformDummy: public DivDispatch {
void acquire(short** buf, size_t len); void acquire(short** buf, size_t len);
void muteChannel(int ch, bool mute); void muteChannel(int ch, bool mute);
int dispatch(DivCommand c); int dispatch(DivCommand c);
void notifyInsDeletion(void* ins);
void* getChanState(int chan); void* getChanState(int chan);
DivDispatchOscBuffer* getOscBuffer(int chan); DivDispatchOscBuffer* getOscBuffer(int chan);
void reset(); void reset();

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -41,8 +41,14 @@ class DivPlatformOPM: public DivPlatformFMBase {
0x00, 0x08, 0x10, 0x18 0x00, 0x08, 0x10, 0x18
}; };
unsigned char lfoValue, lfoValue2, lfoShape, lfoShape2;
DivPlatformOPM(): DivPlatformOPM():
DivPlatformFMBase() {} DivPlatformFMBase(),
lfoValue(0),
lfoValue2(0),
lfoShape(0),
lfoShape2(0) {}
}; };
#endif #endif

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -47,6 +47,8 @@ class DivPlatformFMBase: public DivDispatch {
0,2,1,3 0,2,1,3
}; };
const unsigned int hardResetCycles=127;
struct FMChannel: public SharedChannel<int> { struct FMChannel: public SharedChannel<int> {
DivInstrumentFM state; DivInstrumentFM state;
unsigned char freqH, freqL; unsigned char freqH, freqL;
@ -83,6 +85,7 @@ class DivPlatformFMBase: public DivDispatch {
unsigned char lastBusy; unsigned char lastBusy;
int delay; int delay;
bool flushFirst;
unsigned char regPool[512]; unsigned char regPool[512];
short oldWrites[512]; short oldWrites[512];
@ -102,7 +105,7 @@ class DivPlatformFMBase: public DivDispatch {
} }
} }
inline void urgentWrite(unsigned short a, unsigned char v) { inline void urgentWrite(unsigned short a, unsigned char v) {
if (!skipRegisterWrites) { if (!skipRegisterWrites && !flushFirst) {
if (writes.empty()) { if (writes.empty()) {
writes.push_back(QueuedWrite(a,v)); writes.push_back(QueuedWrite(a,v));
} else if (writes.size()>16 || writes.front().addrOrVal) { } else if (writes.size()>16 || writes.front().addrOrVal) {
@ -118,9 +121,11 @@ class DivPlatformFMBase: public DivDispatch {
friend void putDispatchChan(void*,int,int); friend void putDispatchChan(void*,int,int);
DivPlatformFMBase():DivDispatch(), DivPlatformFMBase():
DivDispatch(),
lastBusy(0), lastBusy(0),
delay(0) {} delay(0),
flushFirst(false) {}
}; };
#endif #endif

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -34,7 +34,7 @@ void DivYM2612Interface::ymfm_set_timer(uint32_t tnum, int32_t duration_in_clock
} else if (tnum==0) { } else if (tnum==0) {
countA=duration_in_clocks; countA=duration_in_clocks;
} }
logV("ymfm_set_timer(%d,%d)",tnum,duration_in_clocks); //logV("ymfm_set_timer(%d,%d)",tnum,duration_in_clocks);
} }
void DivYM2612Interface::clock() { void DivYM2612Interface::clock() {
@ -141,24 +141,27 @@ void DivPlatformGenesis::acquire_nuked(short** buf, size_t len) {
os[0]=0; os[1]=0; os[0]=0; os[1]=0;
for (int i=0; i<6; i++) { for (int i=0; i<6; i++) {
if (!writes.empty() && --delay<0) { if (!writes.empty()) {
if (--delay<0) {
delay=0; delay=0;
QueuedWrite& w=writes.front(); QueuedWrite& w=writes.front();
if (w.addrOrVal) { if (w.addrOrVal) {
//logV("%.3x = %.2x",w.addr,w.val);
OPN2_Write(&fm,0x1+((w.addr>>8)<<1),w.val); OPN2_Write(&fm,0x1+((w.addr>>8)<<1),w.val);
//printf("write: %x = %.2x\n",w.addr,w.val);
lastBusy=0; lastBusy=0;
regPool[w.addr&0x1ff]=w.val; regPool[w.addr&0x1ff]=w.val;
writes.pop_front(); writes.pop_front();
} else { } else {
lastBusy++; lastBusy++;
if (fm.write_busy==0) { if (fm.write_busy==0) {
//printf("busycounter: %d\n",lastBusy);
OPN2_Write(&fm,0x0+((w.addr>>8)<<1),w.addr); OPN2_Write(&fm,0x0+((w.addr>>8)<<1),w.addr);
w.addrOrVal=true; w.addrOrVal=true;
} }
} }
} }
} else {
flushFirst=false;
}
OPN2_Clock(&fm,o); os[0]+=o[0]; os[1]+=o[1]; OPN2_Clock(&fm,o); os[0]+=o[0]; os[1]+=o[1];
//OPN2_Write(&fm,0,0); //OPN2_Write(&fm,0,0);
@ -207,6 +210,8 @@ void DivPlatformGenesis::acquire_ymfm(short** buf, size_t len) {
regPool[w.addr&0x1ff]=w.val; regPool[w.addr&0x1ff]=w.val;
writes.pop_front(); writes.pop_front();
lastBusy=1; lastBusy=1;
} else {
flushFirst=false;
} }
if (ladder) { if (ladder) {
@ -220,6 +225,9 @@ void DivPlatformGenesis::acquire_ymfm(short** buf, size_t len) {
//OPN2_Write(&fm,0,0); //OPN2_Write(&fm,0,0);
for (int i=0; i<6; i++) { for (int i=0; i<6; i++) {
int chOut=(fme->debug_channel(i)->debug_output(0)+fme->debug_channel(i)->debug_output(1))<<6;
if (chOut<-32768) chOut=-32768;
if (chOut>32767) chOut=32767;
if (i==5) { if (i==5) {
if (fm_ymfm->debug_dac_enable()) { if (fm_ymfm->debug_dac_enable()) {
if (softPCM) { if (softPCM) {
@ -229,10 +237,10 @@ void DivPlatformGenesis::acquire_ymfm(short** buf, size_t len) {
oscBuf[i]->data[oscBuf[i]->needle++]=fm_ymfm->debug_dac_data()<<7; oscBuf[i]->data[oscBuf[i]->needle++]=fm_ymfm->debug_dac_data()<<7;
} }
} else { } else {
oscBuf[i]->data[oscBuf[i]->needle++]=(fme->debug_channel(i)->debug_output(0)+fme->debug_channel(i)->debug_output(1))<<6; oscBuf[i]->data[oscBuf[i]->needle++]=chOut;
} }
} else { } else {
oscBuf[i]->data[oscBuf[i]->needle++]=(fme->debug_channel(i)->debug_output(0)+fme->debug_channel(i)->debug_output(1))<<6; oscBuf[i]->data[oscBuf[i]->needle++]=chOut;
} }
} }
@ -389,6 +397,10 @@ void DivPlatformGenesis::tick(bool sysTick) {
chan[i].state.ams=chan[i].std.ams.val; chan[i].state.ams=chan[i].std.ams.val;
rWrite(chanOffs[i]+ADDR_LRAF,(IS_REALLY_MUTED(i)?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4)); rWrite(chanOffs[i]+ADDR_LRAF,(IS_REALLY_MUTED(i)?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4));
} }
if (chan[i].std.ex3.had) {
lfoValue=(chan[i].std.ex3.val>7)?0:(8|(chan[i].std.ex3.val&7));
rWrite(0x22,lfoValue);
}
if (chan[i].std.ex4.had && chan[i].active) { if (chan[i].std.ex4.had && chan[i].active) {
chan[i].opMask=chan[i].std.ex4.val&15; chan[i].opMask=chan[i].std.ex4.val&15;
chan[i].opMaskChanged=true; chan[i].opMaskChanged=true;
@ -454,31 +466,28 @@ void DivPlatformGenesis::tick(bool sysTick) {
for (int i=0; i<512; i++) { for (int i=0; i<512; i++) {
if (pendingWrites[i]!=oldWrites[i]) { if (pendingWrites[i]!=oldWrites[i]) {
if (i==0x2b && pendingWrites[i]!=0 && !parent->song.brokenDACMode) {
if (chan[5].keyOn) chan[5].keyOn=false;
chan[5].keyOff=true;
}
immWrite(i,pendingWrites[i]&0xff); immWrite(i,pendingWrites[i]&0xff);
oldWrites[i]=pendingWrites[i]; oldWrites[i]=pendingWrites[i];
} }
} }
int hardResetElapsed=0;
bool mustHardReset=false;
for (int i=0; i<6; i++) { for (int i=0; i<6; i++) {
if (i==2 && extMode) continue; if (i==2 && extMode) continue;
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) { if (chan[i].hardReset && chan[i].keyOn) {
mustHardReset=true;
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];
for (int k=0; k<5; k++) {
immWrite(baseAddr+ADDR_SL_RR,0x0f); immWrite(baseAddr+ADDR_SL_RR,0x0f);
} hardResetElapsed++;
} }
} }
chan[i].keyOff=false; chan[i].keyOff=false;
@ -507,6 +516,7 @@ void DivPlatformGenesis::tick(bool sysTick) {
if (i<6) { if (i<6) {
immWrite(chanOffs[i]+ADDR_FREQH,chan[i].freq>>8); immWrite(chanOffs[i]+ADDR_FREQH,chan[i].freq>>8);
immWrite(chanOffs[i]+ADDR_FREQ,chan[i].freq&0xff); immWrite(chanOffs[i]+ADDR_FREQ,chan[i].freq&0xff);
hardResetElapsed+=2;
} }
if (chan[i].furnaceDac && chan[i].dacMode) { if (chan[i].furnaceDac && chan[i].dacMode) {
double off=1.0; double off=1.0;
@ -525,12 +535,38 @@ void DivPlatformGenesis::tick(bool sysTick) {
} }
chan[i].freqChanged=false; chan[i].freqChanged=false;
} }
if (chan[i].keyOn || chan[i].opMaskChanged) { if ((chan[i].keyOn || chan[i].opMaskChanged) && !chan[i].hardReset) {
if (i<6) immWrite(0x28,(chan[i].opMask<<4)|konOffs[i]); if (i<6) {
immWrite(0x28,(chan[i].opMask<<4)|konOffs[i]);
hardResetElapsed++;
}
chan[i].opMaskChanged=false; chan[i].opMaskChanged=false;
chan[i].keyOn=false; chan[i].keyOn=false;
} }
} }
// hard reset handling
if (mustHardReset) {
for (unsigned int i=hardResetElapsed; i<hardResetCycles; i++) {
immWrite(0xf0,i&0xff);
}
for (int i=0; i<csmChan; i++) {
if (i==2 && extMode) continue;
if ((chan[i].keyOn || chan[i].opMaskChanged) && chan[i].hardReset) {
if (i<6) {
// restore SL/RR
for (int j=0; j<4; j++) {
unsigned short baseAddr=chanOffs[i]|opOffs[j];
DivInstrumentFM::Operator& op=chan[i].state.op[j];
immWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
}
immWrite(0x28,(chan[i].opMask<<4)|konOffs[i]);
}
chan[i].opMaskChanged=false;
chan[i].keyOn=false;
}
}
}
} }
void DivPlatformGenesis::muteChannel(int ch, bool mute) { void DivPlatformGenesis::muteChannel(int ch, bool mute) {
@ -556,6 +592,47 @@ void DivPlatformGenesis::muteChannel(int ch, bool mute) {
rWrite(chanOffs[ch]+ADDR_LRAF,(IS_REALLY_MUTED(ch)?0:(chan[ch].pan<<6))|(chan[ch].state.fms&7)|((chan[ch].state.ams&3)<<4)); rWrite(chanOffs[ch]+ADDR_LRAF,(IS_REALLY_MUTED(ch)?0:(chan[ch].pan<<6))|(chan[ch].state.fms&7)|((chan[ch].state.ams&3)<<4));
} }
void DivPlatformGenesis::commitState(int ch, DivInstrument* ins) {
if (chan[ch].insChanged) {
chan[ch].state=ins->fm;
chan[ch].opMask=
(chan[ch].state.op[0].enable?1:0)|
(chan[ch].state.op[2].enable?2:0)|
(chan[ch].state.op[1].enable?4:0)|
(chan[ch].state.op[3].enable?8:0);
}
for (int i=0; i<4; i++) {
unsigned short baseAddr=chanOffs[ch]|opOffs[i];
DivInstrumentFM::Operator& op=chan[ch].state.op[i];
if (isMuted[ch]) {
rWrite(baseAddr+ADDR_TL,127);
} else {
if (KVS(ch,i)) {
if (!chan[ch].active || chan[ch].insChanged) {
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG_BROKEN(127-op.tl,chan[ch].outVol&0x7f,127));
}
} else {
if (chan[ch].insChanged) {
rWrite(baseAddr+ADDR_TL,op.tl);
}
}
}
if (chan[ch].insChanged) {
rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4));
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6));
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
rWrite(baseAddr+ADDR_DT2_D2R,op.d2r&31);
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
rWrite(baseAddr+ADDR_SSG,op.ssgEnv&15);
}
}
if (chan[ch].insChanged) {
rWrite(chanOffs[ch]+ADDR_FB_ALG,(chan[ch].state.alg&7)|(chan[ch].state.fb<<3));
rWrite(chanOffs[ch]+ADDR_LRAF,(IS_REALLY_MUTED(ch)?0:(chan[ch].pan<<6))|(chan[ch].state.fms&7)|((chan[ch].state.ams&3)<<4));
}
}
int DivPlatformGenesis::dispatch(DivCommand c) { int DivPlatformGenesis::dispatch(DivCommand c) {
switch (c.cmd) { switch (c.cmd) {
case DIV_CMD_NOTE_ON: { case DIV_CMD_NOTE_ON: {
@ -586,7 +663,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
} }
} }
if (c.chan>=5 && chan[c.chan].dacMode) { if (c.chan>=5 && chan[c.chan].dacMode) {
if (skipRegisterWrites) break; //if (skipRegisterWrites) break;
if (ins->type==DIV_INS_AMIGA) { // Furnace mode if (ins->type==DIV_INS_AMIGA) { // Furnace mode
if (c.value!=DIV_NOTE_NULL) chan[c.chan].dacSample=ins->amiga.getSample(c.value); if (c.value!=DIV_NOTE_NULL) chan[c.chan].dacSample=ins->amiga.getSample(c.value);
if (chan[c.chan].dacSample<0 || chan[c.chan].dacSample>=parent->song.sampleLen) { if (chan[c.chan].dacSample<0 || chan[c.chan].dacSample>=parent->song.sampleLen) {
@ -638,49 +715,12 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
} }
if (c.chan>=6) break; if (c.chan>=6) break;
if (chan[c.chan].insChanged) {
chan[c.chan].state=ins->fm;
chan[c.chan].opMask=
(chan[c.chan].state.op[0].enable?1:0)|
(chan[c.chan].state.op[2].enable?2:0)|
(chan[c.chan].state.op[1].enable?4:0)|
(chan[c.chan].state.op[3].enable?8:0);
}
chan[c.chan].macroInit(ins); chan[c.chan].macroInit(ins);
if (!chan[c.chan].std.vol.will) { if (!chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol; chan[c.chan].outVol=chan[c.chan].vol;
} }
for (int i=0; i<4; i++) { commitState(c.chan,ins);
unsigned short baseAddr=chanOffs[c.chan]|opOffs[i];
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
if (isMuted[c.chan]) {
rWrite(baseAddr+ADDR_TL,127);
} else {
if (KVS(c.chan,i)) {
if (!chan[c.chan].active || chan[c.chan].insChanged) {
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG_BROKEN(127-op.tl,chan[c.chan].outVol&0x7f,127));
}
} else {
if (chan[c.chan].insChanged) {
rWrite(baseAddr+ADDR_TL,op.tl);
}
}
}
if (chan[c.chan].insChanged) {
rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4));
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6));
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
rWrite(baseAddr+ADDR_DT2_D2R,op.d2r&31);
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
rWrite(baseAddr+ADDR_SSG,op.ssgEnv&15);
}
}
if (chan[c.chan].insChanged) {
rWrite(chanOffs[c.chan]+ADDR_FB_ALG,(chan[c.chan].state.alg&7)|(chan[c.chan].state.fb<<3));
rWrite(chanOffs[c.chan]+ADDR_LRAF,(IS_REALLY_MUTED(c.chan)?0:(chan[c.chan].pan<<6))|(chan[c.chan].state.fms&7)|((chan[c.chan].state.ams&3)<<4));
}
chan[c.chan].insChanged=false; chan[c.chan].insChanged=false;
if (c.value!=DIV_NOTE_NULL) { if (c.value!=DIV_NOTE_NULL) {
@ -863,6 +903,11 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
} else if (c.chan>=5 && chan[c.chan].furnaceDac && chan[c.chan].dacMode) { } else if (c.chan>=5 && chan[c.chan].furnaceDac && chan[c.chan].dacMode) {
chan[c.chan].baseFreq=parent->calcBaseFreq(1,1,c.value,false); chan[c.chan].baseFreq=parent->calcBaseFreq(1,1,c.value,false);
} else { } else {
if (chan[c.chan].insChanged) {
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM);
commitState(c.chan,ins);
chan[c.chan].insChanged=false;
}
chan[c.chan].baseFreq=NOTE_FNUM_BLOCK(c.value,11); chan[c.chan].baseFreq=NOTE_FNUM_BLOCK(c.value,11);
} }
chan[c.chan].note=c.value; chan[c.chan].note=c.value;
@ -1117,14 +1162,20 @@ void DivPlatformGenesis::forceIns() {
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));
rWrite(chanOffs[i]+ADDR_LRAF,(IS_REALLY_MUTED(i)?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4)); rWrite(chanOffs[i]+ADDR_LRAF,(IS_REALLY_MUTED(i)?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4));
if (chan[i].active) { if (chan[i].active) {
if (i<5 || !chan[i].dacMode) {
chan[i].keyOn=true; chan[i].keyOn=true;
chan[i].freqChanged=true; chan[i].freqChanged=true;
} }
} }
}
immWrite(0x2b,0x00);
//rWrite(0x2a,0x00);
if (chan[5].dacMode) { if (chan[5].dacMode) {
rWrite(0x2b,0x80); chan[5].dacSample=-1;
chan[6].dacSample=-1;
} }
immWrite(0x22,lfoValue); immWrite(0x22,lfoValue);
flushFirst=true;
} }
void DivPlatformGenesis::toggleRegisterDump(bool enable) { void DivPlatformGenesis::toggleRegisterDump(bool enable) {
@ -1151,6 +1202,10 @@ int DivPlatformGenesis::getRegisterPoolSize() {
return 512; return 512;
} }
float DivPlatformGenesis::getPostAmp() {
return 2.0f;
}
void DivPlatformGenesis::reset() { void DivPlatformGenesis::reset() {
while (!writes.empty()) writes.pop_front(); while (!writes.empty()) writes.pop_front();
memset(regPool,0,512); memset(regPool,0,512);
@ -1178,6 +1233,7 @@ void DivPlatformGenesis::reset() {
lfoValue=8; lfoValue=8;
softPCMTimer=0; softPCMTimer=0;
extMode=false; extMode=false;
flushFirst=false;
if (softPCM) { if (softPCM) {
chan[5].dacMode=true; chan[5].dacMode=true;
@ -1214,6 +1270,9 @@ void DivPlatformGenesis::notifyInsChange(int ins) {
} }
void DivPlatformGenesis::notifyInsDeletion(void* ins) { void DivPlatformGenesis::notifyInsDeletion(void* ins) {
for (int i=0; i<10; i++) {
chan[i].std.notifyInsDeletion((DivInstrument*)ins);
}
} }
void DivPlatformGenesis::poke(unsigned int addr, unsigned short val) { void DivPlatformGenesis::poke(unsigned int addr, unsigned short val) {
@ -1280,6 +1339,7 @@ int DivPlatformGenesis::init(DivEngine* p, int channels, int sugRate, const DivC
dumpWrites=false; dumpWrites=false;
ladder=false; ladder=false;
skipRegisterWrites=false; skipRegisterWrites=false;
flushFirst=false;
for (int i=0; i<10; i++) { for (int i=0; i<10; i++) {
isMuted[i]=false; isMuted[i]=false;
oscBuf[i]=new DivDispatchOscBuffer; oscBuf[i]=new DivDispatchOscBuffer;

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -92,6 +92,7 @@ class DivPlatformGenesis: public DivPlatformOPN {
friend void putDispatchChan(void*,int,int); friend void putDispatchChan(void*,int,int);
inline void processDAC(int iRate); inline void processDAC(int iRate);
inline void commitState(int ch, DivInstrument* ins);
void acquire_nuked(short** buf, size_t len); void acquire_nuked(short** buf, size_t len);
void acquire_ymfm(short** buf, size_t len); void acquire_ymfm(short** buf, size_t len);
@ -114,10 +115,11 @@ class DivPlatformGenesis: public DivPlatformOPN {
void setYMFM(bool use); void setYMFM(bool use);
bool keyOffAffectsArp(int ch); bool keyOffAffectsArp(int ch);
bool keyOffAffectsPorta(int ch); bool keyOffAffectsPorta(int ch);
float getPostAmp();
void toggleRegisterDump(bool enable); void toggleRegisterDump(bool enable);
void setFlags(const DivConfig& flags); void setFlags(const DivConfig& flags);
void notifyInsChange(int ins); void notifyInsChange(int ins);
void notifyInsDeletion(void* ins); virtual void notifyInsDeletion(void* ins);
void setSoftPCM(bool value); void setSoftPCM(bool value);
int getPortaFloor(int ch); int getPortaFloor(int ch);
void poke(unsigned int addr, unsigned short val); void poke(unsigned int addr, unsigned short val);

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -26,23 +26,8 @@
#define IS_REALLY_MUTED(x) (isMuted[x] && (x<5 || !softPCM || (isMuted[5] && isMuted[6]))) #define IS_REALLY_MUTED(x) (isMuted[x] && (x<5 || !softPCM || (isMuted[5] && isMuted[6])))
int DivPlatformGenesisExt::dispatch(DivCommand c) { void DivPlatformGenesisExt::commitStateExt(int ch, DivInstrument* ins) {
if (c.chan<2) {
return DivPlatformGenesis::dispatch(c);
}
if (c.chan>5) {
c.chan-=3;
return DivPlatformGenesis::dispatch(c);
}
int ch=c.chan-2;
int ordch=orderedOps[ch]; int ordch=orderedOps[ch];
if (!extMode) {
c.chan=2;
return DivPlatformGenesis::dispatch(c);
}
switch (c.cmd) {
case DIV_CMD_NOTE_ON: {
DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM);
if (opChan[ch].insChanged) { if (opChan[ch].insChanged) {
chan[2].state.alg=ins->fm.alg; chan[2].state.alg=ins->fm.alg;
@ -54,15 +39,6 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) {
chan[2].state.op[ordch]=ins->fm.op[ordch]; chan[2].state.op[ordch]=ins->fm.op[ordch];
} }
if (noExtMacros) {
opChan[ch].macroInit(NULL);
} else {
opChan[ch].macroInit(ins);
}
if (!opChan[ch].std.vol.will) {
opChan[ch].outVol=opChan[ch].vol;
}
unsigned short baseAddr=chanOffs[2]|opOffs[ordch]; unsigned short baseAddr=chanOffs[2]|opOffs[ordch];
DivInstrumentFM::Operator& op=chan[2].state.op[ordch]; DivInstrumentFM::Operator& op=chan[2].state.op[ordch];
// TODO: how does this work?! // TODO: how does this work?!
@ -86,6 +62,36 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) {
rWrite(chanOffs[2]+0xb0,(chan[2].state.alg&7)|(chan[2].state.fb<<3)); rWrite(chanOffs[2]+0xb0,(chan[2].state.alg&7)|(chan[2].state.fb<<3));
rWrite(chanOffs[2]+0xb4,(IS_EXTCH_MUTED?0:(opChan[ch].pan<<6))|(chan[2].state.fms&7)|((chan[2].state.ams&3)<<4)); rWrite(chanOffs[2]+0xb4,(IS_EXTCH_MUTED?0:(opChan[ch].pan<<6))|(chan[2].state.fms&7)|((chan[2].state.ams&3)<<4));
} }
}
int DivPlatformGenesisExt::dispatch(DivCommand c) {
if (c.chan<2) {
return DivPlatformGenesis::dispatch(c);
}
if (c.chan>5) {
c.chan-=3;
return DivPlatformGenesis::dispatch(c);
}
int ch=c.chan-2;
int ordch=orderedOps[ch];
if (!extMode) {
c.chan=2;
return DivPlatformGenesis::dispatch(c);
}
switch (c.cmd) {
case DIV_CMD_NOTE_ON: {
DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM);
if (noExtMacros) {
opChan[ch].macroInit(NULL);
} else {
opChan[ch].macroInit(ins);
}
if (!opChan[ch].std.vol.will) {
opChan[ch].outVol=opChan[ch].vol;
}
commitStateExt(ch,ins);
opChan[ch].insChanged=false; opChan[ch].insChanged=false;
if (c.value!=DIV_NOTE_NULL) { if (c.value!=DIV_NOTE_NULL) {
@ -202,6 +208,11 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) {
} }
break; break;
case DIV_CMD_LEGATO: { case DIV_CMD_LEGATO: {
if (opChan[ch].insChanged) {
DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM);
commitStateExt(ch,ins);
opChan[ch].insChanged=false;
}
opChan[ch].baseFreq=NOTE_FNUM_BLOCK(c.value,11); opChan[ch].baseFreq=NOTE_FNUM_BLOCK(c.value,11);
opChan[ch].freqChanged=true; opChan[ch].freqChanged=true;
break; break;
@ -578,6 +589,7 @@ void DivPlatformGenesisExt::tick(bool sysTick) {
if (opChan[i].freq>0x3fff) opChan[i].freq=0x3fff; if (opChan[i].freq>0x3fff) opChan[i].freq=0x3fff;
immWrite(opChanOffsH[i],opChan[i].freq>>8); immWrite(opChanOffsH[i],opChan[i].freq>>8);
immWrite(opChanOffsL[i],opChan[i].freq&0xff); immWrite(opChanOffsL[i],opChan[i].freq&0xff);
opChan[i].freqChanged=false;
} }
writeMask|=(unsigned char)(opChan[i].mask && opChan[i].active)<<(4+i); writeMask|=(unsigned char)(opChan[i].mask && opChan[i].active)<<(4+i);
if (opChan[i].keyOn) { if (opChan[i].keyOn) {
@ -640,10 +652,10 @@ void DivPlatformGenesisExt::forceIns() {
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];
if (i==2 && extMode) { // extended channel if (i==2 && extMode) { // extended channel
if (isOpMuted[j]) { if (isOpMuted[orderedOps[j]]) {
rWrite(baseAddr+0x40,127); rWrite(baseAddr+0x40,127);
} else if (KVS(i,j)) { } else if (KVS(i,j)) {
rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[j].outVol&0x7f,127)); rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[orderedOps[j]].outVol&0x7f,127));
} else { } else {
rWrite(baseAddr+0x40,op.tl); rWrite(baseAddr+0x40,op.tl);
} }
@ -677,6 +689,8 @@ void DivPlatformGenesisExt::forceIns() {
} }
} }
if (chan[5].dacMode) { if (chan[5].dacMode) {
chan[5].dacSample=-1;
chan[6].dacSample=-1;
rWrite(0x2b,0x80); rWrite(0x2b,0x80);
} }
immWrite(0x22,lfoValue); immWrite(0x22,lfoValue);
@ -744,6 +758,13 @@ void DivPlatformGenesisExt::notifyInsChange(int ins) {
} }
} }
void DivPlatformGenesisExt::notifyInsDeletion(void* ins) {
DivPlatformGenesis::notifyInsDeletion(ins);
for (int i=0; i<4; i++) {
opChan[i].std.notifyInsDeletion((DivInstrument*)ins);
}
}
int DivPlatformGenesisExt::getPortaFloor(int ch) { int DivPlatformGenesisExt::getPortaFloor(int ch) {
return (ch>8)?12:0; return (ch>8)?12:0;
} }

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -29,6 +29,7 @@ class DivPlatformGenesisExt: public DivPlatformGenesis {
bool isOpMuted[4]; bool isOpMuted[4];
friend void putDispatchChip(void*,int); friend void putDispatchChip(void*,int);
friend void putDispatchChan(void*,int,int); friend void putDispatchChan(void*,int,int);
inline void commitStateExt(int ch, DivInstrument* ins);
public: public:
int dispatch(DivCommand c); int dispatch(DivCommand c);
void* getChanState(int chan); void* getChanState(int chan);
@ -41,6 +42,7 @@ class DivPlatformGenesisExt: public DivPlatformGenesis {
bool keyOffAffectsArp(int ch); bool keyOffAffectsArp(int ch);
bool keyOffAffectsPorta(int ch); bool keyOffAffectsPorta(int ch);
void notifyInsChange(int ins); void notifyInsChange(int ins);
void notifyInsDeletion(void* ins);
int getPortaFloor(int ch); int getPortaFloor(int ch);
void setCSMChannel(unsigned char ch); void setCSMChannel(unsigned char ch);
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags); int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -353,6 +353,9 @@ void DivPlatformMSM6258::notifyInsChange(int ins) {
} }
void DivPlatformMSM6258::notifyInsDeletion(void* ins) { void DivPlatformMSM6258::notifyInsDeletion(void* ins) {
for (int i=0; i<1; i++) {
chan[i].std.notifyInsDeletion((DivInstrument*)ins);
}
} }
void DivPlatformMSM6258::setFlags(const DivConfig& flags) { void DivPlatformMSM6258::setFlags(const DivConfig& flags) {

View file

@ -1,6 +1,6 @@
/** /**
* Furnace Tracker - multi-system chiptune tracker * Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 tildearrow and contributors * Copyright (C) 2021-2023 tildearrow and contributors
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

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