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
env:
BUILD_TYPE: Debug
BUILD_TYPE: RelWithDebInfo
jobs:
build:
@ -20,11 +20,11 @@ jobs:
config:
- { name: 'Windows MSVC x86', os: windows-latest, compiler: msvc, arch: x86 }
- { name: 'Windows MSVC x86_64', os: windows-latest, compiler: msvc, arch: x86_64 }
##- { name: 'Windows MinGW x86', os: ubuntu-20.04, compiler: mingw, arch: x86 }
##- { name: 'Windows MinGW x86_64', os: ubuntu-20.04, compiler: mingw, arch: x86_64 }
#- { name: 'Windows MinGW x86', os: ubuntu-20.04, compiler: mingw, arch: x86 }
#- { name: 'Windows MinGW x86_64', os: ubuntu-20.04, compiler: mingw, arch: x86_64 }
- { name: 'macOS x86_64', os: macos-latest, arch: x86_64 }
- { 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 }
fail-fast: false
@ -278,6 +278,9 @@ jobs:
cp -v ../LICENSE LICENSE.txt
cp -v ../README.md README.txt
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
popd

View File

@ -265,6 +265,9 @@ if (USE_SDL2)
if (MSVC)
list(APPEND DEPENDENCIES_COMPILE_OPTIONS "/DHAVE_LIBC")
endif()
if (WIN32)
list(APPEND DEPENDENCIES_LIBRARIES SDL2main)
endif()
message(STATUS "Using vendored SDL2")
endif()
else()
@ -593,6 +596,7 @@ src/gui/editControls.cpp
src/gui/effectList.cpp
src/gui/findReplace.cpp
src/gui/gradient.cpp
src/gui/grooves.cpp
src/gui/insEdit.cpp
src/gui/log.cpp
src/gui/mixer.cpp
@ -610,6 +614,7 @@ src/gui/scaling.cpp
src/gui/settings.cpp
src/gui/songInfo.cpp
src/gui/songNotes.cpp
src/gui/speed.cpp
src/gui/spoiler.cpp
src/gui/stats.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.
- 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.
> my .dmf song sounds correct, but it doesn't in DefleMask
file a bug report **here**. it still is a playback inaccuracy.
Furnace's .dmf compatibility isn't perfect and it's mostly because DefleMask does things different.
> 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?
@ -301,7 +297,7 @@ right click on the channel name.
---
# 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.
@ -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.
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
* modify it under the terms of the GNU General Public License
@ -17,7 +17,7 @@
* siliconpr0n.org(digshadow, John McMaster):
* VRC VII decap and die shot.
*
* version: 1.0.1
* version: 1.0.2
*/
#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 },{ 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, 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 } }
};
@ -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);
if (!ismod1) {

View File

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

View File

@ -8,11 +8,11 @@
#include "k005289.hpp"
void k005289_core::tick()
void k005289_core::tick(const unsigned int cycles)
{
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()
{
if (bitfield(++m_counter, 0, 12) == 0)
void k005289_core::timer_t::tick(const unsigned int cycles) {
m_counter-=cycles;
while (m_counter < 0)
{
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
void reset();
void tick();
void tick(const unsigned int cycles=1);
// accessors
// Replace current frequency to lastest loaded pitch
@ -63,7 +63,7 @@ class k005289_core : public vgsound_emu_core
// internal state
void reset();
void tick();
void tick(const unsigned int cycles);
// accessors
// TG1/2 pin

View File

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

View File

@ -10,17 +10,17 @@
#include "scc.hpp"
// shared SCC features
void scc_core::tick()
void scc_core::tick(const int cycles)
{
m_out = 0;
for (auto &elem : m_voice)
{
elem.tick();
elem.tick(cycles);
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
{
@ -28,23 +28,27 @@ void scc_core::voice_t::tick()
const u16 temp = m_counter;
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 & ~0xf00) | (bitfield(bitfield(m_counter, 8, 4) - 1, 0, 4) << 8);
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) - cycles, 0, 4) << 8);
}
else
{
m_counter = bitfield(m_counter - 1, 0, 12);
m_counter = bitfield(m_counter - cycles, 0, 12);
}
// 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)
: (m_host.m_test.freq_4bit() ? (bitfield(temp, 8, 4) == 0)
: (bitfield(temp, 0, 12) == 0));
: (bitfield(temp, 0, 12) == 0)));
if (carry)
{
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

View File

@ -41,7 +41,7 @@ class scc_core : public vgsound_emu_core
// internal state
void reset();
void tick();
void tick(const int cycles=1);
// accessors
inline void reset_addr() { m_addr = 0; }
@ -151,7 +151,7 @@ class scc_core : public vgsound_emu_core
// internal state
virtual void reset();
void tick();
void tick(const int cycles=1);
// getters
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.
- `EExx`: send external command.
- this effect is currently incomplete.
- `EFxx`: add or subtract global pitch.
- this effect is rather weird. use with caution.
- `80` is center.
- `F0xx`: change song Hz by BPM value.
- `F1xx`: single tick slide up.
- `F2xx`: single tick slide down.
@ -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 | |
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 |
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 | | | | |
B | FB | FB | FB | | | Noise AND | | | | | WaveLoad L | | | | | | | |
C | FMS | FMS | FMS | | | Noise OR | | | | | WaveLoad T | | | | | | | |
@ -144,4 +141,4 @@ ex | FM | OPM | OPZ | OPLL | AY-3-8910 | AY8930 | Lynx
5 | | | AMD2 | | | | | | | | | | | EnvRampR | | | | |
6 | | | PMD2 | | | | | | | | | | | EnvRampK1 | | | | |
7 | | | LFO2Speed | | | | | | | | | | | EnvRampK2 | | | | |
8 | | | LFO2Shape | | | | | | | | | | | Env Mode | | | | |
8 | | | LFO2Shape | | | | | | | | | | | Env Mode | | | | |

View File

@ -45,6 +45,16 @@ no plans have been made for TX81Z MIDI passthrough, because:
- `1Bxx`: set attack of operator 2.
- `1Cxx`: set attack of operator 3.
- `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.
- `x` is the operator (1-4). a value of 0 means "all operators".
- `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:
- 139: Furnace dev139
- 138: Furnace dev138
- 137: Furnace dev137
- 136: Furnace dev136
- 135: Furnace dev135
- 134: Furnace dev134
@ -398,6 +401,17 @@ size | description
4?? | patchbay
| - see next section for more details.
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
@ -467,6 +481,9 @@ size | description
| - a list of channelCount C strings
S?? | channel short names
| - 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

View File

@ -1,6 +1,6 @@
/**
* 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
* 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
* 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

View File

@ -1,6 +1,6 @@
/**
* 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
* 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
* 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

View File

@ -1,6 +1,6 @@
/**
* 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
* 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) {
memcpy(m.data,msg.data()+1,MIN(msg.size()-1,7));
} 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();
logD("got a SysEx of length %ld!",msg.size());
memcpy(m.sysExData.get(),msg.data(),msg.size());

View File

@ -1,6 +1,6 @@
/**
* 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
* 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
* 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

View File

@ -1,6 +1,6 @@
/**
* 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
* 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
* 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

View File

@ -1,6 +1,6 @@
/**
* 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
* 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
* 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

View File

@ -1,6 +1,6 @@
/**
* 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
* 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
* 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

View File

@ -1,6 +1,6 @@
/**
* 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
* 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
* 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

View File

@ -1,6 +1,6 @@
/**
* 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
* 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
* 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

View File

@ -1,6 +1,6 @@
/**
* 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
* 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
* 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
@ -24,6 +24,7 @@
#define DIV_MAX_CHIPS 32
#define DIV_MAX_CHANS 128
#define DIV_MAX_PATTERNS 256
#define DIV_MAX_CHIP_DEFS 256
// in-pattern
#define DIV_MAX_ROWS 256

View File

@ -1,6 +1,6 @@
/**
* 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
* 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_PM_DEPTH, // (depth)
DIV_CMD_GENESIS_LFO, // unused?
DIV_CMD_ARCADE_LFO, // unused?
DIV_CMD_FM_LFO2, // (speed)
DIV_CMD_FM_LFO2_WAVE, // (waveform)
DIV_CMD_STD_NOISE_FREQ, // (freq)
DIV_CMD_STD_NOISE_MODE, // (mode)
@ -215,6 +214,9 @@ enum DivDispatchCmds {
DIV_CMD_SURROUND_PANNING, // (out, val)
DIV_CMD_FM_AM2_DEPTH, // (depth)
DIV_CMD_FM_PM2_DEPTH, // (depth)
DIV_ALWAYS_SET_VOLUME, // () -> alwaysSetVol
DIV_CMD_MAX

View File

@ -1,6 +1,6 @@
/**
* 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
* 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
* 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
@ -60,7 +60,7 @@ const char* DivEngine::getEffectDesc(unsigned char effect, int chan, bool notNul
case 0x08:
return "08xy: Set panning (x: left; y: right)";
case 0x09:
return "09xx: Set speed 1";
return "09xx: Set groove pattern (speed 1 if no grooves exist)";
case 0x0a:
return "0Axy: Volume slide (0y: down; x0: up)";
case 0x0b:
@ -70,7 +70,7 @@ const char* DivEngine::getEffectDesc(unsigned char effect, int chan, bool notNul
case 0x0d:
return "0Dxx: Jump to next pattern";
case 0x0f:
return "0Fxx: Set speed 2";
return "0Fxx: Set speed (speed 2 if no grooves exist)";
case 0x80:
return "80xx: Set panning (00: left; 80: center; FF: right)";
case 0x81:
@ -110,8 +110,6 @@ const char* DivEngine::getEffectDesc(unsigned char effect, int chan, bool notNul
return "EDxx: Note delay";
case 0xee:
return "EExx: Send external command";
case 0xef:
return "EFxx: Set global tuning (quirky!)";
case 0xf0:
return "F0xx: Set tick rate (bpm)";
case 0xf1:
@ -1961,14 +1959,12 @@ String DivEngine::getPlaybackDebugInfo() {
"cmdsPerSecond: %d\n"
"globalPitch: %d\n"
"extValue: %d\n"
"speed1: %d\n"
"speed2: %d\n"
"tempoAccum: %d\n"
"totalProcessed: %d\n"
"bufferPos: %d\n",
curOrder,prevOrder,curRow,prevRow,ticks,subticks,totalLoops,lastLoopPos,nextSpeed,divider,cycles,clockDrift,
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;
}
endOfSong=false;
speedAB=false;
// whaaaaa?
curSpeed=0;
playing=true;
skipping=true;
memset(walked,0,8192);
@ -2441,15 +2438,14 @@ void DivEngine::reset() {
}
extValue=0;
extValuePresent=0;
speed1=curSubSong->speed1;
speed2=curSubSong->speed2;
speeds=curSubSong->speeds;
firstTick=false;
shallStop=false;
shallStopSched=false;
pendingMetroTick=0;
elapsedBars=0;
elapsedBeats=0;
nextSpeed=speed1;
nextSpeed=speeds.val[0];
divider=60;
if (curSubSong->customTempo) {
divider=curSubSong->hz;
@ -2649,12 +2645,8 @@ size_t DivEngine::getCurrentSubSong() {
return curSubSongIndex;
}
unsigned char DivEngine::getSpeed1() {
return speed1;
}
unsigned char DivEngine::getSpeed2() {
return speed2;
const DivGroovePattern& DivEngine::getSpeeds() {
return speeds;
}
float DivEngine::getHz() {
@ -4236,7 +4228,7 @@ void DivEngine::quitDispatch() {
clockDrift=0;
chans=0;
playing=false;
speedAB=false;
curSpeed=0;
endOfSong=false;
ticks=0;
tempoAccum=0;
@ -4472,6 +4464,9 @@ bool DivEngine::init() {
for (int i=0; i<64; i++) {
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++) {
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)));

View File

@ -1,6 +1,6 @@
/**
* 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
* 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_END isBusy.unlock(); softLocked=false;
#define DIV_VERSION "dev136"
#define DIV_ENGINE_VERSION 136
#define DIV_VERSION "dev139"
#define DIV_ENGINE_VERSION 139
// for imports
#define DIV_VERSION_MOD 0xff01
#define DIV_VERSION_FC 0xff02
@ -337,7 +337,6 @@ class DivEngine {
bool playing;
bool freelance;
bool shallStop, shallStopSched;
bool speedAB;
bool endOfSong;
bool consoleMode;
bool extValuePresent;
@ -359,7 +358,7 @@ class DivEngine {
bool midiOutClock;
int midiOutMode;
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 bufferPos;
double divider;
@ -368,7 +367,7 @@ class DivEngine {
int stepPlay;
int changeOrd, changePos, totalSeconds, totalTicks, totalTicksR, totalCmds, lastCmds, cmdsPerSecond, globalPitch;
unsigned char extValue, pendingMetroTick;
unsigned char speed1, speed2;
DivGroovePattern speeds;
short tempoAccum;
DivStatusView view;
DivHaltPositions haltOn;
@ -391,9 +390,9 @@ class DivEngine {
std::vector<String> midiOuts;
std::vector<DivCommand> cmdStream;
std::vector<DivInstrumentType> possibleInsTypes;
static DivSysDef* sysDefs[256];
static DivSystem sysFileMapFur[256];
static DivSystem sysFileMapDMF[256];
static DivSysDef* sysDefs[DIV_MAX_CHIP_DEFS];
static DivSystem sysFileMapFur[DIV_MAX_CHIP_DEFS];
static DivSystem sysFileMapDMF[DIV_MAX_CHIP_DEFS];
struct SamplePreview {
double rate;
@ -413,6 +412,7 @@ class DivEngine {
} sPreview;
short vibTable[64];
short tremTable[128];
int reversePitchTable[4096];
int pitchTable[4096];
char c163NameCS[1024];
@ -442,7 +442,7 @@ class DivEngine {
void processRow(int i, bool afterDelay);
void nextOrder();
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.
bool nextTick(bool noAccum=false, bool inhibitLowLat=false);
bool perSystemEffect(int ch, unsigned char effect, unsigned char effectVal);
@ -729,11 +729,8 @@ class DivEngine {
// get current subsong
size_t getCurrentSubSong();
// get speed 1
unsigned char getSpeed1();
// get speed 2
unsigned char getSpeed2();
// get speeds
const DivGroovePattern& getSpeeds();
// get Hz
float getHz();
@ -1064,7 +1061,6 @@ class DivEngine {
freelance(false),
shallStop(false),
shallStopSched(false),
speedAB(false),
endOfSong(false),
consoleMode(false),
extValuePresent(false),
@ -1098,6 +1094,7 @@ class DivEngine {
nextSpeed(3),
elapsedBars(0),
elapsedBeats(0),
curSpeed(0),
curSubSongIndex(0),
bufferPos(0),
divider(60),
@ -1115,8 +1112,6 @@ class DivEngine {
globalPitch(0),
extValue(0),
pendingMetroTick(0),
speed1(3),
speed2(3),
tempoAccum(0),
view(DIV_STATUS_NOTHING),
haltOn(DIV_HALT_NONE),
@ -1158,13 +1153,14 @@ class DivEngine {
memset(dispatchOfChan,0,DIV_MAX_CHANS*sizeof(int));
memset(sysOfChan,0,DIV_MAX_CHANS*sizeof(int));
memset(vibTable,0,64*sizeof(short));
memset(tremTable,0,128*sizeof(short));
memset(reversePitchTable,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(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;
sysFileMapDMF[i]=DIV_SYSTEM_NULL;
}

View File

@ -1,6 +1,6 @@
/**
* 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
* 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();
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!");
lastError="this version is not supported by Furnace yet";
delete[] file;
@ -219,14 +219,15 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
}
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) {
ds.subsong[0]->speed2=reader.readC();
ds.subsong[0]->speeds.val[1]=reader.readC();
ds.subsong[0]->pal=reader.readC();
ds.subsong[0]->hz=(ds.subsong[0]->pal)?60:50;
ds.subsong[0]->customTempo=reader.readC();
} else {
ds.subsong[0]->speed2=ds.subsong[0]->speed1;
ds.subsong[0]->speeds.len=1;
}
if (ds.version>0x0a) {
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++) {
DivSample* sample=new DivSample;
int length=reader.readI();
int cutStart=0;
int cutEnd=length;
int pitch=5;
int vol=50;
short* data;
@ -866,6 +869,29 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
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 (ds.version>0x08) {
if (ds.version<0x0b) {
@ -876,6 +902,19 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
data=new short[length];
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
// convert to big-endian
@ -1716,6 +1755,9 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
if (ds.version<130) {
ds.oldArpStrategy=true;
}
if (ds.version<138) {
ds.brokenPortaLegato=true;
}
ds.isDMF=false;
reader.readS(); // reserved
@ -1739,8 +1781,9 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
reader.readI();
subSong->timeBase=reader.readC();
subSong->speed1=reader.readC();
subSong->speed2=reader.readC();
subSong->speeds.len=2;
subSong->speeds.val[0]=reader.readC();
subSong->speeds.val[1]=reader.readC();
subSong->arpLen=reader.readC();
subSong->hz=reader.readF();
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>=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
if (ds.version>=119) {
logD("reading chip flags...");
@ -2279,8 +2348,9 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
subSong=ds.subsong[i+1];
subSong->timeBase=reader.readC();
subSong->speed1=reader.readC();
subSong->speed2=reader.readC();
subSong->speeds.len=2;
subSong->speeds.val[0]=reader.readC();
subSong->speeds.val[1]=reader.readC();
subSong->arpLen=reader.readC();
subSong->hz=reader.readF();
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++) {
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();
BUSY_BEGIN_SOFT;
saveLock.lock();
@ -2920,7 +3023,6 @@ bool DivEngine::loadMod(unsigned char* file, size_t len) {
if (fxVal>0x20 && ds.name!="klisje paa klisje") {
writeFxCol(0xf0,fxVal);
} else {
writeFxCol(0x09,fxVal);
writeFxCol(0x0f,fxVal);
}
break;
@ -3399,8 +3501,8 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) {
ds.subsong[0]->pal=true;
ds.subsong[0]->customTempo=true;
ds.subsong[0]->pat[3].effectCols=3;
ds.subsong[0]->speed1=3;
ds.subsong[0]->speed2=3;
ds.subsong[0]->speeds.val[0]=3;
ds.subsong[0]->speeds.len=1;
int lastIns[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;
DivPattern* p=ds.subsong[0]->pat[j].getPattern(i,true);
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][8]=0x0f;
p->data[0][9]=seq[i].speed;
}
bool ignoreNext=false;
@ -4307,8 +4407,9 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) {
w->writeI(0);
w->writeC(subSong->timeBase);
w->writeC(subSong->speed1);
w->writeC(subSong->speed2);
// these are for compatibility
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->writeF(subSong->hz);
w->writeS(subSong->patLen);
@ -4489,6 +4590,27 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) {
}
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();
w->seek(blockStartSeek,SEEK_SET);
w->writeI(blockEndSeek-blockStartSeek-4);
@ -4503,8 +4625,8 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) {
w->writeI(0);
w->writeC(subSong->timeBase);
w->writeC(subSong->speed1);
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->writeF(subSong->hz);
w->writeS(subSong->patLen);
@ -4543,6 +4665,12 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) {
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();
w->seek(blockStartSeek,SEEK_SET);
w->writeI(blockEndSeek-blockStartSeek-4);
@ -4798,8 +4926,8 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) {
w->writeC(curSubSong->hilightB);
w->writeC(curSubSong->timeBase);
w->writeC(curSubSong->speed1);
w->writeC(curSubSong->speed2);
w->writeC(curSubSong->speeds.val[0]);
w->writeC((curSubSong->speeds.len>=2)?curSubSong->speeds.val[1]:curSubSong->speeds.val[0]);
w->writeC(curSubSong->pal);
w->writeC(curSubSong->customTempo);
char customHz[4];
@ -4823,6 +4951,14 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) {
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) {
addWarning(".dmf format does not support virtual tempo");
}

View File

@ -1,6 +1,6 @@
/**
* 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
* 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
* 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

View File

@ -1,6 +1,6 @@
/**
* 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
* 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
* 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

View File

@ -1,6 +1,6 @@
/**
* 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
* 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
* 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
@ -56,7 +56,7 @@ void DivMacroStruct::doMacro(DivInstrumentMacro& source, bool released, bool tic
}
if (delay>0) {
delay--;
had=false;
if (!linger) had=false;
return;
}
if (began && source.delay>0) {
@ -523,4 +523,4 @@ DivMacroStruct* DivMacroInt::structByName(const String& name) {
return NULL;
}
#undef CONSIDER
#undef CONSIDER

View File

@ -1,6 +1,6 @@
/**
* 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
* 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
* 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

View File

@ -1,6 +1,6 @@
/**
* 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
* 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
* 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

View File

@ -1,6 +1,6 @@
/**
* 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
* it under the terms of the GNU General Public License as published by
@ -18,6 +18,7 @@
*/
#include "../dispatch.h"
#include "../../ta-log.h"
void DivDispatch::acquire(short** buf, size_t len) {
}
@ -121,7 +122,8 @@ void DivDispatch::notifyWaveChange(int ins) {
}
void DivDispatch::notifyInsDeletion(void* ins) {
logE("notifyInsDeletion NOT implemented!");
abort();
}
void DivDispatch::notifyPlaybackStop() {

View File

@ -1,6 +1,6 @@
/**
* 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
* 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
* 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

View File

@ -1,6 +1,6 @@
/**
* 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
* 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));
}
}
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++) {
@ -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++) {
if (chan[i].freqChanged) {
chan[i].freq=chan[i].baseFreq+(chan[i].pitch>>1)-64+chan[i].pitch2;
@ -363,14 +360,37 @@ void DivPlatformArcade::tick(bool sysTick) {
if (chan[i].freq>=(95<<6)) chan[i].freq=(95<<6)-1;
immWrite(i+0x28,hScale(chan[i].freq>>6));
immWrite(i+0x30,chan[i].freq<<2);
hardResetElapsed+=2;
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);
chan[i].opMaskChanged=false;
chan[i].keyOn=false;
}
}
}
}
void DivPlatformArcade::muteChannel(int ch, bool mute) {
@ -382,53 +402,57 @@ void DivPlatformArcade::muteChannel(int ch, bool mute) {
}
}
void DivPlatformArcade::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 (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)|(op.dt2<<6));
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
}
}
if (chan[ch].insChanged) {
if (isMuted[ch]) {
rWrite(chanOffs[ch]+ADDR_LR_FB_ALG,(chan[ch].state.alg&7)|(chan[ch].state.fb<<3));
} else {
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[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);
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);
if (!chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
for (int i=0; i<4; i++) {
unsigned short baseAddr=chanOffs[c.chan]|opOffs[i];
DivInstrumentFM::Operator op=chan[c.chan].state.op[i];
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)|(op.dt2<<6));
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
}
}
if (chan[c.chan].insChanged) {
if (isMuted[c.chan]) {
rWrite(chanOffs[c.chan]+ADDR_LR_FB_ALG,(chan[c.chan].state.alg&7)|(chan[c.chan].state.fb<<3));
} 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[c.chan]+ADDR_FMS_AMS,((chan[c.chan].state.fms&7)<<4)|(chan[c.chan].state.ams&3));
}
commitState(c.chan,ins);
chan[c.chan].insChanged=false;
if (c.value!=DIV_NOTE_NULL) {
@ -521,6 +545,11 @@ int DivPlatformArcade::dispatch(DivCommand c) {
break;
}
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].freqChanged=true;
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) {
return &chan[ch];
}

View File

@ -1,6 +1,6 @@
/**
* 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
* 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 toFreq(int freq);
void commitState(int ch, DivInstrument* ins);
void acquire_nuked(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);
DivMacroInt* getChanMacroInt(int ch);
void notifyInsChange(int ins);
void notifyInsDeletion(void* ins);
void setFlags(const DivConfig& flags);
int getOutputCount();
void setYMFM(bool use);

View File

@ -1,6 +1,6 @@
/**
* 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
* 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
* 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

View File

@ -1,6 +1,6 @@
/**
* 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
* 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
* 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

View File

@ -1,6 +1,6 @@
/**
* 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
* 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++) {
signed int out=0;
// K005289 part
k005289.tick();
k005289.tick(8);
// Wavetable part
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
@ -332,9 +332,9 @@ void DivPlatformBubSysWSG::notifyInsDeletion(void* ins) {
void DivPlatformBubSysWSG::setFlags(const DivConfig& flags) {
chipClock=COLOR_NTSC;
CHECK_CUSTOM_CLOCK;
rate=chipClock;
rate=chipClock/8;
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
* 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

View File

@ -1,6 +1,6 @@
/**
* 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
* 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
* 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

View File

@ -1,6 +1,6 @@
/**
* 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
* it under the terms of the GNU General Public License as published by
@ -131,6 +131,10 @@ int DivPlatformDummy::dispatch(DivCommand c) {
return 1;
}
void DivPlatformDummy::notifyInsDeletion(void* ins) {
// nothing
}
void DivPlatformDummy::reset() {
for (int i=0; i<chans; i++) {
chan[i]=DivPlatformDummy::Channel();

View File

@ -1,6 +1,6 @@
/**
* 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
* 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 muteChannel(int ch, bool mute);
int dispatch(DivCommand c);
void notifyInsDeletion(void* ins);
void* getChanState(int chan);
DivDispatchOscBuffer* getOscBuffer(int chan);
void reset();

View File

@ -1,6 +1,6 @@
/**
* 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
* 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
* 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

View File

@ -1,6 +1,6 @@
/**
* 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
* 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
};
unsigned char lfoValue, lfoValue2, lfoShape, lfoShape2;
DivPlatformOPM():
DivPlatformFMBase() {}
DivPlatformFMBase(),
lfoValue(0),
lfoValue2(0),
lfoShape(0),
lfoShape2(0) {}
};
#endif

View File

@ -1,6 +1,6 @@
/**
* 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
* 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
* 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
@ -47,6 +47,8 @@ class DivPlatformFMBase: public DivDispatch {
0,2,1,3
};
const unsigned int hardResetCycles=127;
struct FMChannel: public SharedChannel<int> {
DivInstrumentFM state;
unsigned char freqH, freqL;
@ -83,6 +85,7 @@ class DivPlatformFMBase: public DivDispatch {
unsigned char lastBusy;
int delay;
bool flushFirst;
unsigned char regPool[512];
short oldWrites[512];
@ -102,7 +105,7 @@ class DivPlatformFMBase: public DivDispatch {
}
}
inline void urgentWrite(unsigned short a, unsigned char v) {
if (!skipRegisterWrites) {
if (!skipRegisterWrites && !flushFirst) {
if (writes.empty()) {
writes.push_back(QueuedWrite(a,v));
} else if (writes.size()>16 || writes.front().addrOrVal) {
@ -118,9 +121,11 @@ class DivPlatformFMBase: public DivDispatch {
friend void putDispatchChan(void*,int,int);
DivPlatformFMBase():DivDispatch(),
lastBusy(0),
delay(0) {}
DivPlatformFMBase():
DivDispatch(),
lastBusy(0),
delay(0),
flushFirst(false) {}
};
#endif

View File

@ -1,6 +1,6 @@
/**
* 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
* 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
* 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

View File

@ -1,6 +1,6 @@
/**
* 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
* 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
* 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

View File

@ -1,6 +1,6 @@
/**
* 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
* 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) {
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() {
@ -141,23 +141,26 @@ void DivPlatformGenesis::acquire_nuked(short** buf, size_t len) {
os[0]=0; os[1]=0;
for (int i=0; i<6; i++) {
if (!writes.empty() && --delay<0) {
delay=0;
QueuedWrite& w=writes.front();
if (w.addrOrVal) {
OPN2_Write(&fm,0x1+((w.addr>>8)<<1),w.val);
//printf("write: %x = %.2x\n",w.addr,w.val);
lastBusy=0;
regPool[w.addr&0x1ff]=w.val;
writes.pop_front();
} else {
lastBusy++;
if (fm.write_busy==0) {
//printf("busycounter: %d\n",lastBusy);
OPN2_Write(&fm,0x0+((w.addr>>8)<<1),w.addr);
w.addrOrVal=true;
if (!writes.empty()) {
if (--delay<0) {
delay=0;
QueuedWrite& w=writes.front();
if (w.addrOrVal) {
//logV("%.3x = %.2x",w.addr,w.val);
OPN2_Write(&fm,0x1+((w.addr>>8)<<1),w.val);
lastBusy=0;
regPool[w.addr&0x1ff]=w.val;
writes.pop_front();
} else {
lastBusy++;
if (fm.write_busy==0) {
OPN2_Write(&fm,0x0+((w.addr>>8)<<1),w.addr);
w.addrOrVal=true;
}
}
}
} else {
flushFirst=false;
}
OPN2_Clock(&fm,o); os[0]+=o[0]; os[1]+=o[1];
@ -207,6 +210,8 @@ void DivPlatformGenesis::acquire_ymfm(short** buf, size_t len) {
regPool[w.addr&0x1ff]=w.val;
writes.pop_front();
lastBusy=1;
} else {
flushFirst=false;
}
if (ladder) {
@ -220,6 +225,9 @@ void DivPlatformGenesis::acquire_ymfm(short** buf, size_t len) {
//OPN2_Write(&fm,0,0);
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 (fm_ymfm->debug_dac_enable()) {
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;
}
} 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 {
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;
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) {
chan[i].opMask=chan[i].std.ex4.val&15;
chan[i].opMaskChanged=true;
@ -454,31 +466,28 @@ void DivPlatformGenesis::tick(bool sysTick) {
for (int i=0; i<512; 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);
oldWrites[i]=pendingWrites[i];
}
}
int hardResetElapsed=0;
bool mustHardReset=false;
for (int i=0; i<6; i++) {
if (i==2 && extMode) continue;
if (chan[i].keyOn || chan[i].keyOff) {
immWrite(0x28,0x00|konOffs[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);
immWrite(baseAddr+ADDR_TL,0x7f);
oldWrites[baseAddr+ADDR_SL_RR]=-1;
oldWrites[baseAddr+ADDR_TL]=-1;
//rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
}
}
immWrite(0x28,0x00|konOffs[i]);
if (chan[i].hardReset && chan[i].keyOn) {
for (int j=0; j<4; j++) {
unsigned short baseAddr=chanOffs[i]|opOffs[j];
for (int k=0; k<5; k++) {
immWrite(baseAddr+ADDR_SL_RR,0x0f);
}
hardResetElapsed++;
}
}
chan[i].keyOff=false;
@ -507,6 +516,7 @@ void DivPlatformGenesis::tick(bool sysTick) {
if (i<6) {
immWrite(chanOffs[i]+ADDR_FREQH,chan[i].freq>>8);
immWrite(chanOffs[i]+ADDR_FREQ,chan[i].freq&0xff);
hardResetElapsed+=2;
}
if (chan[i].furnaceDac && chan[i].dacMode) {
double off=1.0;
@ -525,12 +535,38 @@ void DivPlatformGenesis::tick(bool sysTick) {
}
chan[i].freqChanged=false;
}
if (chan[i].keyOn || chan[i].opMaskChanged) {
if (i<6) immWrite(0x28,(chan[i].opMask<<4)|konOffs[i]);
if ((chan[i].keyOn || chan[i].opMaskChanged) && !chan[i].hardReset) {
if (i<6) {
immWrite(0x28,(chan[i].opMask<<4)|konOffs[i]);
hardResetElapsed++;
}
chan[i].opMaskChanged=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) {
@ -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));
}
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) {
switch (c.cmd) {
case DIV_CMD_NOTE_ON: {
@ -586,7 +663,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
}
}
if (c.chan>=5 && chan[c.chan].dacMode) {
if (skipRegisterWrites) break;
//if (skipRegisterWrites) break;
if (ins->type==DIV_INS_AMIGA) { // Furnace mode
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) {
@ -638,49 +715,12 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
}
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);
if (!chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
for (int i=0; i<4; i++) {
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));
}
commitState(c.chan,ins);
chan[c.chan].insChanged=false;
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) {
chan[c.chan].baseFreq=parent->calcBaseFreq(1,1,c.value,false);
} 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].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_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) {
chan[i].keyOn=true;
chan[i].freqChanged=true;
if (i<5 || !chan[i].dacMode) {
chan[i].keyOn=true;
chan[i].freqChanged=true;
}
}
}
immWrite(0x2b,0x00);
//rWrite(0x2a,0x00);
if (chan[5].dacMode) {
rWrite(0x2b,0x80);
chan[5].dacSample=-1;
chan[6].dacSample=-1;
}
immWrite(0x22,lfoValue);
flushFirst=true;
}
void DivPlatformGenesis::toggleRegisterDump(bool enable) {
@ -1151,6 +1202,10 @@ int DivPlatformGenesis::getRegisterPoolSize() {
return 512;
}
float DivPlatformGenesis::getPostAmp() {
return 2.0f;
}
void DivPlatformGenesis::reset() {
while (!writes.empty()) writes.pop_front();
memset(regPool,0,512);
@ -1178,6 +1233,7 @@ void DivPlatformGenesis::reset() {
lfoValue=8;
softPCMTimer=0;
extMode=false;
flushFirst=false;
if (softPCM) {
chan[5].dacMode=true;
@ -1214,6 +1270,9 @@ void DivPlatformGenesis::notifyInsChange(int 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) {
@ -1280,6 +1339,7 @@ int DivPlatformGenesis::init(DivEngine* p, int channels, int sugRate, const DivC
dumpWrites=false;
ladder=false;
skipRegisterWrites=false;
flushFirst=false;
for (int i=0; i<10; i++) {
isMuted[i]=false;
oscBuf[i]=new DivDispatchOscBuffer;

View File

@ -1,6 +1,6 @@
/**
* 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
* 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);
inline void processDAC(int iRate);
inline void commitState(int ch, DivInstrument* ins);
void acquire_nuked(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);
bool keyOffAffectsArp(int ch);
bool keyOffAffectsPorta(int ch);
float getPostAmp();
void toggleRegisterDump(bool enable);
void setFlags(const DivConfig& flags);
void notifyInsChange(int ins);
void notifyInsDeletion(void* ins);
virtual void notifyInsDeletion(void* ins);
void setSoftPCM(bool value);
int getPortaFloor(int ch);
void poke(unsigned int addr, unsigned short val);

View File

@ -1,6 +1,6 @@
/**
* 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
* it under the terms of the GNU General Public License as published by
@ -26,6 +26,44 @@
#define IS_REALLY_MUTED(x) (isMuted[x] && (x<5 || !softPCM || (isMuted[5] && isMuted[6])))
void DivPlatformGenesisExt::commitStateExt(int ch, DivInstrument* ins) {
int ordch=orderedOps[ch];
if (opChan[ch].insChanged) {
chan[2].state.alg=ins->fm.alg;
if (ch==0 || fbAllOps) {
chan[2].state.fb=ins->fm.fb;
}
chan[2].state.fms=ins->fm.fms;
chan[2].state.ams=ins->fm.ams;
chan[2].state.op[ordch]=ins->fm.op[ordch];
}
unsigned short baseAddr=chanOffs[2]|opOffs[ordch];
DivInstrumentFM::Operator& op=chan[2].state.op[ordch];
// TODO: how does this work?!
if (isOpMuted[ch]) {
rWrite(baseAddr+0x40,127);
} else {
if (opChan[ch].insChanged) {
rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[ch].outVol&0x7f,127));
}
}
if (opChan[ch].insChanged) {
rWrite(baseAddr+0x30,(op.mult&15)|(dtTable[op.dt&7]<<4));
rWrite(baseAddr+0x50,(op.ar&31)|(op.rs<<6));
rWrite(baseAddr+0x60,(op.dr&31)|(op.am<<7));
rWrite(baseAddr+0x70,op.d2r&31);
rWrite(baseAddr+0x80,(op.rr&15)|(op.sl<<4));
rWrite(baseAddr+0x90,op.ssgEnv&15);
opChan[ch].mask=op.enable;
}
if (opChan[ch].insChanged) { // TODO how does this work?
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));
}
}
int DivPlatformGenesisExt::dispatch(DivCommand c) {
if (c.chan<2) {
return DivPlatformGenesis::dispatch(c);
@ -44,16 +82,6 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) {
case DIV_CMD_NOTE_ON: {
DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM);
if (opChan[ch].insChanged) {
chan[2].state.alg=ins->fm.alg;
if (ch==0 || fbAllOps) {
chan[2].state.fb=ins->fm.fb;
}
chan[2].state.fms=ins->fm.fms;
chan[2].state.ams=ins->fm.ams;
chan[2].state.op[ordch]=ins->fm.op[ordch];
}
if (noExtMacros) {
opChan[ch].macroInit(NULL);
} else {
@ -62,30 +90,8 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) {
if (!opChan[ch].std.vol.will) {
opChan[ch].outVol=opChan[ch].vol;
}
unsigned short baseAddr=chanOffs[2]|opOffs[ordch];
DivInstrumentFM::Operator& op=chan[2].state.op[ordch];
// TODO: how does this work?!
if (isOpMuted[ch]) {
rWrite(baseAddr+0x40,127);
} else {
if (opChan[ch].insChanged) {
rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[ch].outVol&0x7f,127));
}
}
if (opChan[ch].insChanged) {
rWrite(baseAddr+0x30,(op.mult&15)|(dtTable[op.dt&7]<<4));
rWrite(baseAddr+0x50,(op.ar&31)|(op.rs<<6));
rWrite(baseAddr+0x60,(op.dr&31)|(op.am<<7));
rWrite(baseAddr+0x70,op.d2r&31);
rWrite(baseAddr+0x80,(op.rr&15)|(op.sl<<4));
rWrite(baseAddr+0x90,op.ssgEnv&15);
opChan[ch].mask=op.enable;
}
if (opChan[ch].insChanged) { // TODO how does this work?
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));
}
commitStateExt(ch,ins);
opChan[ch].insChanged=false;
if (c.value!=DIV_NOTE_NULL) {
@ -202,6 +208,11 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) {
}
break;
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].freqChanged=true;
break;
@ -578,6 +589,7 @@ void DivPlatformGenesisExt::tick(bool sysTick) {
if (opChan[i].freq>0x3fff) opChan[i].freq=0x3fff;
immWrite(opChanOffsH[i],opChan[i].freq>>8);
immWrite(opChanOffsL[i],opChan[i].freq&0xff);
opChan[i].freqChanged=false;
}
writeMask|=(unsigned char)(opChan[i].mask && opChan[i].active)<<(4+i);
if (opChan[i].keyOn) {
@ -640,10 +652,10 @@ void DivPlatformGenesisExt::forceIns() {
unsigned short baseAddr=chanOffs[i]|opOffs[j];
DivInstrumentFM::Operator& op=chan[i].state.op[j];
if (i==2 && extMode) { // extended channel
if (isOpMuted[j]) {
if (isOpMuted[orderedOps[j]]) {
rWrite(baseAddr+0x40,127);
} 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 {
rWrite(baseAddr+0x40,op.tl);
}
@ -677,6 +689,8 @@ void DivPlatformGenesisExt::forceIns() {
}
}
if (chan[5].dacMode) {
chan[5].dacSample=-1;
chan[6].dacSample=-1;
rWrite(0x2b,0x80);
}
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) {
return (ch>8)?12:0;
}

View File

@ -1,6 +1,6 @@
/**
* 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
* it under the terms of the GNU General Public License as published by
@ -29,6 +29,7 @@ class DivPlatformGenesisExt: public DivPlatformGenesis {
bool isOpMuted[4];
friend void putDispatchChip(void*,int);
friend void putDispatchChan(void*,int,int);
inline void commitStateExt(int ch, DivInstrument* ins);
public:
int dispatch(DivCommand c);
void* getChanState(int chan);
@ -41,6 +42,7 @@ class DivPlatformGenesisExt: public DivPlatformGenesis {
bool keyOffAffectsArp(int ch);
bool keyOffAffectsPorta(int ch);
void notifyInsChange(int ins);
void notifyInsDeletion(void* ins);
int getPortaFloor(int ch);
void setCSMChannel(unsigned char ch);
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);

View File

@ -1,6 +1,6 @@
/**
* 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
* 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
* 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

View File

@ -1,6 +1,6 @@
/**
* 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
* 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
* 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

View File

@ -1,6 +1,6 @@
/**
* 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
* 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
* 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

View File

@ -1,6 +1,6 @@
/**
* 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
* 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
* 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

View File

@ -1,6 +1,6 @@
/**
* 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
* 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) {
for (int i=0; i<1; i++) {
chan[i].std.notifyInsDeletion((DivInstrument*)ins);
}
}
void DivPlatformMSM6258::setFlags(const DivConfig& flags) {

View File

@ -1,6 +1,6 @@
/**
* 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
* 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